Преглед изворни кода

Merge branch 'thirdparty_dev' into dev

# Conflicts:
#	source/putty/ssh.c

Source commit: f82ff49bdcacb90af417d21c8adbac0683ce5788
Martin Prikryl пре 6 година
родитељ
комит
2cb8f90e4b

+ 2 - 2
source/putty/agentf.c

@@ -12,7 +12,7 @@
 #include "sshchan.h"
 
 typedef struct agentf {
-    struct ssh_channel *c;
+    SshChannel *c;
     bufchain inbuffer;
     agent_pending_query *pending;
     int input_wanted;
@@ -158,7 +158,7 @@ static const struct ChannelVtable agentf_channelvt = {
     chan_no_eager_close,
 };
 
-Channel *agentf_new(struct ssh_channel *c)
+Channel *agentf_new(SshChannel *c)
 {
     agentf *af = snew(agentf);
     af->c = c;

+ 9 - 0
source/putty/defs.h

@@ -54,13 +54,22 @@ typedef struct Frontend Frontend;
 typedef struct ssh_tag *Ssh;
 
 typedef struct Channel Channel;
+typedef struct SshChannel SshChannel;
 
 typedef struct ssh_sharing_state ssh_sharing_state;
 typedef struct ssh_sharing_connstate ssh_sharing_connstate;
 typedef struct share_channel share_channel;
 
+typedef struct PortFwdManager PortFwdManager;
+typedef struct PortFwdRecord PortFwdRecord;
+typedef struct ConnectionLayer ConnectionLayer;
+
 typedef struct dlgparam dlgparam;
 
+typedef struct settings_w settings_w;
+typedef struct settings_r settings_r;
+typedef struct settings_e settings_e;
+
 /* Note indirection: for historical reasons (it used to be closer to
  * the OS socket type), the type that most code uses for a socket is
  * 'Socket', not 'Socket *'. So an implementation of Socket or Plug

+ 11 - 0
source/putty/misc.c

@@ -1184,6 +1184,17 @@ int smemeq(const void *av, const void *bv, size_t len)
     return (0x100 - val) >> 8;
 }
 
+int nullstrcmp(const char *a, const char *b)
+{
+    if (a == NULL && b == NULL)
+        return 0;
+    if (a == NULL)
+        return -1;
+    if (b == NULL)
+        return +1;
+    return strcmp(a, b);
+}
+
 ptrlen make_ptrlen(const void *ptr, size_t len)
 {
     ptrlen pl;

+ 6 - 0
source/putty/misc.h

@@ -87,6 +87,12 @@ int validate_manual_hostkey(char *key);
 
 struct tm ltime(void);
 
+/*
+ * Special form of strcmp which can cope with NULL inputs. NULL is
+ * defined to sort before even the empty string.
+ */
+int nullstrcmp(const char *a, const char *b);
+
 ptrlen make_ptrlen(const void *ptr, size_t len);
 int ptrlen_eq_string(ptrlen pl, const char *str);
 char *mkstr(ptrlen pl);

+ 459 - 77
source/putty/portfwd.c

@@ -10,6 +10,18 @@
 #include "ssh.h"
 #include "sshchan.h"
 
+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);
+}
+
 /*
  * Enumeration of values that live in the 'socks_state' field of
  * struct PortForwarding.
@@ -23,8 +35,8 @@ typedef enum {
 } SocksState;
 
 typedef struct PortForwarding {
-    struct ssh_channel *c;        /* channel structure held by ssh.c */
-    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;
@@ -49,7 +61,7 @@ typedef struct PortForwarding {
 } PortForwarding;
 
 struct PortListener {
-    Ssh ssh;                      /* instance of SSH backend itself */
+    ConnectionLayer *cl;
     Socket s;
     int is_dynamic;
     /*
@@ -139,6 +151,8 @@ static void pfd_closing(Plug plug, const char *error_msg, int error_code,
     }
 }
 
+static void pfl_terminate(struct PortListener *pl);
+
 static void pfl_closing(Plug plug, const char *error_msg, int error_code,
 			int calling_back)
 {
@@ -146,11 +160,12 @@ static void pfl_closing(Plug plug, const char *error_msg, int error_code,
     pfl_terminate(pl);
 }
 
-static struct ssh_channel *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;
-    struct ssh_channel *toret;
+    SshChannel *toret;
 
     peerinfo = sk_peer_info(s);
     if (peerinfo) {
@@ -160,7 +175,7 @@ static struct ssh_channel *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;
@@ -405,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);
@@ -447,61 +462,6 @@ static const struct ChannelVtable PortForwarding_channelvt = {
     chan_no_eager_close,
 };
 
-/*
- * Called when receiving a PORT OPEN from the server to make a
- * connection to a destination host.
- *
- * On success, returns NULL and fills in *pf_ret. On error, returns a
- * dynamically allocated error message string.
- */
-char *pfd_connect(Channel **chan_ret, char *hostname,int port,
-                  struct ssh_channel *c, Conf *conf, int addressfamily)
-{
-    SockAddr addr;
-    const char *err;
-    char *dummy_realhost = NULL;
-    struct PortForwarding *pf;
-
-    /*
-     * Try to find host.
-     */
-    addr = name_lookup(hostname, port, &dummy_realhost, conf, addressfamily,
-                       NULL, NULL);
-    if ((err = sk_addr_error(addr)) != NULL) {
-        char *err_ret = dupstr(err);
-	sk_addr_free(addr);
-        sfree(dummy_realhost);
-	return err_ret;
-    }
-
-    /*
-     * Open socket.
-     */
-    pf = new_portfwd_state();
-    *chan_ret = &pf->chan;
-    pf->plugvt = &PortForwarding_plugvt;
-    pf->chan.initial_fixed_window_size = 0;
-    pf->chan.vt = &PortForwarding_channelvt;
-    pf->input_wanted = TRUE;
-    pf->ready = 1;
-    pf->c = c;
-    pf->ssh = NULL;            /* we shouldn't need this */
-    pf->socks_state = SOCKS_NONE;
-
-    pf->s = new_connection(addr, dummy_realhost, port,
-                           0, 1, 0, 0, &pf->plugvt, conf);
-    sfree(dummy_realhost);
-    if ((err = sk_socket_error(pf->s)) != NULL) {
-        char *err_ret = dupstr(err);
-        sk_close(pf->s);
-	free_portfwd_state(pf);
-        *chan_ret = NULL;
-	return err_ret;
-    }
-
-    return NULL;
-}
-
 /*
  called when someone connects to the local port
  */
@@ -521,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) {
@@ -542,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;
@@ -560,12 +520,14 @@ static const Plug_vtable PortListener_plugvt = {
 /*
  * Add a new port-forwarding listener from srcaddr:port -> desthost:destport.
  *
+ * desthost == NULL indicates dynamic SOCKS port forwarding.
+ *
  * On success, returns NULL and fills in *pl_ret. On error, returns a
  * dynamically allocated error message string.
  */
-char *pfl_listen(char *desthost, int destport, char *srcaddr,
-                 int port, Ssh ssh, Conf *conf,
-                 struct PortListener **pl_ret, int address_family)
+static char *pfl_listen(char *desthost, int destport, char *srcaddr,
+                        int port, ConnectionLayer *cl, Conf *conf,
+                        struct PortListener **pl_ret, int address_family)
 {
     const char *err;
     struct PortListener *pl;
@@ -581,7 +543,7 @@ 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),
@@ -614,7 +576,7 @@ static void pfd_close(struct PortForwarding *pf)
 /*
  * Terminate a listener.
  */
-void pfl_terminate(struct PortListener *pl)
+static void pfl_terminate(struct PortListener *pl)
 {
     if (!pl)
 	return;
@@ -676,11 +638,431 @@ static void pfd_open_failure(Channel *chan, const char *errtext)
     pinitassert(chan->vt == &PortForwarding_channelvt);
     PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
 
-    char *msg = dupprintf(
-        "Forwarded connection refused by server%s%s",
-        errtext ? ": " : "", errtext ? errtext : "");
-    logevent(ssh_get_frontend(pf->ssh), msg);
-    sfree(msg);
+    logeventf(pf->cl->frontend,
+              "Forwarded connection refused by server%s%s",
+              errtext ? ": " : "", errtext ? errtext : "");
+}
+
+/* ----------------------------------------------------------------------
+ * Code to manage the complete set of currently active port
+ * forwardings, and update it from Conf.
+ */
+
+struct PortFwdRecord {
+    enum { DESTROY, KEEP, CREATE } status;
+    int type;
+    unsigned sport, dport;
+    char *saddr, *daddr;
+    char *sserv, *dserv;
+    struct ssh_rportfwd *remote;
+    int addressfamily;
+    struct PortListener *local;
+};
+
+static int pfr_cmp(void *av, void *bv)
+{
+    PortFwdRecord *a = (PortFwdRecord *) av;
+    PortFwdRecord *b = (PortFwdRecord *) bv;
+    int i;
+    if (a->type > b->type)
+        return +1;
+    if (a->type < b->type)
+        return -1;
+    if (a->addressfamily > b->addressfamily)
+        return +1;
+    if (a->addressfamily < b->addressfamily)
+        return -1;
+    if ( (i = nullstrcmp(a->saddr, b->saddr)) != 0)
+        return i < 0 ? -1 : +1;
+    if (a->sport > b->sport)
+        return +1;
+    if (a->sport < b->sport)
+        return -1;
+    if (a->type != 'D') {
+        if ( (i = nullstrcmp(a->daddr, b->daddr)) != 0)
+            return i < 0 ? -1 : +1;
+        if (a->dport > b->dport)
+            return +1;
+        if (a->dport < b->dport)
+            return -1;
+    }
+    return 0;
+}
+
+void pfr_free(PortFwdRecord *pfr)
+{
+    /* Dispose of any listening socket. */
+    if (pfr->local)
+        pfl_terminate(pfr->local);
+
+    sfree(pfr->saddr);
+    sfree(pfr->daddr);
+    sfree(pfr->sserv);
+    sfree(pfr->dserv);
+    sfree(pfr);
+}
+
+struct PortFwdManager {
+    ConnectionLayer *cl;
+    Conf *conf;
+    tree234 *forwardings;
+};
+
+PortFwdManager *portfwdmgr_new(ConnectionLayer *cl)
+{
+    PortFwdManager *mgr = snew(PortFwdManager);
+
+    mgr->cl = cl;
+    mgr->conf = NULL;
+    mgr->forwardings = newtree234(pfr_cmp);
+
+    return mgr;
+}
+
+void portfwdmgr_close(PortFwdManager *mgr, PortFwdRecord *pfr)
+{
+    PortFwdRecord *realpfr = del234(mgr->forwardings, pfr);
+    if (realpfr == pfr)
+        pfr_free(pfr);
+}
+
+void portfwdmgr_close_all(PortFwdManager *mgr)
+{
+    PortFwdRecord *pfr;
+
+    while ((pfr = delpos234(mgr->forwardings, 0)) != NULL)
+        pfr_free(pfr);
+}
+
+void portfwdmgr_free(PortFwdManager *mgr)
+{
+    portfwdmgr_close_all(mgr);
+    freetree234(mgr->forwardings);
+    if (mgr->conf)
+        conf_free(mgr->conf);
+    sfree(mgr);
+}
+
+void portfwdmgr_config(PortFwdManager *mgr, Conf *conf)
+{
+    PortFwdRecord *pfr;
+    int i;
+    char *key, *val;
+
+    if (mgr->conf)
+        conf_free(mgr->conf);
+    mgr->conf = conf_copy(conf);
+
+    /*
+     * Go through the existing port forwardings and tag them
+     * with status==DESTROY. Any that we want to keep will be
+     * re-enabled (status==KEEP) as we go through the
+     * configuration and find out which bits are the same as
+     * they were before.
+     */
+    for (i = 0; (pfr = index234(mgr->forwardings, i)) != NULL; i++)
+        pfr->status = DESTROY;
+
+    for (val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key);
+         val != NULL;
+         val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) {
+        char *kp, *kp2, *vp, *vp2;
+        char address_family, type;
+        int sport, dport, sserv, dserv;
+        char *sports, *dports, *saddr, *host;
+
+        kp = key;
+
+        address_family = 'A';
+        type = 'L';
+        if (*kp == 'A' || *kp == '4' || *kp == '6')
+            address_family = *kp++;
+        if (*kp == 'L' || *kp == 'R')
+            type = *kp++;
+
+        if ((kp2 = host_strchr(kp, ':')) != NULL) {
+            /*
+             * There's a colon in the middle of the source port
+             * string, which means that the part before it is
+             * actually a source address.
+             */
+            char *saddr_tmp = dupprintf("%.*s", (int)(kp2 - kp), kp);
+            saddr = host_strduptrim(saddr_tmp);
+            sfree(saddr_tmp);
+            sports = kp2+1;
+        } else {
+            saddr = NULL;
+            sports = kp;
+        }
+        sport = atoi(sports);
+        sserv = 0;
+        if (sport == 0) {
+            sserv = 1;
+            sport = net_service_lookup(sports);
+            if (!sport) {
+                logeventf(mgr->cl->frontend, "Service lookup failed for source"
+                          " port \"%s\"", sports);
+            }
+        }
+
+        if (type == 'L' && !strcmp(val, "D")) {
+            /* dynamic forwarding */
+            host = NULL;
+            dports = NULL;
+            dport = -1;
+            dserv = 0;
+            type = 'D';
+        } else {
+            /* ordinary forwarding */
+            vp = val;
+            vp2 = vp + host_strcspn(vp, ":");
+            host = dupprintf("%.*s", (int)(vp2 - vp), vp);
+            if (*vp2)
+                vp2++;
+            dports = vp2;
+            dport = atoi(dports);
+            dserv = 0;
+            if (dport == 0) {
+                dserv = 1;
+                dport = net_service_lookup(dports);
+                if (!dport) {
+                    logeventf(mgr->cl->frontend,
+                              "Service lookup failed for destination"
+                              " port \"%s\"", dports);
+                }
+            }
+        }
+
+        if (sport && dport) {
+            /* Set up a description of the source port. */
+            pfr = snew(PortFwdRecord);
+            pfr->type = type;
+            pfr->saddr = saddr;
+            pfr->sserv = sserv ? dupstr(sports) : NULL;
+            pfr->sport = sport;
+            pfr->daddr = host;
+            pfr->dserv = dserv ? dupstr(dports) : NULL;
+            pfr->dport = dport;
+            pfr->local = NULL;
+            pfr->remote = NULL;
+            pfr->addressfamily = (address_family == '4' ? ADDRTYPE_IPV4 :
+                                  address_family == '6' ? ADDRTYPE_IPV6 :
+                                  ADDRTYPE_UNSPEC);
+
+            PortFwdRecord *existing = add234(mgr->forwardings, pfr);
+            if (existing != pfr) {
+                if (existing->status == DESTROY) {
+                    /*
+                     * We already have a port forwarding up and running
+                     * with precisely these parameters. Hence, no need
+                     * to do anything; simply re-tag the existing one
+                     * as KEEP.
+                     */
+                    existing->status = KEEP;
+                }
+                /*
+                 * Anything else indicates that there was a duplicate
+                 * in our input, which we'll silently ignore.
+                 */
+                pfr_free(pfr);
+            } else {
+                pfr->status = CREATE;
+            }
+        } else {
+            sfree(saddr);
+            sfree(host);
+        }
+    }
+
+    /*
+     * Now go through and destroy any port forwardings which were
+     * not re-enabled.
+     */
+    for (i = 0; (pfr = index234(mgr->forwardings, i)) != NULL; i++) {
+        if (pfr->status == DESTROY) {
+            char *message;
+
+            message = dupprintf("%s port forwarding from %s%s%d",
+                                pfr->type == 'L' ? "local" :
+                                pfr->type == 'R' ? "remote" : "dynamic",
+                                pfr->saddr ? pfr->saddr : "",
+                                pfr->saddr ? ":" : "",
+                                pfr->sport);
+
+            if (pfr->type != 'D') {
+                char *msg2 = dupprintf("%s to %s:%d", message,
+                                       pfr->daddr, pfr->dport);
+                sfree(message);
+                message = msg2;
+            }
+
+            logeventf(mgr->cl->frontend, "Cancelling %s", message);
+            sfree(message);
+
+            /* pfr->remote or pfr->local may be NULL if setting up a
+             * forwarding failed. */
+            if (pfr->remote) {
+                /*
+                 * Cancel the port forwarding at the server
+                 * end.
+                 *
+                 * Actually closing the listening port on the server
+                 * side may fail - because in SSH-1 there's no message
+                 * in the protocol to request it!
+                 *
+                 * Instead, we simply remove the record of the
+                 * forwarding from our local end, so that any
+                 * connections the server tries to make on it are
+                 * rejected.
+                 */
+                ssh_rportfwd_remove(mgr->cl, pfr->remote);
+            } else if (pfr->local) {
+                pfl_terminate(pfr->local);
+            }
+
+            delpos234(mgr->forwardings, i);
+            pfr_free(pfr);
+            i--;                       /* so we don't skip one in the list */
+        }
+    }
+
+    /*
+     * And finally, set up any new port forwardings (status==CREATE).
+     */
+    for (i = 0; (pfr = index234(mgr->forwardings, i)) != NULL; i++) {
+        if (pfr->status == CREATE) {
+            char *sportdesc, *dportdesc;
+            sportdesc = dupprintf("%s%s%s%s%d%s",
+                                  pfr->saddr ? pfr->saddr : "",
+                                  pfr->saddr ? ":" : "",
+                                  pfr->sserv ? pfr->sserv : "",
+                                  pfr->sserv ? "(" : "",
+                                  pfr->sport,
+                                  pfr->sserv ? ")" : "");
+            if (pfr->type == 'D') {
+                dportdesc = NULL;
+            } else {
+                dportdesc = dupprintf("%s:%s%s%d%s",
+                                      pfr->daddr,
+                                      pfr->dserv ? pfr->dserv : "",
+                                      pfr->dserv ? "(" : "",
+                                      pfr->dport,
+                                      pfr->dserv ? ")" : "");
+            }
+
+            if (pfr->type == 'L') {
+                char *err = pfl_listen(pfr->daddr, pfr->dport,
+                                       pfr->saddr, pfr->sport,
+                                       mgr->cl, conf, &pfr->local,
+                                       pfr->addressfamily);
+
+                logeventf(mgr->cl->frontend,
+                          "Local %sport %s forwarding to %s%s%s",
+                          pfr->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
+                          pfr->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
+                          sportdesc, dportdesc,
+                          err ? " failed: " : "", err ? err : "");
+                if (err)
+                    sfree(err);
+            } else if (pfr->type == 'D') {
+                char *err = pfl_listen(NULL, -1, pfr->saddr, pfr->sport,
+                                       mgr->cl, conf, &pfr->local,
+                                       pfr->addressfamily);
+
+                logeventf(mgr->cl->frontend,
+                          "Local %sport %s SOCKS dynamic forwarding%s%s",
+                          pfr->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
+                          pfr->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
+                          sportdesc,
+                          err ? " failed: " : "", err ? err : "");
+
+                if (err)
+                    sfree(err);
+            } else {
+                const char *shost;
+
+                if (pfr->saddr) {
+                    shost = pfr->saddr;
+                } else if (conf_get_int(conf, CONF_rport_acceptall)) {
+                    shost = "";
+                } else {
+                    shost = "localhost";
+                }
+
+                pfr->remote = ssh_rportfwd_alloc(
+                    mgr->cl, shost, pfr->sport, pfr->daddr, pfr->dport,
+                    pfr->addressfamily, sportdesc, pfr, NULL);
+
+                if (!pfr->remote) {
+                    logeventf(mgr->cl->frontend,
+                              "Duplicate remote port forwarding to %s:%d",
+                              pfr->daddr, pfr->dport);
+                    pfr_free(pfr);
+                } else {
+                    logeventf(mgr->cl->frontend, "Requesting remote port %s"
+                              " forward to %s", sportdesc, dportdesc);
+                }
+            }
+            sfree(sportdesc);
+            sfree(dportdesc);
+        }
+    }
+}
+
+/*
+ * Called when receiving a PORT OPEN from the server to make a
+ * connection to a destination host.
+ *
+ * On success, returns NULL and fills in *pf_ret. On error, returns a
+ * dynamically allocated error message string.
+ */
+char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret,
+                         char *hostname, int port, SshChannel *c,
+                         int addressfamily)
+{
+    SockAddr addr;
+    const char *err;
+    char *dummy_realhost = NULL;
+    struct PortForwarding *pf;
+
+    /*
+     * Try to find host.
+     */
+    addr = name_lookup(hostname, port, &dummy_realhost, mgr->conf,
+                       addressfamily, NULL, NULL);
+    if ((err = sk_addr_error(addr)) != NULL) {
+        char *err_ret = dupstr(err);
+        sk_addr_free(addr);
+        sfree(dummy_realhost);
+        return err_ret;
+    }
+
+    /*
+     * Open socket.
+     */
+    pf = new_portfwd_state();
+    *chan_ret = &pf->chan;
+    pf->plugvt = &PortForwarding_plugvt;
+    pf->chan.initial_fixed_window_size = 0;
+    pf->chan.vt = &PortForwarding_channelvt;
+    pf->input_wanted = TRUE;
+    pf->ready = 1;
+    pf->c = c;
+    pf->cl = mgr->cl;
+    pf->socks_state = SOCKS_NONE;
+
+    pf->s = new_connection(addr, dummy_realhost, port,
+                           0, 1, 0, 0, &pf->plugvt, mgr->conf);
+    sfree(dummy_realhost);
+    if ((err = sk_socket_error(pf->s)) != NULL) {
+        char *err_ret = dupstr(err);
+        sk_close(pf->s);
+        free_portfwd_state(pf);
+        *chan_ret = NULL;
+        return err_ret;
+    }
+
+    return NULL;
 }
 
 #ifdef MPEXT

+ 2 - 2
source/putty/putty.h

@@ -1080,9 +1080,9 @@ const struct Backend_vtable *backend_vt_from_name(const char *name);
 const struct Backend_vtable *backend_vt_from_proto(int proto);
 char *get_remote_username(Conf *conf); /* dynamically allocated */
 char *save_settings(const char *section, Conf *conf);
-void save_open_settings(void *sesskey, Conf *conf);
+void save_open_settings(settings_w *sesskey, Conf *conf);
 void load_settings(const char *section, Conf *conf);
-void load_open_settings(void *sesskey, Conf *conf);
+void load_open_settings(settings_r *sesskey, Conf *conf);
 void get_sesslist(struct sesslist *, int allocate);
 void do_defaults(const char *, Conf *);
 void registry_cleanup(void);

Разлика између датотеке није приказан због своје велике величине
+ 223 - 513
source/putty/ssh.c


+ 122 - 84
source/putty/ssh.h

@@ -12,19 +12,6 @@
 #ifndef WINSCP_VS
 struct ssh_channel;
 
-extern int sshfwd_write(struct ssh_channel *c, const void *, int);
-extern void sshfwd_write_eof(struct ssh_channel *c);
-extern void sshfwd_unclean_close(struct ssh_channel *c, const char *err);
-extern void sshfwd_unthrottle(struct ssh_channel *c, int bufsize);
-Conf *sshfwd_get_conf(struct ssh_channel *c);
-void sshfwd_window_override_removed(struct ssh_channel *c);
-void sshfwd_x11_sharing_handover(struct ssh_channel *c,
-                                 ssh_sharing_connstate *share_cs,
-                                 share_channel *share_chan,
-                                 const char *peer_addr, int peer_port,
-                                 int endian, int protomajor, int protominor,
-                                 const void *initial_data, int initial_len);
-
 /*
  * Buffer management constants. There are several of these for
  * various different purposes:
@@ -153,8 +140,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);
@@ -165,26 +152,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);
-int ssh_alloc_sharing_rportfwd(Ssh ssh, const char *shost, int sport,
-                               ssh_sharing_connstate *connstate);
-void ssh_remove_sharing_rportfwd(Ssh ssh, const char *shost, int sport,
-                                 ssh_sharing_connstate *connstate);
-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,
@@ -193,6 +160,87 @@ void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan,
                              int protomajor, int protominor,
                              const void *initial_data, int initial_len);
 
+struct ssh_rportfwd;
+
+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(ConnectionLayer *cl);
+void portfwdmgr_free(PortFwdManager *mgr);
+void portfwdmgr_config(PortFwdManager *mgr, Conf *conf);
+void portfwdmgr_close(PortFwdManager *mgr, PortFwdRecord *pfr);
+void portfwdmgr_close_all(PortFwdManager *mgr);
+char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret,
+                         char *hostname, int port, SshChannel *c,
+                         int addressfamily);
+
 Frontend *ssh_get_frontend(Ssh ssh);
 
 #define SSH_CIPHER_IDEA		1
@@ -387,7 +435,7 @@ struct hmacmd5_context *hmacmd5_make_context(void);
 void hmacmd5_free_context(struct hmacmd5_context *ctx);
 void hmacmd5_key(struct hmacmd5_context *ctx, void const *key, int len);
 void hmacmd5_do_hmac(struct hmacmd5_context *ctx,
-                     unsigned char const *blk, int len, unsigned char *hmac);
+                     const void *blk, int len, unsigned char *hmac);
 
 int supports_sha_ni(void);
 
@@ -413,7 +461,8 @@ void SHA_Init(SHA_State * s);
 void SHA_Final(SHA_State * s, unsigned char *output);
 void SHA_Simple(const void *p, int len, unsigned char *output);
 
-void hmac_sha1_simple(void *key, int keylen, void *data, int datalen,
+void hmac_sha1_simple(const void *key, int keylen,
+                      const void *data, int datalen,
 		      unsigned char *output);
 #endif // WINSCP_VS
 typedef struct SHA256_State {
@@ -621,23 +670,39 @@ struct ssh_keyalg {
 #define ssh_key_ssh_id(key) ((*(key))->ssh_id)
 #define ssh_key_cache_id(key) ((*(key))->cache_id)
 
-struct ssh_compress {
+typedef struct ssh_compressor {
+    const struct ssh_compression_alg *vt;
+} ssh_compressor;
+typedef struct ssh_decompressor {
+    const struct ssh_compression_alg *vt;
+} ssh_decompressor;
+
+struct ssh_compression_alg {
     const char *name;
     /* For [email protected]: if non-NULL, this name will be considered once
      * userauth has completed successfully. */
     const char *delayed_name;
-    void *(*compress_init) (void);
-    void (*compress_cleanup) (void *);
-    void (*compress) (void *, unsigned char *block, int len,
-                      unsigned char **outblock, int *outlen,
-                      int minlen);
-    void *(*decompress_init) (void);
-    void (*decompress_cleanup) (void *);
-    int (*decompress) (void *, unsigned char *block, int len,
-		       unsigned char **outblock, int *outlen);
+    ssh_compressor *(*compress_new)(void);
+    void (*compress_free)(ssh_compressor *);
+    void (*compress)(ssh_compressor *, unsigned char *block, int len,
+                     unsigned char **outblock, int *outlen,
+                     int minlen);
+    ssh_decompressor *(*decompress_new)(void);
+    void (*decompress_free)(ssh_decompressor *);
+    int (*decompress)(ssh_decompressor *, unsigned char *block, int len,
+                      unsigned char **outblock, int *outlen);
     const char *text_name;
 };
 
+#define ssh_compressor_new(alg) ((alg)->compress_new())
+#define ssh_compressor_free(comp) ((comp)->vt->compress_free(comp))
+#define ssh_compressor_compress(comp, in, inlen, out, outlen, minlen) \
+    ((comp)->vt->compress(comp, in, inlen, out, outlen, minlen))
+#define ssh_decompressor_new(alg) ((alg)->decompress_new())
+#define ssh_decompressor_free(comp) ((comp)->vt->decompress_free(comp))
+#define ssh_decompressor_decompress(comp, in, inlen, out, outlen) \
+    ((comp)->vt->decompress(comp, in, inlen, out, outlen))
+
 struct ssh2_userkey {
     ssh_key *key;                      /* the key itself */
     char *comment;		       /* the key comment */
@@ -677,6 +742,7 @@ extern const struct ssh2_macalg ssh_hmac_sha1_buggy;
 extern const struct ssh2_macalg ssh_hmac_sha1_96;
 extern const struct ssh2_macalg ssh_hmac_sha1_96_buggy;
 extern const struct ssh2_macalg ssh_hmac_sha256;
+extern const struct ssh_compression_alg ssh_zlib;
 
 typedef struct AESContext AESContext;
 AESContext *aes_make_context(void);
@@ -736,22 +802,6 @@ void random_add_heavynoise(void *noise, int length);
 
 void logevent(Frontend *, const char *);
 
-struct PortForwarding;
-
-/* Allocate and register a new channel for port forwarding */
-struct ssh_channel *ssh_send_port_open(Ssh ssh, const char *hostname, int port,
-                                       const char *org, Channel *chan);
-
-/* Exports from portfwd.c */
-extern char *pfd_connect(Channel **chan_ret, char *hostname, int port,
-                         struct ssh_channel *c, Conf *conf, int addressfamily);
-struct PortListener;
-/* desthost == NULL indicates dynamic (SOCKS) port forwarding */
-extern char *pfl_listen(char *desthost, int destport, char *srcaddr,
-                        int port, Ssh ssh, Conf *conf,
-                        struct PortListener **pl, int address_family);
-extern void pfl_terminate(struct PortListener *);
-
 /* Exports from x11fwd.c */
 enum {
     X11_TRANS_IPV4 = 0, X11_TRANS_IPV6 = 6, X11_TRANS_UNIX = 256
@@ -818,7 +868,7 @@ extern struct X11Display *x11_setup_display(const char *display, Conf *);
 void x11_free_display(struct X11Display *disp);
 struct X11FakeAuth *x11_invent_fake_auth(tree234 *t, int authtype);
 void x11_free_fake_auth(struct X11FakeAuth *auth);
-Channel *x11_new_channel(tree234 *authtree, struct ssh_channel *c,
+Channel *x11_new_channel(tree234 *authtree, SshChannel *c,
                          const char *peeraddr, int peerport,
                          int connection_sharing_possible);
 char *x11_display(const char *display);
@@ -850,7 +900,7 @@ void x11_get_auth_from_authfile(struct X11Display *display,
 int x11_identify_auth_proto(ptrlen protoname);
 void *x11_dehexify(ptrlen hex, int *outlen);
 
-Channel *agentf_new(struct ssh_channel *c);
+Channel *agentf_new(SshChannel *c);
 
 Bignum copybn(Bignum b);
 Bignum bn_power_2(int n);
@@ -896,12 +946,13 @@ void diagbn(char *prefix, Bignum md);
 #endif
 
 int dh_is_gex(const struct ssh_kex *kex);
-void *dh_setup_group(const struct ssh_kex *kex);
-void *dh_setup_gex(Bignum pval, Bignum gval);
-void dh_cleanup(void *);
-Bignum dh_create_e(void *, int nbits);
-const char *dh_validate_f(void *handle, Bignum f);
-Bignum dh_find_K(void *, Bignum f);
+struct dh_ctx;
+struct dh_ctx *dh_setup_group(const struct ssh_kex *kex);
+struct dh_ctx *dh_setup_gex(Bignum pval, Bignum gval);
+void dh_cleanup(struct dh_ctx *);
+Bignum dh_create_e(struct dh_ctx *, int nbits);
+const char *dh_validate_f(struct dh_ctx *, Bignum f);
+Bignum dh_find_K(struct dh_ctx *, Bignum f);
 
 int rsa_ssh1_encrypted(const Filename *filename, char **comment);
 int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs,
@@ -1043,19 +1094,6 @@ Bignum primegen(int bits, int modulus, int residue, Bignum factor,
 		int phase, progfn_t pfn, void *pfnparam, unsigned firstbits);
 void invent_firstbits(unsigned *one, unsigned *two);
 
-
-/*
- * zlib compression.
- */
-void *zlib_compress_init(void);
-void zlib_compress_cleanup(void *);
-void *zlib_decompress_init(void);
-void zlib_decompress_cleanup(void *);
-void zlib_compress_block(void *, unsigned char *block, int len,
-                         unsigned char **outblock, int *outlen, int minlen);
-int zlib_decompress_block(void *, unsigned char *block, int len,
-			  unsigned char **outblock, int *outlen);
-
 /*
  * Connection-sharing API provided by platforms. This function must
  * either:

+ 11 - 10
source/putty/ssh1bpp.c

@@ -21,7 +21,8 @@ struct ssh1_bpp_state {
 
     struct crcda_ctx *crcda_ctx;
 
-    void *compctx, *decompctx;
+    ssh_compressor *compctx;
+    ssh_decompressor *decompctx;
 
     BinaryPacketProtocol bpp;
 };
@@ -52,9 +53,9 @@ static void ssh1_bpp_free(BinaryPacketProtocol *bpp)
     if (s->cipher)
         ssh1_cipher_free(s->cipher);
     if (s->compctx)
-        zlib_compress_cleanup(s->compctx);
+        ssh_compressor_free(s->compctx);
     if (s->decompctx)
-        zlib_decompress_cleanup(s->decompctx);
+        ssh_decompressor_free(s->decompctx);
     if (s->crcda_ctx)
         crcda_free_context(s->crcda_ctx);
     if (s->pktin)
@@ -90,8 +91,8 @@ void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp)
     assert(!s->compctx);
     assert(!s->decompctx);
 
-    s->compctx = zlib_compress_init();
-    s->decompctx = zlib_decompress_init();
+    s->compctx = ssh_compressor_new(&ssh_zlib);
+    s->decompctx = ssh_decompressor_new(&ssh_zlib);
 }
 
 static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp)
@@ -157,9 +158,9 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp)
         if (s->decompctx) {
             unsigned char *decompblk;
             int decomplen;
-            if (!zlib_decompress_block(s->decompctx,
-                                       s->data + s->pad, s->length + 1,
-                                       &decompblk, &decomplen)) {
+            if (!ssh_decompressor_decompress(
+                    s->decompctx, s->data + s->pad, s->length + 1,
+                    &decompblk, &decomplen)) {
                 s->bpp.error = dupprintf(
                     "Zlib decompression encountered invalid data");
                 crStopV;
@@ -248,8 +249,8 @@ static void ssh1_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt)
     if (s->compctx) {
         unsigned char *compblk;
         int complen;
-        zlib_compress_block(s->compctx, pkt->data + 12, pkt->length - 12,
-                            &compblk, &complen, 0);
+        ssh_compressor_compress(s->compctx, pkt->data + 12, pkt->length - 12,
+                                &compblk, &complen, 0);
         /* Replace the uncompressed packet data with the compressed
          * version. */
         pkt->length = 12;

+ 29 - 28
source/putty/ssh2bpp.c

@@ -14,8 +14,6 @@ struct ssh2_bpp_direction {
     ssh2_cipher *cipher;
     ssh2_mac *mac;
     int etm_mode;
-    const struct ssh_compress *comp;
-    void *comp_ctx;
 };
 
 struct ssh2_bpp_state {
@@ -28,6 +26,11 @@ struct ssh2_bpp_state {
     PktIn *pktin;
 
     struct ssh2_bpp_direction in, out;
+    /* comp and decomp logically belong in the per-direction
+     * substructure, except that they have different types */
+    ssh_decompressor *in_decomp;
+    ssh_compressor *out_comp;
+
     int pending_newkeys;
 
     BinaryPacketProtocol bpp;
@@ -61,14 +64,14 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp)
         ssh2_cipher_free(s->out.cipher);
     if (s->out.mac)
         ssh2_mac_free(s->out.mac);
-    if (s->out.comp_ctx)
-        s->out.comp->compress_cleanup(s->out.comp_ctx);
+    if (s->out_comp)
+        ssh_compressor_free(s->out_comp);
     if (s->in.cipher)
         ssh2_cipher_free(s->in.cipher);
     if (s->in.mac)
         ssh2_mac_free(s->in.mac);
-    if (s->in.comp_ctx)
-        s->in.comp->decompress_cleanup(s->in.comp_ctx);
+    if (s->in_decomp)
+        ssh_decompressor_free(s->in_decomp);
     if (s->pktin)
         ssh_unref_packet(s->pktin);
     sfree(s);
@@ -78,7 +81,7 @@ void ssh2_bpp_new_outgoing_crypto(
     BinaryPacketProtocol *bpp,
     const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv,
     const struct ssh2_macalg *mac, int etm_mode, const void *mac_key,
-    const struct ssh_compress *compression)
+    const struct ssh_compression_alg *compression)
 {
     struct ssh2_bpp_state *s;
     assert(bpp->vt == &ssh2_bpp_vtable);
@@ -88,8 +91,8 @@ void ssh2_bpp_new_outgoing_crypto(
         ssh2_cipher_free(s->out.cipher);
     if (s->out.mac)
         ssh2_mac_free(s->out.mac);
-    if (s->out.comp_ctx)
-        s->out.comp->compress_cleanup(s->out.comp_ctx);
+    if (s->out_comp)
+        ssh_compressor_free(s->out_comp);
 
     if (cipher) {
         s->out.cipher = ssh2_cipher_new(cipher);
@@ -106,18 +109,17 @@ void ssh2_bpp_new_outgoing_crypto(
         s->out.mac = NULL;
     }
 
-    s->out.comp = compression;
-    /* out_comp is always non-NULL, because no compression is
-     * indicated by ssh_comp_none. So compress_init always exists, but
-     * it may return a null out_comp_ctx. */
-    s->out.comp_ctx = compression->compress_init();
+    /* 'compression' is always non-NULL, because no compression is
+     * indicated by ssh_comp_none. But this setup call may return a
+     * null out_comp. */
+    s->out_comp = ssh_compressor_new(compression);
 }
 
 void ssh2_bpp_new_incoming_crypto(
     BinaryPacketProtocol *bpp,
     const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv,
     const struct ssh2_macalg *mac, int etm_mode, const void *mac_key,
-    const struct ssh_compress *compression)
+    const struct ssh_compression_alg *compression)
 {
     struct ssh2_bpp_state *s;
     assert(bpp->vt == &ssh2_bpp_vtable);
@@ -127,8 +129,8 @@ void ssh2_bpp_new_incoming_crypto(
         ssh2_cipher_free(s->in.cipher);
     if (s->in.mac)
         ssh2_mac_free(s->in.mac);
-    if (s->in.comp_ctx)
-        s->in.comp->decompress_cleanup(s->in.comp_ctx);
+    if (s->in_decomp)
+        ssh_decompressor_free(s->in_decomp);
 
     if (cipher) {
         s->in.cipher = ssh2_cipher_new(cipher);
@@ -145,11 +147,10 @@ void ssh2_bpp_new_incoming_crypto(
         s->in.mac = NULL;
     }
 
-    s->in.comp = compression;
-    /* in_comp is always non-NULL, because no compression is
-     * indicated by ssh_comp_none. So compress_init always exists, but
-     * it may return a null in_comp_ctx. */
-    s->in.comp_ctx = compression->decompress_init();
+    /* 'compression' is always non-NULL, because no compression is
+     * indicated by ssh_comp_none. But this setup call may return a
+     * null in_decomp. */
+    s->in_decomp = ssh_decompressor_new(compression);
 
     /* Clear the pending_newkeys flag, so that handle_input below will
      * start consuming the input data again. */
@@ -419,8 +420,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
         {
             unsigned char *newpayload;
             int newlen;
-            if (s->in.comp && s->in.comp->decompress(
-                    s->in.comp_ctx, s->data + 5, s->length - 5,
+            if (s->in_decomp && ssh_decompressor_decompress(
+                    s->in_decomp, s->data + 5, s->length - 5,
                     &newpayload, &newlen)) {
                 if (s->maxlen < newlen + 5) {
                     PktIn *old_pktin = s->pktin;
@@ -526,7 +527,7 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
     cipherblk = s->out.cipher ? ssh2_cipher_alg(s->out.cipher)->blksize : 8;
     cipherblk = cipherblk < 8 ? 8 : cipherblk;  /* or 8 if blksize < 8 */
 
-    if (s->out.comp && s->out.comp_ctx) {
+    if (s->out_comp) {
         unsigned char *newpayload;
         int minlen, newlen;
 
@@ -544,8 +545,8 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
             minlen -= 8;              /* length field + min padding */
         }
 
-        s->out.comp->compress(s->out.comp_ctx, pkt->data + 5, pkt->length - 5,
-                              &newpayload, &newlen, minlen);
+        ssh_compressor_compress(s->out_comp, pkt->data + 5, pkt->length - 5,
+                                &newpayload, &newlen, minlen);
         pkt->length = 5;
         put_data(pkt, newpayload, newlen);
         sfree(newpayload);
@@ -608,7 +609,7 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt)
 {
     struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp);
 
-    if (pkt->minlen > 0 && !(s->out.comp && s->out.comp_ctx)) {
+    if (pkt->minlen > 0 && !s->out_comp) {
         /*
          * If we've been told to pad the packet out to a given minimum
          * length, but we're not compressing (and hence can't get the

+ 2 - 2
source/putty/sshbpp.h

@@ -41,12 +41,12 @@ void ssh2_bpp_new_outgoing_crypto(
     BinaryPacketProtocol *bpp,
     const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv,
     const struct ssh2_macalg *mac, int etm_mode, const void *mac_key,
-    const struct ssh_compress *compression);
+    const struct ssh_compression_alg *compression);
 void ssh2_bpp_new_incoming_crypto(
     BinaryPacketProtocol *bpp,
     const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv,
     const struct ssh2_macalg *mac, int etm_mode, const void *mac_key,
-    const struct ssh_compress *compression);
+    const struct ssh_compression_alg *compression);
 
 BinaryPacketProtocol *ssh2_bare_bpp_new(void);
 

+ 34 - 0
source/putty/sshchan.h

@@ -56,4 +56,38 @@ void chan_remotely_opened_failure(Channel *chan, const char *errtext);
  * closing until both directions have had an EOF */
 int chan_no_eager_close(Channel *, int, int);
 
+/* ----------------------------------------------------------------------
+ * This structure is owned by an SSH connection layer, and identifies
+ * the connection layer's end of the channel, for the Channel
+ * implementation to talk back to.
+ */
+
+struct SshChannelVtable {
+    int (*write)(SshChannel *c, const void *, int);
+    void (*write_eof)(SshChannel *c);
+    void (*unclean_close)(SshChannel *c, const char *err);
+    void (*unthrottle)(SshChannel *c, int bufsize);
+    Conf *(*get_conf)(SshChannel *c);
+    void (*window_override_removed)(SshChannel *c);
+    void (*x11_sharing_handover)(SshChannel *c,
+                                 ssh_sharing_connstate *share_cs,
+                                 share_channel *share_chan,
+                                 const char *peer_addr, int peer_port,
+                                 int endian, int protomajor, int protominor,
+                                 const void *initial_data, int initial_len);
+};
+
+struct SshChannel {
+    const struct SshChannelVtable *vt;
+};
+
+#define sshfwd_write(c, buf, len) ((c)->vt->write(c, buf, len))
+#define sshfwd_write_eof(c) ((c)->vt->write_eof(c))
+#define sshfwd_unclean_close(c, err) ((c)->vt->unclean_close(c, err))
+#define sshfwd_unthrottle(c, bufsize) ((c)->vt->unthrottle(c, bufsize))
+#define sshfwd_get_conf(c) ((c)->vt->get_conf(c))
+#define sshfwd_window_override_removed(c) ((c)->vt->window_override_removed(c))
+#define sshfwd_x11_sharing_handover(c, cs, ch, pa, pp, e, pmaj, pmin, d, l) \
+    ((c)->vt->x11_sharing_handover(c, cs, ch, pa, pp, e, pmaj, pmin, d, l))
+
 #endif /* PUTTY_SSHCHAN_H */

+ 6 - 10
source/putty/sshdh.c

@@ -187,7 +187,7 @@ int dh_is_gex(const struct ssh_kex *kex)
 /*
  * Initialise DH for a standard group.
  */
-void *dh_setup_group(const struct ssh_kex *kex)
+struct dh_ctx *dh_setup_group(const struct ssh_kex *kex)
 {
     const struct dh_extra *extra = (const struct dh_extra *)kex->extra;
     struct dh_ctx *ctx = snew(struct dh_ctx);
@@ -200,7 +200,7 @@ void *dh_setup_group(const struct ssh_kex *kex)
 /*
  * Initialise DH for a server-supplied group.
  */
-void *dh_setup_gex(Bignum pval, Bignum gval)
+struct dh_ctx *dh_setup_gex(Bignum pval, Bignum gval)
 {
     struct dh_ctx *ctx = snew(struct dh_ctx);
     ctx->p = copybn(pval);
@@ -212,9 +212,8 @@ void *dh_setup_gex(Bignum pval, Bignum gval)
 /*
  * Clean up and free a context.
  */
-void dh_cleanup(void *handle)
+void dh_cleanup(struct dh_ctx *ctx)
 {
-    struct dh_ctx *ctx = (struct dh_ctx *)handle;
     freebn(ctx->x);
     freebn(ctx->e);
     freebn(ctx->p);
@@ -239,9 +238,8 @@ void dh_cleanup(void *handle)
  * Advances in Cryptology: Proceedings of Eurocrypt '96
  * Springer-Verlag, May 1996.
  */
-Bignum dh_create_e(void *handle, int nbits)
+Bignum dh_create_e(struct dh_ctx *ctx, int nbits)
 {
-    struct dh_ctx *ctx = (struct dh_ctx *)handle;
     int i;
 
     int nbytes;
@@ -295,9 +293,8 @@ Bignum dh_create_e(void *handle, int nbits)
  * they lead to obviously weak keys that even a passive eavesdropper
  * can figure out.)
  */
-const char *dh_validate_f(void *handle, Bignum f)
+const char *dh_validate_f(struct dh_ctx *ctx, Bignum f)
 {
-    struct dh_ctx *ctx = (struct dh_ctx *)handle;
     if (bignum_cmp(f, One) <= 0) {
         return "f value received is too small";
     } else {
@@ -313,9 +310,8 @@ const char *dh_validate_f(void *handle, Bignum f)
 /*
  * DH stage 2: given a number f, compute K = f^x mod p.
  */
-Bignum dh_find_K(void *handle, Bignum f)
+Bignum dh_find_K(struct dh_ctx *ctx, Bignum f)
 {
-    struct dh_ctx *ctx = (struct dh_ctx *)handle;
     Bignum ret;
     ret = modpow(f, ctx->x, ctx->p);
     return ret;

+ 1 - 1
source/putty/sshmd5.c

@@ -315,7 +315,7 @@ static void hmacmd5_genresult(ssh2_mac *mac, unsigned char *hmac)
 }
 
 void hmacmd5_do_hmac(struct hmacmd5_context *ctx,
-                     unsigned char const *blk, int len, unsigned char *hmac)
+                     const void *blk, int len, unsigned char *hmac)
 {
     ssh2_mac_start(&ctx->mac);
     put_data(&ctx->mac, blk, len);

+ 2 - 1
source/putty/sshsha.c

@@ -363,7 +363,8 @@ static void hmacsha1_genresult(ssh2_mac *mac, unsigned char *hmac)
     smemclr(intermediate, sizeof(intermediate));
 }
 
-void hmac_sha1_simple(void *key, int keylen, void *data, int datalen,
+void hmac_sha1_simple(const void *key, int keylen,
+                      const void *data, int datalen,
 		      unsigned char *output) {
     SHA_State states[2];
     unsigned char intermediate[20];

+ 124 - 55
source/putty/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;
@@ -242,6 +242,7 @@ struct share_forwarding {
     char *host;
     int port;
     int active;             /* has the server sent REQUEST_SUCCESS? */
+    struct ssh_rportfwd *rpf;
 };
 
 struct share_xchannel_message {
@@ -617,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);
@@ -702,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)
@@ -789,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);
@@ -818,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);
@@ -827,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 */
             }
@@ -851,13 +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_remove_sharing_rportfwd(cs->parent->ssh,
-                                        fwd->host, fwd->port, cs);
+            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) {
@@ -1306,7 +1344,8 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
         if (ptrlen_eq_string(request_name, "tcpip-forward")) {
             ptrlen hostpl;
             char *host;
-            int port, ret;
+            int port;
+            struct ssh_rportfwd *rpf;
 
             /*
              * Pick the packet apart to find the want_reply field and
@@ -1328,8 +1367,9 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
              * ourselves to manufacture a failure packet and send it
              * back to downstream.
              */
-            ret = ssh_alloc_sharing_rportfwd(cs->parent->ssh, host, port, cs);
-            if (!ret) {
+            rpf = ssh_rportfwd_alloc(
+                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,
                                               "", 0, NULL);
@@ -1344,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);
@@ -1359,6 +1399,8 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
                     globreq->fwd = fwd;
                     globreq->want_reply = orig_wantreply;
                     globreq->type = GLOBREQ_TCPIP_FORWARD;
+
+                    fwd->rpf = rpf;
                 }
             }
 
@@ -1395,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_remove_sharing_rportfwd(cs->parent->ssh, host, port, cs);
+                ssh_rportfwd_remove(cs->parent->cl, fwd->rpf);
 
                 /*
                  * Pass the cancel request on to the SSH server, but
@@ -1405,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
@@ -1441,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)) {
@@ -1450,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;
 
@@ -1473,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;
@@ -1487,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) {
@@ -1511,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))
@@ -1565,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, "[email protected]") &&
-                !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) {
@@ -1639,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;
 
@@ -1657,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);
 
@@ -1665,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 {
@@ -1753,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;
 
     /*
@@ -1809,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;
 }
@@ -1919,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;
@@ -2020,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))
@@ -2061,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:
         /*
@@ -2072,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:
         /*
@@ -2084,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:
         /*
@@ -2095,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;
 }

+ 41 - 24
source/putty/sshzlib.c

@@ -66,6 +66,10 @@
 #define TRUE 1
 #endif
 
+typedef struct { const struct dummy *vt; } ssh_compressor;
+typedef struct { const struct dummy *vt; } ssh_decompressor;
+static const struct dummy { int i; } ssh_zlib;
+
 #else
 #include "ssh.h"
 #endif
@@ -600,37 +604,45 @@ static void zlib_match(struct LZ77Context *ectx, int distance, int len)
     }
 }
 
-void *zlib_compress_init(void)
+struct ssh_zlib_compressor {
+    struct LZ77Context ectx;
+    ssh_compressor sc;
+};
+
+ssh_compressor *zlib_compress_init(void)
 {
     struct Outbuf *out;
-    struct LZ77Context *ectx = snew(struct LZ77Context);
+    struct ssh_zlib_compressor *comp = snew(struct ssh_zlib_compressor);
 
-    lz77_init(ectx);
-    ectx->literal = zlib_literal;
-    ectx->match = zlib_match;
+    lz77_init(&comp->ectx);
+    comp->sc.vt = &ssh_zlib;
+    comp->ectx.literal = zlib_literal;
+    comp->ectx.match = zlib_match;
 
     out = snew(struct Outbuf);
     out->outbits = out->noutbits = 0;
     out->firstblock = 1;
-    ectx->userdata = out;
+    comp->ectx.userdata = out;
 
-    return ectx;
+    return &comp->sc;
 }
 
-void zlib_compress_cleanup(void *handle)
+void zlib_compress_cleanup(ssh_compressor *sc)
 {
-    struct LZ77Context *ectx = (struct LZ77Context *)handle;
-    sfree(ectx->userdata);
-    sfree(ectx->ictx);
-    sfree(ectx);
+    struct ssh_zlib_compressor *comp =
+        FROMFIELD(sc, struct ssh_zlib_compressor, sc);
+    sfree(comp->ectx.userdata);
+    sfree(comp->ectx.ictx);
+    sfree(comp);
 }
 
-void zlib_compress_block(void *handle, unsigned char *block, int len,
+void zlib_compress_block(ssh_compressor *sc, unsigned char *block, int len,
                          unsigned char **outblock, int *outlen,
                          int minlen)
 {
-    struct LZ77Context *ectx = (struct LZ77Context *)handle;
-    struct Outbuf *out = (struct Outbuf *) ectx->userdata;
+    struct ssh_zlib_compressor *comp =
+        FROMFIELD(sc, struct ssh_zlib_compressor, sc);
+    struct Outbuf *out = (struct Outbuf *) comp->ectx.userdata;
     int in_block;
 
     out->outbuf = NULL;
@@ -662,7 +674,7 @@ void zlib_compress_block(void *handle, unsigned char *block, int len,
     /*
      * Do the compression.
      */
-    lz77_compress(ectx, block, len, TRUE);
+    lz77_compress(&comp->ectx, block, len, TRUE);
 
     /*
      * End the block (by transmitting code 256, which is
@@ -875,9 +887,11 @@ struct zlib_decompress_ctx {
     int winpos;
     unsigned char *outblk;
     int outlen, outsize;
+
+    ssh_decompressor dc;
 };
 
-void *zlib_decompress_init(void)
+ssh_decompressor *zlib_decompress_init(void)
 {
     struct zlib_decompress_ctx *dctx = snew(struct zlib_decompress_ctx);
     unsigned char lengths[288];
@@ -895,12 +909,14 @@ void *zlib_decompress_init(void)
     dctx->nbits = 0;
     dctx->winpos = 0;
 
-    return dctx;
+    dctx->dc.vt = &ssh_zlib;
+    return &dctx->dc;
 }
 
-void zlib_decompress_cleanup(void *handle)
+void zlib_decompress_cleanup(ssh_decompressor *dc)
 {
-    struct zlib_decompress_ctx *dctx = (struct zlib_decompress_ctx *)handle;
+    struct zlib_decompress_ctx *dctx =
+        FROMFIELD(dc, struct zlib_decompress_ctx, dc);
 
     if (dctx->currlentable && dctx->currlentable != dctx->staticlentable)
 	zlib_freetable(&dctx->currlentable);
@@ -958,10 +974,11 @@ static void zlib_emit_char(struct zlib_decompress_ctx *dctx, int c)
 
 #define EATBITS(n) ( dctx->nbits -= (n), dctx->bits >>= (n) )
 
-int zlib_decompress_block(void *handle, unsigned char *block, int len,
+int zlib_decompress_block(ssh_decompressor *dc, unsigned char *block, int len,
 			  unsigned char **outblock, int *outlen)
 {
-    struct zlib_decompress_ctx *dctx = (struct zlib_decompress_ctx *)handle;
+    struct zlib_decompress_ctx *dctx =
+        FROMFIELD(dc, struct zlib_decompress_ctx, dc);
     const coderecord *rec;
     int code, blktype, rep, dist, nlen, header;
     static const unsigned char lenlenmap[] = {
@@ -1217,7 +1234,7 @@ int main(int argc, char **argv)
 {
     unsigned char buf[16], *outbuf;
     int ret, outlen;
-    void *handle;
+    ssh_decompressor *handle;
     int noheader = FALSE, opts = TRUE;
     char *filename = NULL;
     FILE *fp;
@@ -1289,7 +1306,7 @@ int main(int argc, char **argv)
 
 #else
 
-const struct ssh_compress ssh_zlib = {
+const struct ssh_compression_alg ssh_zlib = {
     "zlib",
     "[email protected]", /* delayed version */
     zlib_compress_init,

+ 17 - 15
source/putty/storage.h

@@ -28,12 +28,14 @@
  * 
  * Any returned error message must be freed after use.
  */
-void *open_settings_w(const char *sessionname, char **errmsg);
-void write_setting_s(void *handle, const char *key, const char *value);
-void write_setting_i(void *handle, const char *key, int value);
-void write_setting_filename(void *handle, const char *key, Filename *value);
-void write_setting_fontspec(void *handle, const char *key, FontSpec *font);
-void close_settings_w(void *handle);
+settings_w *open_settings_w(const char *sessionname, char **errmsg);
+void write_setting_s(settings_w *handle, const char *key, const char *value);
+void write_setting_i(settings_w *handle, const char *key, int value);
+void write_setting_filename(settings_w *handle,
+                            const char *key, Filename *value);
+void write_setting_fontspec(settings_w *handle,
+                            const char *key, FontSpec *font);
+void close_settings_w(settings_w *handle);
 
 /*
  * Read a saved session. The caller is expected to call
@@ -51,12 +53,12 @@ void close_settings_w(void *handle);
  * should invent a sensible default. If an integer setting is not
  * present, read_setting_i() returns its provided default.
  */
-void *open_settings_r(const char *sessionname);
-char *read_setting_s(void *handle, const char *key);
-int read_setting_i(void *handle, const char *key, int defvalue);
-Filename *read_setting_filename(void *handle, const char *key);
-FontSpec *read_setting_fontspec(void *handle, const char *key);
-void close_settings_r(void *handle);
+settings_r *open_settings_r(const char *sessionname);
+char *read_setting_s(settings_r *handle, const char *key);
+int read_setting_i(settings_r *handle, const char *key, int defvalue);
+Filename *read_setting_filename(settings_r *handle, const char *key);
+FontSpec *read_setting_fontspec(settings_r *handle, const char *key);
+void close_settings_r(settings_r *handle);
 
 /*
  * Delete a whole saved session.
@@ -66,9 +68,9 @@ void del_settings(const char *sessionname);
 /*
  * Enumerate all saved sessions.
  */
-void *enum_settings_start(void);
-char *enum_settings_next(void *handle, char *buffer, int buflen);
-void enum_settings_finish(void *handle);
+settings_e *enum_settings_start(void);
+char *enum_settings_next(settings_e *handle, char *buffer, int buflen);
+void enum_settings_finish(settings_e *handle);
 
 /* ----------------------------------------------------------------------
  * Functions to access PuTTY's host key database.

+ 46 - 31
source/putty/windows/winstore.c

@@ -89,7 +89,11 @@ static void unmungestr(const char *in, char *out, int outlen)
     return;
 }
 
-void *open_settings_w(const char *sessionname, char **errmsg)
+struct settings_w {
+    HKEY sesskey;
+};
+
+settings_w *open_settings_w(const char *sessionname, char **errmsg)
 {
     HKEY subkey1, sesskey;
     int ret;
@@ -119,29 +123,37 @@ void *open_settings_w(const char *sessionname, char **errmsg)
 	return NULL;
     }
     sfree(p);
-    return (void *) sesskey;
+
+    settings_w *toret = snew(settings_w);
+    toret->sesskey = sesskey;
+    return toret;
 }
 
-void write_setting_s(void *handle, const char *key, const char *value)
+void write_setting_s(settings_w *handle, const char *key, const char *value)
 {
     if (handle)
-	RegSetValueEx((HKEY) handle, key, 0, REG_SZ, (CONST BYTE *)value,
+        RegSetValueEx(handle->sesskey, key, 0, REG_SZ, (CONST BYTE *)value,
 		      1 + strlen(value));
 }
 
-void write_setting_i(void *handle, const char *key, int value)
+void write_setting_i(settings_w *handle, const char *key, int value)
 {
     if (handle)
-	RegSetValueEx((HKEY) handle, key, 0, REG_DWORD,
+        RegSetValueEx(handle->sesskey, key, 0, REG_DWORD,
 		      (CONST BYTE *) &value, sizeof(value));
 }
 
-void close_settings_w(void *handle)
+void close_settings_w(settings_w *handle)
 {
-    RegCloseKey((HKEY) handle);
+    RegCloseKey(handle->sesskey);
+    sfree(handle);
 }
 
-void *open_settings_r(const char *sessionname)
+struct settings_r {
+    HKEY sesskey;
+};
+
+settings_r *open_settings_r(const char *sessionname)
 {
     HKEY subkey1, sesskey;
     char *p;
@@ -163,10 +175,12 @@ void *open_settings_r(const char *sessionname)
 
     sfree(p);
 
-    return (void *) sesskey;
+    settings_r *toret = snew(settings_r);
+    toret->sesskey = sesskey;
+    return toret;
 }
 
-char *read_setting_s(void *handle, const char *key)
+char *read_setting_s(settings_r *handle, const char *key)
 {
     DWORD type, allocsize, size;
     char *ret;
@@ -175,14 +189,14 @@ char *read_setting_s(void *handle, const char *key)
 	return NULL;
 
     /* Find out the type and size of the data. */
-    if (RegQueryValueEx((HKEY) handle, key, 0,
+    if (RegQueryValueEx(handle->sesskey, key, 0,
 			&type, NULL, &size) != ERROR_SUCCESS ||
 	type != REG_SZ)
 	return NULL;
 
     allocsize = size+1;         /* allow for an extra NUL if needed */
     ret = snewn(allocsize, char);
-    if (RegQueryValueEx((HKEY) handle, key, 0,
+    if (RegQueryValueEx(handle->sesskey, key, 0,
 			&type, (BYTE *)ret, &size) != ERROR_SUCCESS ||
 	type != REG_SZ) {
         sfree(ret);
@@ -195,13 +209,13 @@ char *read_setting_s(void *handle, const char *key)
     return ret;
 }
 
-int read_setting_i(void *handle, const char *key, int defvalue)
+int read_setting_i(settings_r *handle, const char *key, int defvalue)
 {
     DWORD type, val, size;
     size = sizeof(val);
 
     if (!handle ||
-	RegQueryValueEx((HKEY) handle, key, 0, &type,
+        RegQueryValueEx(handle->sesskey, key, 0, &type,
 			(BYTE *) &val, &size) != ERROR_SUCCESS ||
 	size != sizeof(val) || type != REG_DWORD)
 	return defvalue;
@@ -209,7 +223,7 @@ int read_setting_i(void *handle, const char *key, int defvalue)
 	return val;
 }
 
-FontSpec *read_setting_fontspec(void *handle, const char *name)
+FontSpec *read_setting_fontspec(settings_r *handle, const char *name)
 {
     char *settingname;
     char *fontname;
@@ -249,7 +263,8 @@ FontSpec *read_setting_fontspec(void *handle, const char *name)
     return ret;
 }
 
-void write_setting_fontspec(void *handle, const char *name, FontSpec *font)
+void write_setting_fontspec(settings_w *handle,
+                            const char *name, FontSpec *font)
 {
     char *settingname;
 
@@ -265,7 +280,7 @@ void write_setting_fontspec(void *handle, const char *name, FontSpec *font)
     sfree(settingname);
 }
 
-Filename *read_setting_filename(void *handle, const char *name)
+Filename *read_setting_filename(settings_r *handle, const char *name)
 {
     char *tmp = read_setting_s(handle, name);
     if (tmp) {
@@ -276,14 +291,16 @@ Filename *read_setting_filename(void *handle, const char *name)
 	return NULL;
 }
 
-void write_setting_filename(void *handle, const char *name, Filename *result)
+void write_setting_filename(settings_w *handle,
+                            const char *name, Filename *result)
 {
     write_setting_s(handle, name, result->path);
 }
 
-void close_settings_r(void *handle)
+void close_settings_r(settings_r *handle)
 {
-    RegCloseKey((HKEY) handle);
+    RegCloseKey(handle->sesskey);
+    sfree(handle);
 }
 
 void del_settings(const char *sessionname)
@@ -304,20 +321,20 @@ void del_settings(const char *sessionname)
     remove_session_from_jumplist(sessionname);
 }
 
-struct enumsettings {
+struct settings_e {
     HKEY key;
     int i;
 };
 
-void *enum_settings_start(void)
+settings_e *enum_settings_start(void)
 {
-    struct enumsettings *ret;
+    settings_e *ret;
     HKEY key;
 
     if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &key) != ERROR_SUCCESS)
 	return NULL;
 
-    ret = snew(struct enumsettings);
+    ret = snew(settings_e);
     if (ret) {
 	ret->key = key;
 	ret->i = 0;
@@ -326,9 +343,8 @@ void *enum_settings_start(void)
     return ret;
 }
 
-char *enum_settings_next(void *handle, char *buffer, int buflen)
+char *enum_settings_next(settings_e *e, char *buffer, int buflen)
 {
-    struct enumsettings *e = (struct enumsettings *) handle;
     char *otherbuf;
     otherbuf = snewn(3 * buflen, char);
     if (RegEnumKey(e->key, e->i++, otherbuf, 3 * buflen) == ERROR_SUCCESS) {
@@ -341,9 +357,8 @@ char *enum_settings_next(void *handle, char *buffer, int buflen)
     }
 }
 
-void enum_settings_finish(void *handle)
+void enum_settings_finish(settings_e *e)
 {
-    struct enumsettings *e = (struct enumsettings *) handle;
     RegCloseKey(e->key);
     sfree(e);
 }
@@ -695,7 +710,7 @@ static int transform_jumplist_registry
     (const char *add, const char *rem, char **out)
 {
     int ret;
-    HKEY pjumplist_key, psettings_tmp;
+    HKEY pjumplist_key;
     DWORD type;
     DWORD value_length;
     char *old_value, *new_value;
@@ -780,7 +795,7 @@ static int transform_jumplist_registry
         while (*piterator_old != '\0') {
             if (!rem || strcmp(piterator_old, rem) != 0) {
                 /* Check if this is a valid session, otherwise don't add. */
-                psettings_tmp = open_settings_r(piterator_old);
+                settings_r *psettings_tmp = open_settings_r(piterator_old);
                 if (psettings_tmp != NULL) {
                     close_settings_r(psettings_tmp);
                     strcpy(piterator_new, piterator_old);

+ 2 - 2
source/putty/x11fwd.c

@@ -39,7 +39,7 @@ typedef struct X11Connection {
     int no_data_sent_to_x_client;
     char *peer_addr;
     int peer_port;
-    struct ssh_channel *c;        /* channel structure held by ssh.c */
+    SshChannel *c;               /* channel structure held by SSH backend */
     Socket s;
 
     const Plug_vtable *plugvt;
@@ -732,7 +732,7 @@ static const struct ChannelVtable X11Connection_channelvt = {
  * Called to set up the X11Connection structure, though this does not
  * yet connect to an actual server.
  */
-Channel *x11_new_channel(tree234 *authtree, struct ssh_channel *c,
+Channel *x11_new_channel(tree234 *authtree, SshChannel *c,
                          const char *peeraddr, int peerport,
                          int connection_sharing_possible)
 {

Неке датотеке нису приказане због велике количине промена