Ver código fonte

PuTTY snapshot 65b65bb (Expose the structure tag 'crcda_ctx' - 2019-09-19)

Source commit: 8320144ae87014ecea25fa6756683ae08f5b57a9
Martin Prikryl 6 anos atrás
pai
commit
aff4559cbd

+ 235 - 0
source/putty/agentf.c

@@ -0,0 +1,235 @@
+/*
+ * SSH agent forwarding.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "putty.h"
+#include "ssh.h"
+#include "pageant.h"
+#include "sshchan.h"
+
+typedef struct agentf {
+    struct ssh_channel *c;
+    bufchain inbuffer;
+    agent_pending_query *pending;
+    int input_wanted;
+    int rcvd_eof;
+
+    Channel chan;
+} agentf;
+
+static void agentf_got_response(agentf *af, void *reply, int replylen)
+{
+    af->pending = NULL;
+
+    if (!reply) {
+        /* The real agent didn't send any kind of reply at all for
+         * some reason, so fake an SSH_AGENT_FAILURE. */
+        reply = "\0\0\0\1\5";
+        replylen = 5;
+    }
+
+    sshfwd_write(af->c, reply, replylen);
+}
+
+static void agentf_callback(void *vctx, void *reply, int replylen);
+
+static void agentf_try_forward(agentf *af)
+{
+    unsigned datalen, length;
+    strbuf *message;
+    unsigned char msglen[4];
+    void *reply;
+    int replylen;
+
+    /*
+     * Don't try to parallelise agent requests. Wait for each one to
+     * return before attempting the next.
+     */
+    if (af->pending)
+        return;
+
+    /*
+     * If the outgoing side of the channel connection is currently
+     * throttled, don't submit any new forwarded requests to the real
+     * agent. This causes the input side of the agent forwarding not
+     * to be emptied, exerting the required back-pressure on the
+     * remote client, and encouraging it to read our responses before
+     * sending too many more requests.
+     */
+    if (!af->input_wanted)
+        return;
+
+    while (1) {
+        /*
+         * Try to extract a complete message from the input buffer.
+         */
+        datalen = bufchain_size(&af->inbuffer);
+        if (datalen < 4)
+            break;         /* not even a length field available yet */
+
+        bufchain_fetch(&af->inbuffer, msglen, 4);
+        length = GET_32BIT(msglen);
+
+        if (length > AGENT_MAX_MSGLEN-4) {
+            /*
+             * If the remote has sent a message that's just _too_
+             * long, we should reject it in advance of seeing the rest
+             * of the incoming message, and also close the connection
+             * for good measure (which avoids us having to faff about
+             * with carefully ignoring just the right number of bytes
+             * from the overlong message).
+             */
+            agentf_got_response(af, NULL, 0);
+            sshfwd_write_eof(af->c);
+            return;
+        }
+
+        if (length > datalen - 4)
+            break;          /* a whole message is not yet available */
+
+        bufchain_consume(&af->inbuffer, 4);
+
+        message = strbuf_new_for_agent_query();
+        bufchain_fetch_consume(
+            &af->inbuffer, strbuf_append(message, length), length);
+        af->pending = agent_query(
+            message, &reply, &replylen, agentf_callback, af);
+        strbuf_free(message);
+
+        if (af->pending)
+            return;   /* agent_query promised to reply in due course */
+
+        /*
+         * If the agent gave us an answer immediately, pass it
+         * straight on and go round this loop again.
+         */
+        agentf_got_response(af, reply, replylen);
+        sfree(reply);
+    }
+
+    /*
+     * If we get here (i.e. we left the above while loop via 'break'
+     * rather than 'return'), that means we've determined that the
+     * input buffer for the agent forwarding connection doesn't
+     * contain a complete request.
+     *
+     * So if there's potentially more data to come, we can return now,
+     * and wait for the remote client to send it. But if the remote
+     * has sent EOF, it would be a mistake to do that, because we'd be
+     * waiting a long time. So this is the moment to check for EOF,
+     * and respond appropriately.
+     */
+    if (af->rcvd_eof)
+        sshfwd_write_eof(af->c);
+}
+
+static void agentf_callback(void *vctx, void *reply, int replylen)
+{
+    agentf *af = (agentf *)vctx;
+
+    agentf_got_response(af, reply, replylen);
+    sfree(reply);
+
+    /*
+     * Now try to extract and send further messages from the channel's
+     * input-side buffer.
+     */
+    agentf_try_forward(af);
+}
+
+static void agentf_free(Channel *chan);
+static int agentf_send(Channel *chan, int is_stderr, const void *, int);
+static void agentf_send_eof(Channel *chan);
+static char *agentf_log_close_msg(Channel *chan);
+static void agentf_set_input_wanted(Channel *chan, int wanted);
+
+static const struct ChannelVtable agentf_channelvt = {
+    agentf_free,
+    chan_remotely_opened_confirmation,
+    chan_remotely_opened_failure,
+    agentf_send,
+    agentf_send_eof,
+    agentf_set_input_wanted,
+    agentf_log_close_msg,
+    chan_no_eager_close,
+};
+
+Channel *agentf_new(struct ssh_channel *c)
+{
+    agentf *af = snew(agentf);
+    af->c = c;
+    af->chan.vt = &agentf_channelvt;
+    af->chan.initial_fixed_window_size = 0;
+    af->rcvd_eof = TRUE;
+    bufchain_init(&af->inbuffer);
+    af->pending = NULL;
+    af->input_wanted = TRUE;
+    return &af->chan;
+}
+
+static void agentf_free(Channel *chan)
+{
+    assert(chan->vt == &agentf_channelvt);
+    agentf *af = FROMFIELD(chan, agentf, chan);
+
+    if (af->pending)
+        agent_cancel_query(af->pending);
+    bufchain_clear(&af->inbuffer);
+    sfree(af);
+}
+
+static int agentf_send(Channel *chan, int is_stderr,
+                       const void *data, int length)
+{
+    assert(chan->vt == &agentf_channelvt);
+    agentf *af = FROMFIELD(chan, agentf, chan);
+    bufchain_add(&af->inbuffer, data, length);
+    agentf_try_forward(af);
+
+    /*
+     * We exert back-pressure on an agent forwarding client if and
+     * only if we're waiting for the response to an asynchronous agent
+     * request. This prevents the client running out of window while
+     * receiving the _first_ message, but means that if any message
+     * takes time to process, the client will be discouraged from
+     * sending an endless stream of further ones after it.
+     */
+    return (af->pending ? bufchain_size(&af->inbuffer) : 0);
+}
+
+static void agentf_send_eof(Channel *chan)
+{
+    assert(chan->vt == &agentf_channelvt);
+    agentf *af = FROMFIELD(chan, agentf, chan);
+
+    af->rcvd_eof = TRUE;
+
+    /* Call try_forward, which will respond to the EOF now if
+     * appropriate, or wait until the queue of outstanding requests is
+     * dealt with if not. */
+    agentf_try_forward(af);
+}
+
+static char *agentf_log_close_msg(Channel *chan)
+{
+    return dupstr("Agent-forwarding connection closed");
+}
+
+static void agentf_set_input_wanted(Channel *chan, int wanted)
+{
+    assert(chan->vt == &agentf_channelvt);
+    agentf *af = FROMFIELD(chan, agentf, chan);
+
+    af->input_wanted = wanted;
+
+    /* Agent forwarding channels are buffer-managed by not asking the
+     * agent questions if the SSH channel isn't accepting input. So if
+     * it's started again, we should ask a question if we have one
+     * pending.. */
+    if (wanted)
+        agentf_try_forward(af);
+}

+ 1 - 1
source/putty/be_misc.c

@@ -9,7 +9,7 @@
 #include "putty.h"
 #include "network.h"
 
-void backend_socket_log(void *frontend, int type, SockAddr addr, int port,
+void backend_socket_log(Frontend *frontend, int type, SockAddr addr, int port,
                         const char *error_msg, int error_code, Conf *conf,
                         int session_started)
 {

+ 4 - 4
source/putty/callback.c

@@ -17,13 +17,13 @@ struct callback {
 struct callback *cbcurr = NULL, *cbhead = NULL, *cbtail = NULL;
 
 toplevel_callback_notify_fn_t notify_frontend = NULL;
-void *frontend = NULL;
+void *notify_ctx = NULL;
 
 void request_callback_notifications(toplevel_callback_notify_fn_t fn,
-                                    void *fr)
+                                    void *ctx)
 {
     notify_frontend = fn;
-    frontend = fr;
+    notify_ctx = ctx;
 }
 
 static void run_idempotent_callback(void *ctx)
@@ -87,7 +87,7 @@ void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
      * callback keeps re-scheduling itself.
      */
     if (notify_frontend && !cbhead && !cbcurr)
-        notify_frontend(frontend);
+        notify_frontend(notify_ctx);
 
     if (cbtail)
         cbtail->next = cb;

+ 18 - 1
source/putty/defs.h

@@ -21,7 +21,6 @@
 #endif
 
 typedef struct conf_tag Conf;
-typedef struct backend_tag Backend;
 typedef struct terminal_tag Terminal;
 
 typedef struct Filename Filename;
@@ -44,6 +43,24 @@ typedef struct SockAddr_tag *SockAddr;
 typedef struct Socket_vtable Socket_vtable;
 typedef struct Plug_vtable Plug_vtable;
 
+typedef struct Backend Backend;
+typedef struct Backend_vtable Backend_vtable;
+
+typedef struct Ldisc_tag Ldisc;
+typedef struct LogContext_tag LogContext;
+
+typedef struct Frontend Frontend;
+
+typedef struct ssh_tag *Ssh;
+
+typedef struct Channel Channel;
+
+typedef struct ssh_sharing_state ssh_sharing_state;
+typedef struct ssh_sharing_connstate ssh_sharing_connstate;
+typedef struct share_channel share_channel;
+
+typedef struct dlgparam dlgparam;
+
 /* 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

+ 17 - 25
source/putty/logging.c

@@ -12,12 +12,12 @@
 #include "putty.h"
 
 /* log session to file stuff ... */
-struct LogContext {
+struct LogContext_tag {
     FILE *lgfp;
     enum { L_CLOSED, L_OPENING, L_OPEN, L_ERROR } state;
     bufchain queue;
     Filename *currlogfilename;
-    void *frontend;
+    Frontend *frontend;
     Conf *conf;
     int logtype;		       /* cached out of conf */
 };
@@ -31,7 +31,7 @@ static Filename *xlatlognam(Filename *s, char *hostname, int port,
  * isn't open, buffering data if it's in the process of being
  * opened asynchronously, etc.
  */
-static void logwrite(struct LogContext *ctx, void *data, int len)
+static void logwrite(LogContext *ctx, void *data, int len)
 {
     /*
      * In state L_CLOSED, we call logfopen, which will set the state
@@ -59,7 +59,7 @@ static void logwrite(struct LogContext *ctx, void *data, int len)
  * Convenience wrapper on logwrite() which printf-formats the
  * string.
  */
-static void logprintf(struct LogContext *ctx, const char *fmt, ...)
+static void logprintf(LogContext *ctx, const char *fmt, ...)
 {
     va_list ap;
     char *data;
@@ -75,16 +75,16 @@ static void logprintf(struct LogContext *ctx, const char *fmt, ...)
 /*
  * Flush any open log file.
  */
-void logflush(void *handle) {
-    struct LogContext *ctx = (struct LogContext *)handle;
+void logflush(LogContext *ctx)
+{
     if (ctx->logtype > 0)
 	if (ctx->state == L_OPEN)
 	    fflush(ctx->lgfp);
 }
 
-static void logfopen_callback(void *handle, int mode)
+static void logfopen_callback(void *vctx, int mode)
 {
-    struct LogContext *ctx = (struct LogContext *)handle;
+    LogContext *ctx = (LogContext *)vctx;
     char buf[256], *event;
     struct tm tm;
     const char *fmode;
@@ -160,9 +160,8 @@ static void logfopen_callback(void *handle, int mode)
  * file and asking the user whether they want to append, overwrite
  * or cancel logging.
  */
-void logfopen(void *handle)
+void logfopen(LogContext *ctx)
 {
-    struct LogContext *ctx = (struct LogContext *)handle;
     struct tm tm;
     int mode;
 
@@ -199,9 +198,8 @@ void logfopen(void *handle)
 	logfopen_callback(ctx, mode);  /* open the file */
 }
 
-void logfclose(void *handle)
+void logfclose(LogContext *ctx)
 {
-    struct LogContext *ctx = (struct LogContext *)handle;
     if (ctx->lgfp) {
 	fclose(ctx->lgfp);
 	ctx->lgfp = NULL;
@@ -212,9 +210,8 @@ void logfclose(void *handle)
 /*
  * Log session traffic.
  */
-void logtraffic(void *handle, unsigned char c, int logmode)
+void logtraffic(LogContext *ctx, unsigned char c, int logmode)
 {
-    struct LogContext *ctx = (struct LogContext *)handle;
     if (ctx->logtype > 0) {
 	if (ctx->logtype == logmode)
 	    logwrite(ctx, &c, 1);
@@ -230,9 +227,8 @@ void logtraffic(void *handle, unsigned char c, int logmode)
  * platforms. Platforms which don't have a meaningful stderr can
  * just avoid defining FLAG_STDERR.
  */
-void log_eventlog(void *handle, const char *event)
+void log_eventlog(LogContext *ctx, const char *event)
 {
-    struct LogContext *ctx = (struct LogContext *)handle;
     if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) {
 	fprintf(stderr, "%s\n", event);
 	fflush(stderr);
@@ -252,13 +248,12 @@ void log_eventlog(void *handle, const char *event)
  * If n_blanks != 0, blank or omit some parts.
  * Set of blanking areas must be in increasing order.
  */
-void log_packet(void *handle, int direction, int type,
+void log_packet(LogContext *ctx, int direction, int type,
 		const char *texttype, const void *data, int len,
 		int n_blanks, const struct logblank_t *blanks,
 		const unsigned long *seq,
                 unsigned downstream_id, const char *additional_log_text)
 {
-    struct LogContext *ctx = (struct LogContext *)handle;
     char dumpdata[80], smalldata[5];
     int p = 0, b = 0, omitted = 0;
     int output_pos = 0; /* NZ if pending output in dumpdata */
@@ -372,9 +367,9 @@ void log_packet(void *handle, int direction, int type,
     logflush(ctx);
 }
 
-void *log_init(void *frontend, Conf *conf)
+LogContext *log_init(Frontend *frontend, Conf *conf)
 {
-    struct LogContext *ctx = snew(struct LogContext);
+    LogContext *ctx = snew(LogContext);
     ctx->lgfp = NULL;
     ctx->state = L_CLOSED;
     ctx->frontend = frontend;
@@ -385,10 +380,8 @@ void *log_init(void *frontend, Conf *conf)
     return ctx;
 }
 
-void log_free(void *handle)
+void log_free(LogContext *ctx)
 {
-    struct LogContext *ctx = (struct LogContext *)handle;
-
     logfclose(ctx);
     bufchain_clear(&ctx->queue);
     if (ctx->currlogfilename)
@@ -397,9 +390,8 @@ void log_free(void *handle)
     sfree(ctx);
 }
 
-void log_reconfig(void *handle, Conf *conf)
+void log_reconfig(LogContext *ctx, Conf *conf)
 {
-    struct LogContext *ctx = (struct LogContext *)handle;
     int reset_logging;
 
     if (!filename_equal(conf_get_filename(ctx->conf, CONF_logfilename),

+ 1 - 1
source/putty/misc.c

@@ -216,7 +216,7 @@ char *host_strduptrim(const char *s)
     return dupstr(s);
 }
 
-prompts_t *new_prompts(void *frontend)
+prompts_t *new_prompts(Frontend *frontend)
 {
     prompts_t *p = snew(prompts_t);
     p->prompts = NULL;

+ 3 - 2
source/putty/network.h

@@ -95,7 +95,8 @@ Socket new_connection(SockAddr addr, const char *hostname,
 Socket new_listener(const char *srcaddr, int port, Plug plug,
                     int local_host_only, Conf *conf, int addressfamily);
 SockAddr name_lookup(const char *host, int port, char **canonicalname,
-		     Conf *conf, int addressfamily, void *frontend_for_logging,
+                     Conf *conf, int addressfamily,
+                     Frontend *frontend_for_logging,
                      const char *lookup_reason_for_logging);
 int proxy_for_destination (SockAddr addr, const char *hostname, int port,
                            Conf *conf);
@@ -221,7 +222,7 @@ extern Plug nullplug;
 /*
  * Exports from be_misc.c.
  */
-void backend_socket_log(void *frontend, int type, SockAddr addr, int port,
+void backend_socket_log(Frontend *frontend, int type, SockAddr addr, int port,
                         const char *error_msg, int error_code, Conf *conf,
                         int session_started);
 void log_proxy_stderr(Plug plug, bufchain *buf, const void *vdata, int len);

+ 95 - 62
source/putty/portfwd.c

@@ -8,6 +8,7 @@
 
 #include "putty.h"
 #include "ssh.h"
+#include "sshchan.h"
 
 /*
  * Enumeration of values that live in the 'socks_state' field of
@@ -21,12 +22,12 @@ typedef enum {
     SOCKS_5_CONNECT      /* expect a SOCKS 5 connection message */
 } SocksState;
 
-struct PortForwarding {
+typedef struct PortForwarding {
     struct ssh_channel *c;        /* channel structure held by ssh.c */
-    void *backhandle;		       /* instance of SSH backend itself */
-    /* Note that backhandle need not be filled in if c is non-NULL */
+    Ssh ssh;                      /* instance of SSH backend itself */
+    /* Note that ssh need not be filled in if c is non-NULL */
     Socket s;
-    int throttled, throttle_override;
+    int input_wanted;
     int ready;
     SocksState socks_state;
     /*
@@ -44,10 +45,11 @@ struct PortForwarding {
     size_t socksbuf_consumed;
 
     const Plug_vtable *plugvt;
-};
+    Channel chan;
+} PortForwarding;
 
 struct PortListener {
-    void *backhandle;		       /* instance of SSH backend itself */
+    Ssh ssh;                      /* instance of SSH backend itself */
     Socket s;
     int is_dynamic;
     /*
@@ -105,6 +107,8 @@ static void pfl_log(Plug plug, int type, SockAddr addr, int port,
     /* we have to dump these since we have no interface to logging.c */
 }
 
+static void pfd_close(struct PortForwarding *pf);
+
 static void pfd_closing(Plug plug, const char *error_msg, int error_code,
 			int calling_back)
 {
@@ -142,10 +146,12 @@ static void pfl_closing(Plug plug, const char *error_msg, int error_code,
     pfl_terminate(pl);
 }
 
-static void wrap_send_port_open(void *channel, const char *hostname, int port,
-                                Socket s)
+static struct ssh_channel *wrap_send_port_open(
+    Ssh ssh, const char *hostname, int port, Socket s, Channel *chan)
 {
     char *peerinfo, *description;
+    struct ssh_channel *toret;
+
     peerinfo = sk_peer_info(s);
     if (peerinfo) {
         description = dupprintf("forwarding from %s", peerinfo);
@@ -153,8 +159,11 @@ static void wrap_send_port_open(void *channel, const char *hostname, int port,
     } else {
         description = dupstr("forwarding");
     }
-    ssh_send_port_open(channel, hostname, port, description);
+
+    toret = ssh_send_port_open(ssh, hostname, port, description, chan);
+
     sfree(description);
+    return toret;
 }
 
 static char *ipv4_to_string(unsigned ipv4)
@@ -396,21 +405,11 @@ static void pfd_receive(Plug plug, int urgent, char *data, int len)
 	 */
 	sk_set_frozen(pf->s, 1);
 
-	pf->c = new_sock_channel(pf->backhandle, pf);
-	if (pf->c == NULL) {
-	    pfd_close(pf);
-	    return;
-	} else {
-	    /* asks to forward to the specified host/port for this */
-	    wrap_send_port_open(pf->c, pf->hostname, pf->port, pf->s);
-	}
-    }
-    if (pf->ready) {
-	if (sshfwd_write(pf->c, data, len) > 0) {
-	    pf->throttled = 1;
-	    sk_set_frozen(pf->s, 1);
-	}
+        pf->c = wrap_send_port_open(pf->ssh, pf->hostname, pf->port, pf->s,
+                                    &pf->chan);
     }
+    if (pf->ready)
+        sshfwd_write(pf->c, data, len);
 }
 
 static void pfd_sent(Plug plug, int bufsize)
@@ -429,6 +428,25 @@ static const Plug_vtable PortForwarding_plugvt = {
     NULL
 };
 
+static void pfd_chan_free(Channel *chan);
+static void pfd_open_confirmation(Channel *chan);
+static void pfd_open_failure(Channel *chan, const char *errtext);
+static int pfd_send(Channel *chan, int is_stderr, const void *data, int len);
+static void pfd_send_eof(Channel *chan);
+static void pfd_set_input_wanted(Channel *chan, int wanted);
+static char *pfd_log_close_msg(Channel *chan);
+
+static const struct ChannelVtable PortForwarding_channelvt = {
+    pfd_chan_free,
+    pfd_open_confirmation,
+    pfd_open_failure,
+    pfd_send,
+    pfd_send_eof,
+    pfd_set_input_wanted,
+    pfd_log_close_msg,
+    chan_no_eager_close,
+};
+
 /*
  * Called when receiving a PORT OPEN from the server to make a
  * connection to a destination host.
@@ -436,8 +454,8 @@ static const Plug_vtable PortForwarding_plugvt = {
  * On success, returns NULL and fills in *pf_ret. On error, returns a
  * dynamically allocated error message string.
  */
-char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port,
-                  void *c, Conf *conf, int addressfamily)
+char *pfd_connect(Channel **chan_ret, char *hostname,int port,
+                  struct ssh_channel *c, Conf *conf, int addressfamily)
 {
     SockAddr addr;
     const char *err;
@@ -459,12 +477,15 @@ char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port,
     /*
      * Open socket.
      */
-    pf = *pf_ret = new_portfwd_state();
+    pf = new_portfwd_state();
+    *chan_ret = &pf->chan;
     pf->plugvt = &PortForwarding_plugvt;
-    pf->throttled = pf->throttle_override = 0;
+    pf->chan.initial_fixed_window_size = 0;
+    pf->chan.vt = &PortForwarding_channelvt;
+    pf->input_wanted = TRUE;
     pf->ready = 1;
     pf->c = c;
-    pf->backhandle = NULL;	       /* we shouldn't need this */
+    pf->ssh = NULL;            /* we shouldn't need this */
     pf->socks_state = SOCKS_NONE;
 
     pf->s = new_connection(addr, dummy_realhost, port,
@@ -474,7 +495,7 @@ char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port,
         char *err_ret = dupstr(err);
         sk_close(pf->s);
 	free_portfwd_state(pf);
-        *pf_ret = NULL;
+        *chan_ret = NULL;
 	return err_ret;
     }
 
@@ -495,9 +516,12 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
     pl = FROMFIELD(p, struct PortListener, plugvt);
     pf = new_portfwd_state();
     pf->plugvt = &PortForwarding_plugvt;
+    pf->chan.initial_fixed_window_size = 0;
+    pf->chan.vt = &PortForwarding_channelvt;
+    pf->input_wanted = TRUE;
 
     pf->c = NULL;
-    pf->backhandle = pl->backhandle;
+    pf->ssh = pl->ssh;
 
     pf->s = s = constructor(ctx, &pf->plugvt);
     if ((err = sk_socket_error(s)) != NULL) {
@@ -505,7 +529,7 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
 	return err != NULL;
     }
 
-    pf->throttled = pf->throttle_override = 0;
+    pf->input_wanted = TRUE;
     pf->ready = 0;
 
     if (pl->is_dynamic) {
@@ -518,15 +542,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 = new_sock_channel(pl->backhandle, pf);
-
-	if (pf->c == NULL) {
-	    free_portfwd_state(pf);
-	    return 1;
-	} else {
-	    /* asks to forward to the specified host/port for this */
-	    wrap_send_port_open(pf->c, pf->hostname, pf->port, s);
-	}
+        pf->c = wrap_send_port_open(pl->ssh, pf->hostname, pf->port,
+                                    s, &pf->chan);
     }
 
     return 0;
@@ -547,7 +564,7 @@ static const Plug_vtable PortListener_plugvt = {
  * dynamically allocated error message string.
  */
 char *pfl_listen(char *desthost, int destport, char *srcaddr,
-                 int port, void *backhandle, Conf *conf,
+                 int port, Ssh ssh, Conf *conf,
                  struct PortListener **pl_ret, int address_family)
 {
     const char *err;
@@ -564,7 +581,7 @@ char *pfl_listen(char *desthost, int destport, char *srcaddr,
 	pl->is_dynamic = FALSE;
     } else
 	pl->is_dynamic = TRUE;
-    pl->backhandle = backhandle;
+    pl->ssh = ssh;
 
     pl->s = new_listener(srcaddr, port, &pl->plugvt,
                          !conf_get_int(conf, CONF_lport_acceptall),
@@ -580,7 +597,12 @@ char *pfl_listen(char *desthost, int destport, char *srcaddr,
     return NULL;
 }
 
-void pfd_close(struct PortForwarding *pf)
+static char *pfd_log_close_msg(Channel *chan)
+{
+    return dupstr("Forwarded port closed");
+}
+
+static void pfd_close(struct PortForwarding *pf)
 {
     if (!pf)
 	return;
@@ -601,43 +623,42 @@ void pfl_terminate(struct PortListener *pl)
     free_portlistener_state(pl);
 }
 
-void pfd_unthrottle(struct PortForwarding *pf)
+static void pfd_set_input_wanted(Channel *chan, int wanted)
 {
-    if (!pf)
-	return;
-
-    pf->throttled = 0;
-    sk_set_frozen(pf->s, pf->throttled || pf->throttle_override);
+    assert(chan->vt == &PortForwarding_channelvt);
+    PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
+    pf->input_wanted = wanted;
+    sk_set_frozen(pf->s, !pf->input_wanted);
 }
 
-void pfd_override_throttle(struct PortForwarding *pf, int enable)
+static void pfd_chan_free(Channel *chan)
 {
-    if (!pf)
-	return;
-
-    pf->throttle_override = enable;
-    sk_set_frozen(pf->s, pf->throttled || pf->throttle_override);
+    assert(chan->vt == &PortForwarding_channelvt);
+    PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
+    pfd_close(pf);
 }
 
 /*
  * Called to send data down the raw connection.
  */
-int pfd_send(struct PortForwarding *pf, const void *data, int len)
+static int pfd_send(Channel *chan, int is_stderr, const void *data, int len)
 {
-    if (pf == NULL)
-	return 0;
+    assert(chan->vt == &PortForwarding_channelvt);
+    PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
     return sk_write(pf->s, data, len);
 }
 
-void pfd_send_eof(struct PortForwarding *pf)
+static void pfd_send_eof(Channel *chan)
 {
+    assert(chan->vt == &PortForwarding_channelvt);
+    PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
     sk_write_eof(pf->s);
 }
 
-void pfd_confirm(struct PortForwarding *pf)
+static void pfd_open_confirmation(Channel *chan)
 {
-    if (pf == NULL)
-	return;
+    assert(chan->vt == &PortForwarding_channelvt);
+    PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
 
     pf->ready = 1;
     sk_set_frozen(pf->s, 0);
@@ -649,3 +670,15 @@ void pfd_confirm(struct PortForwarding *pf)
         pf->socksbuf = NULL;
     }
 }
+
+static void pfd_open_failure(Channel *chan, const char *errtext)
+{
+    assert(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);
+}

+ 1 - 1
source/putty/proxy.c

@@ -368,7 +368,7 @@ static char *dns_log_msg(const char *host, int addressfamily,
 }
 
 SockAddr name_lookup(const char *host, int port, char **canonicalname,
-		     Conf *conf, int addressfamily, void *frontend,
+                     Conf *conf, int addressfamily, Frontend *frontend,
                      const char *reason)
 {
     char *logmsg;

+ 129 - 107
source/putty/putty.h

@@ -441,43 +441,67 @@ enum {
     ADDRTYPE_UNSPEC, ADDRTYPE_IPV4, ADDRTYPE_IPV6, ADDRTYPE_NAME
 };
 
-struct backend_tag {
-    const char *(*init) (void *frontend_handle, void **backend_handle,
+struct Backend {
+    const Backend_vtable *vt;
+};
+struct Backend_vtable {
+    const char *(*init) (Frontend *frontend, Backend **backend_out,
 			 Conf *conf, const char *host, int port,
                          char **realhost, int nodelay, int keepalive);
-    void (*free) (void *handle);
-    /* back->reconfig() passes in a replacement configuration. */
-    void (*reconfig) (void *handle, Conf *conf);
-    /* back->send() returns the current amount of buffered data. */
-    int (*send) (void *handle, const char *buf, int len);
-    /* back->sendbuffer() does the same thing but without attempting a send */
-    int (*sendbuffer) (void *handle);
-    void (*size) (void *handle, int width, int height);
-    void (*special) (void *handle, Telnet_Special code);
-    const struct telnet_special *(*get_specials) (void *handle);
-    int (*connected) (void *handle);
-    int (*exitcode) (void *handle);
-    /* If back->sendok() returns FALSE, data sent to it from the frontend
-     * may be lost. */
-    int (*sendok) (void *handle);
-    int (*ldisc) (void *handle, int);
-    void (*provide_ldisc) (void *handle, void *ldisc);
-    void (*provide_logctx) (void *handle, void *logctx);
-    /*
-     * back->unthrottle() tells the back end that the front end
-     * buffer is clearing.
-     */
-    void (*unthrottle) (void *handle, int);
-    int (*cfg_info) (void *handle);
+
+    void (*free) (Backend *be);
+    /* Pass in a replacement configuration. */
+    void (*reconfig) (Backend *be, Conf *conf);
+    /* send() returns the current amount of buffered data. */
+    int (*send) (Backend *be, const char *buf, int len);
+    /* sendbuffer() does the same thing but without attempting a send */
+    int (*sendbuffer) (Backend *be);
+    void (*size) (Backend *be, int width, int height);
+    void (*special) (Backend *be, Telnet_Special code);
+    const struct telnet_special *(*get_specials) (Backend *be);
+    int (*connected) (Backend *be);
+    int (*exitcode) (Backend *be);
+    /* If back->sendok() returns FALSE, the backend doesn't currently
+     * want input data, so the frontend should avoid acquiring any if
+     * possible (passing back-pressure on to its sender). */
+    int (*sendok) (Backend *be);
+    int (*ldisc_option_state) (Backend *be, int);
+    void (*provide_ldisc) (Backend *be, Ldisc *ldisc);
+    void (*provide_logctx) (Backend *be, LogContext *logctx);
+    /* Tells the back end that the front end  buffer is clearing. */
+    void (*unthrottle) (Backend *be, int bufsize);
+    int (*cfg_info) (Backend *be);
+
     /* Only implemented in the SSH protocol: check whether a
      * connection-sharing upstream exists for a given configuration. */
     int (*test_for_upstream)(const char *host, int port, Conf *conf);
+
     const char *name;
     int protocol;
     int default_port;
 };
 
-extern Backend *backends[];
+#define backend_init(vt, fe, out, conf, host, port, rhost, nd, ka) \
+    ((vt)->init(fe, out, conf, host, port, rhost, nd, ka))
+#define backend_free(be) ((be)->vt->free(be))
+#define backend_reconfig(be, conf) ((be)->vt->reconfig(be, conf))
+#define backend_send(be, buf, len) ((be)->vt->send(be, buf, len))
+#define backend_sendbuffer(be) ((be)->vt->sendbuffer(be))
+#define backend_size(be, w, h) ((be)->vt->size(be, w, h))
+#define backend_special(be, code) ((be)->vt->special(be, code))
+#define backend_get_specials(be) ((be)->vt->get_specials(be))
+#define backend_connected(be) ((be)->vt->connected(be))
+#define backend_exitcode(be) ((be)->vt->exitcode(be))
+#define backend_sendok(be) ((be)->vt->sendok(be))
+#define backend_ldisc_option_state(be, opt) \
+    ((be)->vt->ldisc_option_state(be, opt))
+#define backend_provide_ldisc(be, ldisc) ((be)->vt->provide_ldisc(be, ldisc))
+#define backend_provide_logctx(be, logctx) \
+    ((be)->vt->provide_logctx(be, logctx))
+#define backend_unthrottle(be, bufsize) ((be)->vt->unthrottle(be, bufsize))
+#define backend_cfg_info(be) ((be)->vt->cfg_info(be))
+
+extern const struct Backend_vtable *const backends[];
 
 /*
  * Suggested default protocol provided by the backend link module.
@@ -584,11 +608,11 @@ typedef struct {
     size_t n_prompts;   /* May be zero (in which case display the foregoing,
                          * if any, and return success) */
     prompt_t **prompts;
-    void *frontend;
+    Frontend *frontend;
     void *data;		/* slot for housekeeping data, managed by
 			 * get_userpass_input(); initially NULL */
 } prompts_t;
-prompts_t *new_prompts(void *frontend);
+prompts_t *new_prompts(Frontend *frontend);
 void add_prompt(prompts_t *p, char *promptstr, int echo);
 void prompt_set_result(prompt_t *pr, const char *newstr);
 void prompt_ensure_result_size(prompt_t *pr, int len);
@@ -649,7 +673,7 @@ enum { ALL_CLIPBOARDS(CLIP_ID) N_CLIPBOARDS };
 /*
  * Exports from the front end.
  */
-void request_resize(void *frontend, int, int);
+void request_resize(Frontend *frontend, int, int);
 void do_text(Context, int, int, wchar_t *, int, unsigned long, int,
              truecolour);
 void do_cursor(Context, int, int, wchar_t *, int, unsigned long, int,
@@ -658,46 +682,46 @@ int char_width(Context ctx, int uc);
 #ifdef OPTIMISE_SCROLL
 void do_scroll(Context, int, int, int);
 #endif
-void set_title(void *frontend, char *);
-void set_icon(void *frontend, char *);
-void set_sbar(void *frontend, int, int, int);
-Context get_ctx(void *frontend);
+void set_title(Frontend *frontend, char *);
+void set_icon(Frontend *frontend, char *);
+void set_sbar(Frontend *frontend, int, int, int);
+Context get_ctx(Frontend *frontend);
 void free_ctx(Context);
-void palette_set(void *frontend, int, int, int, int);
-void palette_reset(void *frontend);
-int palette_get(void *frontend, int n, int *r, int *g, int *b);
-void write_clip(void *frontend, int clipboard, wchar_t *, int *,
+void palette_set(Frontend *frontend, int, int, int, int);
+void palette_reset(Frontend *frontend);
+int palette_get(Frontend *frontend, int n, int *r, int *g, int *b);
+void write_clip(Frontend *frontend, int clipboard, wchar_t *, int *,
                 truecolour *, int, int);
-void optimised_move(void *frontend, int, int, int);
-void set_raw_mouse_mode(void *frontend, int);
-void connection_fatal(void *frontend, const char *, ...);
+void optimised_move(Frontend *frontend, int, int, int);
+void set_raw_mouse_mode(Frontend *frontend, int);
+void connection_fatal(Frontend *frontend, const char *, ...);
 void nonfatal(const char *, ...);
 void modalfatalbox(const char *, ...);
 #ifdef macintosh
 #pragma noreturn(modalfatalbox)
 #endif
-void do_beep(void *frontend, int);
-void begin_session(void *frontend);
-void sys_cursor(void *frontend, int x, int y);
-void frontend_request_paste(void *frontend, int clipboard);
-void frontend_keypress(void *frontend);
-void frontend_echoedit_update(void *frontend, int echo, int edit);
+void do_beep(Frontend *frontend, int);
+void begin_session(Frontend *frontend);
+void sys_cursor(Frontend *frontend, int x, int y);
+void frontend_request_paste(Frontend *frontend, int clipboard);
+void frontend_keypress(Frontend *frontend);
+void frontend_echoedit_update(Frontend *frontend, int echo, int edit);
 /* It's the backend's responsibility to invoke this at the start of a
  * connection, if necessary; it can also invoke it later if the set of
  * special commands changes. It does not need to invoke it at session
  * shutdown. */
-void update_specials_menu(void *frontend);
-int from_backend(void *frontend, int is_stderr, const void *data, int len);
-int from_backend_untrusted(void *frontend, const void *data, int len);
+void update_specials_menu(Frontend *frontend);
+int from_backend(Frontend *frontend, int is_stderr, const void *data, int len);
+int from_backend_untrusted(Frontend *frontend, const void *data, int len);
 /* Called when the back end wants to indicate that EOF has arrived on
  * the server-to-client stream. Returns FALSE to indicate that we
  * intend to keep the session open in the other direction, or TRUE to
  * indicate that if they're closing so are we. */
-int from_backend_eof(void *frontend);
-void notify_remote_exit(void *frontend);
+int from_backend_eof(Frontend *frontend);
+void notify_remote_exit(Frontend *frontend);
 /* Get a sensible value for a tty mode. NULL return = don't set.
  * Otherwise, returned value should be freed by caller. */
-char *get_ttymode(void *frontend, const char *mode);
+char *get_ttymode(Frontend *frontend, const char *mode);
 /*
  * >0 = `got all results, carry on'
  * 0  = `user cancelled' (FIXME distinguish "give up entirely" and "next auth"?)
@@ -706,15 +730,15 @@ char *get_ttymode(void *frontend, const char *mode);
 int get_userpass_input(prompts_t *p, bufchain *input);
 #define OPTIMISE_IS_SCROLL 1
 
-void set_iconic(void *frontend, int iconic);
-void move_window(void *frontend, int x, int y);
-void set_zorder(void *frontend, int top);
-void refresh_window(void *frontend);
-void set_zoomed(void *frontend, int zoomed);
-int is_iconic(void *frontend);
-void get_window_pos(void *frontend, int *x, int *y);
-void get_window_pixels(void *frontend, int *x, int *y);
-char *get_window_title(void *frontend, int icon);
+void set_iconic(Frontend *frontend, int iconic);
+void move_window(Frontend *frontend, int x, int y);
+void set_zorder(Frontend *frontend, int top);
+void refresh_window(Frontend *frontend);
+void set_zoomed(Frontend *frontend, int zoomed);
+int is_iconic(Frontend *frontend);
+void get_window_pos(Frontend *frontend, int *x, int *y);
+void get_window_pixels(Frontend *frontend, int *x, int *y);
+char *get_window_title(Frontend *frontend, int icon);
 /* Hint from backend to frontend about time-consuming operations.
  * Initial state is assumed to be BUSY_NOT. */
 enum {
@@ -724,8 +748,8 @@ enum {
 		       stuff is suspended */
     BUSY_CPU	    /* Locally busy (e.g. crypto); user interaction suspended */
 };
-void set_busy_status(void *frontend, int status);
-int frontend_is_utf8(void *frontend);
+void set_busy_status(Frontend *frontend, int status);
+int frontend_is_utf8(Frontend *frontend);
 
 void cleanup_exit(int);
 
@@ -1046,8 +1070,8 @@ void random_destroy_seed(void);
 /*
  * Exports from settings.c.
  */
-Backend *backend_from_name(const char *name);
-Backend *backend_from_proto(int proto);
+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);
@@ -1081,7 +1105,7 @@ FontSpec *platform_default_fontspec(const char *name);
  * Exports from terminal.c.
  */
 
-Terminal *term_init(Conf *, struct unicode_data *, void *);
+Terminal *term_init(Conf *, struct unicode_data *, Frontend *);
 void term_free(Terminal *);
 void term_size(Terminal *, int, int, int);
 void term_paint(Terminal *, Context, int, int, int, int, int);
@@ -1107,10 +1131,8 @@ void term_request_paste(Terminal *, int clipboard);
 void term_seen_key_event(Terminal *); 
 int term_data(Terminal *, int is_stderr, const void *data, int len);
 int term_data_untrusted(Terminal *, const void *data, int len);
-void term_provide_resize_fn(Terminal *term,
-			    void (*resize_fn)(void *, int, int),
-			    void *resize_ctx);
-void term_provide_logctx(Terminal *term, void *logctx);
+void term_provide_backend(Terminal *term, Backend *backend);
+void term_provide_logctx(Terminal *term, LogContext *logctx);
 void term_set_focus(Terminal *term, int has_focus);
 char *term_get_ttymode(Terminal *term, const char *mode);
 int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input);
@@ -1120,14 +1142,14 @@ int format_arrow_key(char *buf, Terminal *term, int xkey, int ctrl);
 /*
  * Exports from logging.c.
  */
-void *log_init(void *frontend, Conf *conf);
-void log_free(void *logctx);
-void log_reconfig(void *logctx, Conf *conf);
-void logfopen(void *logctx);
-void logfclose(void *logctx);
-void logtraffic(void *logctx, unsigned char c, int logmode);
-void logflush(void *logctx);
-void log_eventlog(void *logctx, const char *string);
+LogContext *log_init(Frontend *frontend, Conf *conf);
+void log_free(LogContext *logctx);
+void log_reconfig(LogContext *logctx, Conf *conf);
+void logfopen(LogContext *logctx);
+void logfclose(LogContext *logctx);
+void logtraffic(LogContext *logctx, unsigned char c, int logmode);
+void logflush(LogContext *logctx);
+void log_eventlog(LogContext *logctx, const char *string);
 enum { PKT_INCOMING, PKT_OUTGOING };
 enum { PKTLOG_EMIT, PKTLOG_BLANK, PKTLOG_OMIT };
 struct logblank_t {
@@ -1135,7 +1157,7 @@ struct logblank_t {
     int len;
     int type;
 };
-void log_packet(void *logctx, int direction, int type,
+void log_packet(LogContext *logctx, int direction, int type,
 		const char *texttype, const void *data, int len,
 		int n_blanks, const struct logblank_t *blanks,
 		const unsigned long *sequence,
@@ -1145,47 +1167,47 @@ void log_packet(void *logctx, int direction, int type,
  * Exports from testback.c
  */
 
-extern Backend null_backend;
-extern Backend loop_backend;
+extern const struct Backend_vtable null_backend;
+extern const struct Backend_vtable loop_backend;
 
 /*
  * Exports from raw.c.
  */
 
-extern Backend raw_backend;
+extern const struct Backend_vtable raw_backend;
 
 /*
  * Exports from rlogin.c.
  */
 
-extern Backend rlogin_backend;
+extern const struct Backend_vtable rlogin_backend;
 
 /*
  * Exports from telnet.c.
  */
 
-extern Backend telnet_backend;
+extern const struct Backend_vtable telnet_backend;
 
 /*
  * Exports from ssh.c.
  */
-extern Backend ssh_backend;
+extern const struct Backend_vtable ssh_backend;
 
 /*
  * Exports from ldisc.c.
  */
-void *ldisc_create(Conf *, Terminal *, Backend *, void *, void *);
-void ldisc_configure(void *, Conf *);
-void ldisc_free(void *);
-void ldisc_send(void *handle, const void *buf, int len, int interactive);
-void ldisc_echoedit_update(void *handle);
+Ldisc *ldisc_create(Conf *, Terminal *, Backend *, Frontend *);
+void ldisc_configure(Ldisc *, Conf *);
+void ldisc_free(Ldisc *);
+void ldisc_send(Ldisc *, const void *buf, int len, int interactive);
+void ldisc_echoedit_update(Ldisc *);
 
 /*
  * Exports from ldiscucs.c.
  */
-void lpage_send(void *, int codepage, const char *buf, int len,
+void lpage_send(Ldisc *, int codepage, const char *buf, int len,
                 int interactive);
-void luni_send(void *, const wchar_t * widebuf, int len, int interactive);
+void luni_send(Ldisc *, const wchar_t * widebuf, int len, int interactive);
 
 /*
  * Exports from sshrand.c.
@@ -1205,7 +1227,7 @@ void random_unref(void);
  * Exports from pinger.c.
  */
 typedef struct pinger_tag *Pinger;
-Pinger pinger_new(Conf *conf, Backend *back, void *backhandle);
+Pinger pinger_new(Conf *conf, Backend *backend);
 void pinger_reconfig(Pinger, Conf *oldconf, Conf *newconf);
 void pinger_free(Pinger);
 
@@ -1302,7 +1324,7 @@ int wc_unescape(char *output, const char *wildcard);
 /*
  * Exports from frontend (windlg.c etc)
  */
-void logevent(void *frontend, const char *);
+void logevent(Frontend *frontend, const char *);
 void pgp_fingerprints(void);
 /*
  * verify_ssh_host_key() can return one of three values:
@@ -1316,7 +1338,7 @@ void pgp_fingerprints(void);
  *    back via the provided function with a result that's either 0
  *    or +1'.
  */
-int verify_ssh_host_key(void *frontend, char *host, int port,
+int verify_ssh_host_key(Frontend *frontend, char *host, int port,
                         const char *keytype, char *keystr, char *fingerprint,
                         void (*callback)(void *ctx, int result), void *ctx);
 /*
@@ -1332,9 +1354,9 @@ int have_ssh_host_key(const char *host, int port, const char *keytype);
  * warning threshold because that's all we have cached, but at least
  * one acceptable algorithm is available that we don't have cached.)
  */
-int askalg(void *frontend, const char *algtype, const char *algname,
+int askalg(Frontend *frontend, const char *algtype, const char *algname,
 	   void (*callback)(void *ctx, int result), void *ctx);
-int askhk(void *frontend, const char *algname, const char *betteralgs,
+int askhk(Frontend *frontend, const char *algname, const char *betteralgs,
           void (*callback)(void *ctx, int result), void *ctx);
 /*
  * askappend can return four values:
@@ -1344,7 +1366,7 @@ int askhk(void *frontend, const char *algname, const char *betteralgs,
  *  - 0 means cancel logging for this session
  *  - -1 means please wait.
  */
-int askappend(void *frontend, Filename *filename,
+int askappend(Frontend *frontend, Filename *filename,
 	      void (*callback)(void *ctx, int result), void *ctx);
 
 /*
@@ -1353,7 +1375,7 @@ int askappend(void *frontend, Filename *filename,
  */
 extern int console_batch_mode;
 int console_get_userpass_input(prompts_t *p);
-void console_provide_logctx(void *logctx);
+void console_provide_logctx(LogContext *logctx);
 int is_interactive(void);
 
 /*
@@ -1399,16 +1421,16 @@ void cmdline_error(const char *, ...);
  */
 struct controlbox;
 union control;
-void conf_radiobutton_handler(union control *ctrl, void *dlg,
+void conf_radiobutton_handler(union control *ctrl, dlgparam *dlg,
 			      void *data, int event);
 #define CHECKBOX_INVERT (1<<30)
-void conf_checkbox_handler(union control *ctrl, void *dlg,
+void conf_checkbox_handler(union control *ctrl, dlgparam *dlg,
 			   void *data, int event);
-void conf_editbox_handler(union control *ctrl, void *dlg,
+void conf_editbox_handler(union control *ctrl, dlgparam *dlg,
 			  void *data, int event);
-void conf_filesel_handler(union control *ctrl, void *dlg,
+void conf_filesel_handler(union control *ctrl, dlgparam *dlg,
 			  void *data, int event);
-void conf_fontsel_handler(union control *ctrl, void *dlg,
+void conf_fontsel_handler(union control *ctrl, dlgparam *dlg,
 			  void *data, int event);
 void setup_config_box(struct controlbox *b, int midsession,
 		      int protocol, int protcfginfo);
@@ -1609,9 +1631,9 @@ struct IdempotentCallback {
 };
 void queue_idempotent_callback(struct IdempotentCallback *ic);
 
-typedef void (*toplevel_callback_notify_fn_t)(void *frontend);
+typedef void (*toplevel_callback_notify_fn_t)(void *ctx);
 void request_callback_notifications(toplevel_callback_notify_fn_t notify,
-                                    void *frontend);
+                                    void *ctx);
 
 /*
  * Define no-op macros for the jump list functions, on platforms that

Diferenças do arquivo suprimidas por serem muito extensas
+ 218 - 438
source/putty/ssh.c


+ 37 - 47
source/putty/ssh.h

@@ -8,19 +8,19 @@
 #include "misc.h"
 
 struct ssh_channel;
-typedef struct ssh_tag *Ssh;
 
 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,
-                                 void *share_cs, void *share_chan,
+                                 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);
-void sshfwd_x11_is_local(struct ssh_channel *c);
 
 /*
  * Buffer management constants. There are several of these for
@@ -149,26 +149,28 @@ void ssh_free_pktout(PktOut *pkt);
 
 extern Socket ssh_connection_sharing_init(
     const char *host, int port, Conf *conf, Ssh ssh, Plug sshplug,
-    void **state);
+    ssh_sharing_state **state);
 int ssh_share_test_for_upstream(const char *host, int port, Conf *conf);
-void share_got_pkt_from_server(void *ctx, int type,
+void share_got_pkt_from_server(ssh_sharing_connstate *ctx, int type,
                                const void *pkt, int pktlen);
-void share_activate(void *state, const char *server_verstring);
-void sharestate_free(void *state);
-int share_ndownstreams(void *state);
+void share_activate(ssh_sharing_state *sharestate,
+                    const char *server_verstring);
+void sharestate_free(ssh_sharing_state *state);
+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, void *sharing_ctx);
+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,
-                               void *share_ctx);
+                               ssh_sharing_connstate *connstate);
 void ssh_remove_sharing_rportfwd(Ssh ssh, const char *shost, int sport,
-                                 void *share_ctx);
-void ssh_sharing_queue_global_request(Ssh ssh, void *share_ctx);
-struct X11FakeAuth *ssh_sharing_add_x11_display(Ssh ssh, int authtype,
-                                                void *share_cs,
-                                                void *share_chan);
+                                 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,
@@ -178,7 +180,7 @@ void ssh_sharing_downstream_connected(Ssh ssh, unsigned id,
 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(void *csv, void *chanv,
+void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan,
                              unsigned upstream_id, unsigned server_id,
                              unsigned server_currwin, unsigned server_maxpkt,
                              unsigned client_adjusted_window,
@@ -186,12 +188,7 @@ void share_setup_x11_channel(void *csv, void *chanv,
                              int protomajor, int protominor,
                              const void *initial_data, int initial_len);
 
-/*
- * Useful thing.
- */
-#ifndef lenof
-#define lenof(x) ( (sizeof((x))) / (sizeof(*(x))))
-#endif
+Frontend *ssh_get_frontend(Ssh ssh);
 
 #define SSH_CIPHER_IDEA		1
 #define SSH_CIPHER_DES		2
@@ -325,9 +322,10 @@ unsigned long crc32_compute(const void *s, size_t len);
 unsigned long crc32_update(unsigned long crc_input, const void *s, size_t len);
 
 /* SSH CRC compensation attack detector */
-void *crcda_make_context(void);
-void crcda_free_context(void *handle);
-int detect_attack(void *handle, unsigned char *buf, uint32 len,
+struct crcda_ctx;
+struct crcda_ctx *crcda_make_context(void);
+void crcda_free_context(struct crcda_ctx *ctx);
+int detect_attack(struct crcda_ctx *ctx, unsigned char *buf, uint32 len,
 		  unsigned char *IV);
 
 /*
@@ -630,7 +628,7 @@ extern const char sshver[];
  * that fails. This variable is the means by which scp.c can reach
  * into the SSH code and find out which one it got.
  */
-extern int ssh_fallback_cmd(void *handle);
+extern int ssh_fallback_cmd(Backend *backend);
 
 void SHATransform(word32 * digest, word32 * data);
 
@@ -661,28 +659,21 @@ int random_byte(void);
 void random_add_noise(void *noise, int length);
 void random_add_heavynoise(void *noise, int length);
 
-void logevent(void *, const char *);
+void logevent(Frontend *, const char *);
 
 struct PortForwarding;
 
 /* Allocate and register a new channel for port forwarding */
-void *new_sock_channel(void *handle, struct PortForwarding *pf);
-void ssh_send_port_open(void *channel, const char *hostname, int port,
-                        const char *org);
+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(struct PortForwarding **pf, char *hostname, int port,
-                         void *c, Conf *conf, int addressfamily);
-extern void pfd_close(struct PortForwarding *);
-extern int pfd_send(struct PortForwarding *, const void *data, int len);
-extern void pfd_send_eof(struct PortForwarding *);
-extern void pfd_confirm(struct PortForwarding *);
-extern void pfd_unthrottle(struct PortForwarding *);
-extern void pfd_override_throttle(struct PortForwarding *, int enable);
+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, void *backhandle, Conf *conf,
+                        int port, Ssh ssh, Conf *conf,
                         struct PortListener **pl, int address_family);
 extern void pfl_terminate(struct PortListener *);
 
@@ -733,7 +724,8 @@ struct X11FakeAuth {
      * What to do with an X connection matching this auth data.
      */
     struct X11Display *disp;
-    void *share_cs, *share_chan;
+    ssh_sharing_connstate *share_cs;
+    share_channel *share_chan;
 };
 void *x11_make_greeting(int endian, int protomajor, int protominor,
                         int auth_proto, const void *auth_data, int auth_len,
@@ -751,13 +743,9 @@ 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);
-struct X11Connection;                  /* opaque outside x11fwd.c */
-struct X11Connection *x11_init(tree234 *authtree, void *, const char *, int);
-extern void x11_close(struct X11Connection *);
-extern int x11_send(struct X11Connection *, const void *, int);
-extern void x11_send_eof(struct X11Connection *s);
-extern void x11_unthrottle(struct X11Connection *s);
-extern void x11_override_throttle(struct X11Connection *s, int enable);
+Channel *x11_new_channel(tree234 *authtree, struct ssh_channel *c,
+                         const char *peeraddr, int peerport,
+                         int connection_sharing_possible);
 char *x11_display(const char *display);
 /* Platform-dependent X11 functions */
 extern void platform_get_x11_auth(struct X11Display *display, Conf *);
@@ -787,6 +775,8 @@ 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);
+
 Bignum copybn(Bignum b);
 Bignum bn_power_2(int n);
 void bn_restore_invariant(Bignum b);

+ 1 - 1
source/putty/ssh1bpp.c

@@ -20,7 +20,7 @@ struct ssh1_bpp_state {
     const struct ssh_cipher *cipher;
     void *cipher_ctx;
 
-    void *crcda_ctx;
+    struct crcda_ctx *crcda_ctx;
 
     void *compctx, *decompctx;
 

+ 1 - 1
source/putty/sshbpp.h

@@ -19,7 +19,7 @@ struct BinaryPacketProtocol {
     bufchain *in_raw, *out_raw;
     PacketQueue *in_pq;
     PacketLogSettings *pls;
-    void *logctx;
+    LogContext *logctx;
 
     int seen_disconnect;
     char *error;

+ 59 - 0
source/putty/sshchan.h

@@ -0,0 +1,59 @@
+/*
+ * Abstraction of the various ways to handle the local end of an SSH
+ * connection-layer channel.
+ */
+
+#ifndef PUTTY_SSHCHAN_H
+#define PUTTY_SSHCHAN_H
+
+struct ChannelVtable {
+    void (*free)(Channel *);
+
+    /* Called for channel types that were created at the same time as
+     * we sent an outgoing CHANNEL_OPEN, when the confirmation comes
+     * back from the server indicating that the channel has been
+     * opened, or the failure message indicating that it hasn't,
+     * respectively. In the latter case, this must _not_ free the
+     * Channel structure - the client will call the free method
+     * separately. But it might do logging or other local cleanup. */
+    void (*open_confirmation)(Channel *);
+    void (*open_failed)(Channel *, const char *error_text);
+
+    int (*send)(Channel *, int is_stderr, const void *buf, int len);
+    void (*send_eof)(Channel *);
+    void (*set_input_wanted)(Channel *, int wanted);
+
+    char *(*log_close_msg)(Channel *);
+
+    int (*want_close)(Channel *, int sent_local_eof, int rcvd_remote_eof);
+};
+
+struct Channel {
+    const struct ChannelVtable *vt;
+    unsigned initial_fixed_window_size;
+};
+
+#define chan_free(ch) ((ch)->vt->free(ch))
+#define chan_open_confirmation(ch) ((ch)->vt->open_confirmation(ch))
+#define chan_open_failed(ch, err) ((ch)->vt->open_failed(ch, err))
+#define chan_send(ch, err, buf, len) ((ch)->vt->send(ch, err, buf, len))
+#define chan_send_eof(ch) ((ch)->vt->send_eof(ch))
+#define chan_set_input_wanted(ch, wanted) \
+    ((ch)->vt->set_input_wanted(ch, wanted))
+#define chan_log_close_msg(ch) ((ch)->vt->send_eof(ch))
+#define chan_want_close(ch, leof, reof) ((ch)->vt->want_close(ch, leof, reof))
+
+/*
+ * Reusable methods you can put in vtables to give default handling of
+ * some of those functions.
+ */
+
+/* open_confirmation / open_failed for any channel it doesn't apply to */
+void chan_remotely_opened_confirmation(Channel *chan);
+void chan_remotely_opened_failure(Channel *chan, const char *errtext);
+
+/* want_close for any channel that wants the default behaviour of not
+ * closing until both directions have had an EOF */
+int chan_no_eager_close(Channel *, int, int);
+
+#endif /* PUTTY_SSHCHAN_H */

+ 3 - 5
source/putty/sshcrcda.c

@@ -55,7 +55,7 @@ struct crcda_ctx {
     uint32 n;
 };
 
-void *crcda_make_context(void)
+struct crcda_ctx *crcda_make_context(void)
 {
     struct crcda_ctx *ret = snew(struct crcda_ctx);
     ret->h = NULL;
@@ -63,9 +63,8 @@ void *crcda_make_context(void)
     return ret;
 }
 
-void crcda_free_context(void *handle)
+void crcda_free_context(struct crcda_ctx *ctx)
 {
-    struct crcda_ctx *ctx = (struct crcda_ctx *)handle;
     if (ctx) {
 	sfree(ctx->h);
 	ctx->h = NULL;
@@ -102,9 +101,8 @@ static int check_crc(uchar *S, uchar *buf, uint32 len, uchar *IV)
 }
 
 /* Detect a crc32 compensation attack on a packet */
-int detect_attack(void *handle, uchar *buf, uint32 len, uchar *IV)
+int detect_attack(struct crcda_ctx *ctx, uchar *buf, uint32 len, uchar *IV)
 {
-    struct crcda_ctx *ctx = (struct crcda_ctx *)handle;
     register uint32 i, j;
     uint32 l;
     register uchar *c;

+ 13 - 19
source/putty/sshshare.c

@@ -507,9 +507,8 @@ static void share_connstate_free(struct ssh_sharing_connstate *cs)
     sfree(cs);
 }
 
-void sharestate_free(void *v)
+void sharestate_free(ssh_sharing_state *sharestate)
 {
-    struct ssh_sharing_state *sharestate = (struct ssh_sharing_state *)v;
     struct ssh_sharing_connstate *cs;
 
     platform_ssh_share_cleanup(sharestate->sockname);
@@ -1061,7 +1060,7 @@ void share_xchannel_failure(struct ssh_sharing_connstate *cs,
     share_dead_xchannel_respond(cs, xc);
 }
 
-void share_setup_x11_channel(void *csv, void *chanv,
+void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan,
                              unsigned upstream_id, unsigned server_id,
                              unsigned server_currwin, unsigned server_maxpkt,
                              unsigned client_adjusted_window,
@@ -1069,8 +1068,6 @@ void share_setup_x11_channel(void *csv, void *chanv,
                              int protomajor, int protominor,
                              const void *initial_data, int initial_len)
 {
-    struct ssh_sharing_connstate *cs = (struct ssh_sharing_connstate *)csv;
-    struct share_channel *chan = (struct share_channel *)chanv;
     struct share_xchannel *xc;
     void *greeting;
     int greeting_len;
@@ -1128,11 +1125,10 @@ void share_setup_x11_channel(void *csv, void *chanv,
     }
 }
 
-void share_got_pkt_from_server(void *csv, int type,
+void share_got_pkt_from_server(ssh_sharing_connstate *cs, int type,
                                const void *vpkt, int pktlen)
 {
     const unsigned char *pkt = (const unsigned char *)vpkt;
-    struct ssh_sharing_connstate *cs = (struct ssh_sharing_connstate *)csv;
     struct share_globreq *globreq;
     size_t id_pos;
     unsigned upstream_id, server_id;
@@ -1718,8 +1714,8 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
 
 static void share_receive(Plug plug, int urgent, char *data, int len)
 {
-    struct ssh_sharing_connstate *cs = FROMFIELD(
-        plug, struct ssh_sharing_connstate, plugvt);
+    ssh_sharing_connstate *cs = FROMFIELD(
+        plug, ssh_sharing_connstate, plugvt);
     static const char expected_verstring_prefix[] =
         "[email protected]";
     unsigned char c;
@@ -1795,8 +1791,8 @@ static void share_receive(Plug plug, int urgent, char *data, int len)
 
 static void share_sent(Plug plug, int bufsize)
 {
-    /* struct ssh_sharing_connstate *cs = FROMFIELD(
-        plug, struct ssh_sharing_connstate, plugvt); */
+    /* ssh_sharing_connstate *cs = FROMFIELD(
+        plug, ssh_sharing_connstate, plugvt); */
 
     /*
      * We do nothing here, because we expect that there won't be a
@@ -1811,8 +1807,7 @@ static void share_sent(Plug plug, int bufsize)
 static void share_listen_closing(Plug plug, const char *error_msg,
 				 int error_code, int calling_back)
 {
-    struct ssh_sharing_state *sharestate = FROMFIELD(
-        plug, struct ssh_sharing_state, plugvt);
+    ssh_sharing_state *sharestate = FROMFIELD(plug, ssh_sharing_state, plugvt);
     if (error_msg)
         ssh_sharing_logf(sharestate->ssh, 0,
                          "listening socket: %s", error_msg);
@@ -1820,7 +1815,7 @@ static void share_listen_closing(Plug plug, const char *error_msg,
     sharestate->listensock = NULL;
 }
 
-static void share_send_verstring(struct ssh_sharing_connstate *cs)
+static void share_send_verstring(ssh_sharing_connstate *cs)
 {
     char *fullstring = dupcat("[email protected]",
                               cs->parent->server_verstring, "\015\012", NULL);
@@ -1830,19 +1825,18 @@ static void share_send_verstring(struct ssh_sharing_connstate *cs)
     cs->sent_verstring = TRUE;
 }
 
-int share_ndownstreams(void *state)
+int share_ndownstreams(ssh_sharing_state *sharestate)
 {
-    struct ssh_sharing_state *sharestate = (struct ssh_sharing_state *)state;
     return count234(sharestate->connections);
 }
 
-void share_activate(void *state, const char *server_verstring)
+void share_activate(ssh_sharing_state *sharestate,
+                    const char *server_verstring)
 {
     /*
      * Indication from ssh.c that we are now ready to begin serving
      * any downstreams that have already connected to us.
      */
-    struct ssh_sharing_state *sharestate = (struct ssh_sharing_state *)state;
     struct ssh_sharing_connstate *cs;
     int i;
 
@@ -2028,7 +2022,7 @@ static const Plug_vtable ssh_sharing_listen_plugvt = {
  */
 Socket ssh_connection_sharing_init(const char *host, int port,
                                    Conf *conf, Ssh ssh, Plug sshplug,
-                                   void **state)
+                                   ssh_sharing_state **state)
 {
     int result, can_upstream, can_downstream;
     char *logtext, *ds_err, *us_err;

+ 6 - 6
source/putty/windows/winstuff.h

@@ -240,14 +240,14 @@ void quit_help(HWND hwnd);
  * windlg.c. Likewise the saved-sessions list.
  */
 GLOBAL Terminal *term;
-GLOBAL void *logctx;
+GLOBAL LogContext *logctx;
 
 /*
  * Windows-specific clipboard helper function shared with windlg.c,
  * which takes the data string in the system code page instead of
  * Unicode.
  */
-void write_aclip(void *frontend, int clipboard, char *, int, int);
+void write_aclip(Frontend *frontend, int clipboard, char *, int, int);
 
 #define WM_NETEVENT  (WM_APP + 5)
 
@@ -437,9 +437,9 @@ void fwdsetter(struct ctlpos *cp, int listid, char *stext, int sid,
 	       char *btext, int bid,
 	       char *r1text, int r1id, char *r2text, int r2id);
 
-void dlg_auto_set_fixed_pitch_flag(void *dlg);
-int dlg_get_fixed_pitch_flag(void *dlg);
-void dlg_set_fixed_pitch_flag(void *dlg, int flag);
+void dlg_auto_set_fixed_pitch_flag(dlgparam *dlg);
+int dlg_get_fixed_pitch_flag(dlgparam *dlg);
+void dlg_set_fixed_pitch_flag(dlgparam *dlg, int flag);
 
 #define MAX_SHORTCUTS_PER_CTRL 16
 
@@ -596,7 +596,7 @@ void agent_schedule_callback(void (*callback)(void *, void *, int),
 /*
  * Exports from winser.c.
  */
-extern Backend serial_backend;
+extern const struct Backend_vtable serial_backend;
 
 /*
  * Exports from winjump.c.

+ 58 - 38
source/putty/x11fwd.c

@@ -9,6 +9,7 @@
 
 #include "putty.h"
 #include "ssh.h"
+#include "sshchan.h"
 #include "tree234.h"
 
 #define GET_16BIT(endian, cp) \
@@ -26,7 +27,7 @@ struct XDMSeen {
     unsigned char clientid[6];
 };
 
-struct X11Connection {
+typedef struct X11Connection {
     unsigned char firstpkt[12];	       /* first X data packet */
     tree234 *authtree;
     struct X11Display *disp;
@@ -34,7 +35,7 @@ struct X11Connection {
     unsigned char *auth_data;
     int data_read, auth_plen, auth_psize, auth_dlen, auth_dsize;
     int verified;
-    int throttled, throttle_override;
+    int input_wanted;
     int no_data_sent_to_x_client;
     char *peer_addr;
     int peer_port;
@@ -42,7 +43,8 @@ struct X11Connection {
     Socket s;
 
     const Plug_vtable *plugvt;
-};
+    Channel chan;
+} X11Connection;
 
 static int xdmseen_cmp(void *a, void *b)
 {
@@ -126,7 +128,8 @@ struct X11FakeAuth *x11_invent_fake_auth(tree234 *authtree, int authtype)
 		auth->data[i]);
 
     auth->disp = NULL;
-    auth->share_cs = auth->share_chan = NULL;
+    auth->share_cs = NULL;
+    auth->share_chan = NULL;
 
     return auth;
 }
@@ -666,11 +669,8 @@ static void x11_receive(Plug plug, int urgent, char *data, int len)
     struct X11Connection *xconn = FROMFIELD(
         plug, struct X11Connection, plugvt);
 
-    if (sshfwd_write(xconn->c, data, len) > 0) {
-	xconn->throttled = 1;
-        xconn->no_data_sent_to_x_client = FALSE;
-	sk_set_frozen(xconn->s, 1);
-    }
+    xconn->no_data_sent_to_x_client = FALSE;
+    sshfwd_write(xconn->c, data, len);
 }
 
 static void x11_sent(Plug plug, int bufsize)
@@ -707,12 +707,30 @@ static const Plug_vtable X11Connection_plugvt = {
     NULL
 };
 
+static void x11_chan_free(Channel *chan);
+static int x11_send(Channel *chan, int is_stderr, const void *vdata, int len);
+static void x11_send_eof(Channel *chan);
+static void x11_set_input_wanted(Channel *chan, int wanted);
+static char *x11_log_close_msg(Channel *chan);
+
+static const struct ChannelVtable X11Connection_channelvt = {
+    x11_chan_free,
+    chan_remotely_opened_confirmation,
+    chan_remotely_opened_failure,
+    x11_send,
+    x11_send_eof,
+    x11_set_input_wanted,
+    x11_log_close_msg,
+    chan_no_eager_close,
+};
+
 /*
  * Called to set up the X11Connection structure, though this does not
  * yet connect to an actual server.
  */
-struct X11Connection *x11_init(tree234 *authtree, void *c,
-                               const char *peeraddr, int peerport)
+Channel *x11_new_channel(tree234 *authtree, struct ssh_channel *c,
+                         const char *peeraddr, int peerport,
+                         int connection_sharing_possible)
 {
     struct X11Connection *xconn;
 
@@ -721,11 +739,14 @@ struct X11Connection *x11_init(tree234 *authtree, void *c,
      */
     xconn = snew(struct X11Connection);
     xconn->plugvt = &X11Connection_plugvt;
+    xconn->chan.vt = &X11Connection_channelvt;
+    xconn->chan.initial_fixed_window_size =
+        (connection_sharing_possible ? 128 : 0);
     xconn->auth_protocol = NULL;
     xconn->authtree = authtree;
     xconn->verified = 0;
     xconn->data_read = 0;
-    xconn->throttled = xconn->throttle_override = 0;
+    xconn->input_wanted = TRUE;
     xconn->no_data_sent_to_x_client = TRUE;
     xconn->c = c;
 
@@ -746,13 +767,13 @@ struct X11Connection *x11_init(tree234 *authtree, void *c,
     xconn->peer_addr = peeraddr ? dupstr(peeraddr) : NULL;
     xconn->peer_port = peerport;
 
-    return xconn;
+    return &xconn->chan;
 }
 
-void x11_close(struct X11Connection *xconn)
+static void x11_chan_free(Channel *chan)
 {
-    if (!xconn)
-	return;
+    assert(chan->vt == &X11Connection_channelvt);
+    X11Connection *xconn = FROMFIELD(chan, X11Connection, chan);
 
     if (xconn->auth_protocol) {
 	sfree(xconn->auth_protocol);
@@ -766,24 +787,14 @@ void x11_close(struct X11Connection *xconn)
     sfree(xconn);
 }
 
-void x11_unthrottle(struct X11Connection *xconn)
+static void x11_set_input_wanted(Channel *chan, int wanted)
 {
-    if (!xconn)
-	return;
+    assert(chan->vt == &X11Connection_channelvt);
+    X11Connection *xconn = FROMFIELD(chan, X11Connection, chan);
 
-    xconn->throttled = 0;
+    xconn->input_wanted = wanted;
     if (xconn->s)
-        sk_set_frozen(xconn->s, xconn->throttled || xconn->throttle_override);
-}
-
-void x11_override_throttle(struct X11Connection *xconn, int enable)
-{
-    if (!xconn)
-	return;
-
-    xconn->throttle_override = enable;
-    if (xconn->s)
-        sk_set_frozen(xconn->s, xconn->throttled || xconn->throttle_override);
+        sk_set_frozen(xconn->s, !xconn->input_wanted);
 }
 
 static void x11_send_init_error(struct X11Connection *xconn,
@@ -831,13 +842,12 @@ static int x11_parse_ip(const char *addr_string, unsigned long *ip)
 /*
  * Called to send data down the raw connection.
  */
-int x11_send(struct X11Connection *xconn, const void *vdata, int len)
+static int x11_send(Channel *chan, int is_stderr, const void *vdata, int len)
 {
+    assert(chan->vt == &X11Connection_channelvt);
+    X11Connection *xconn = FROMFIELD(chan, X11Connection, chan);
     const char *data = (const char *)vdata;
 
-    if (!xconn)
-	return 0;
-
     /*
      * Read the first packet.
      */
@@ -914,7 +924,8 @@ int x11_send(struct X11Connection *xconn, const void *vdata, int len)
         /*
          * If this auth points to a connection-sharing downstream
          * rather than an X display we know how to connect to
-         * directly, pass it off to the sharing module now.
+         * directly, pass it off to the sharing module now. (This will
+         * have the side effect of freeing xconn.)
          */
         if (auth_matched->share_cs) {
             sshfwd_x11_sharing_handover(xconn->c, auth_matched->share_cs,
@@ -929,7 +940,8 @@ int x11_send(struct X11Connection *xconn, const void *vdata, int len)
          * Now we know we're going to accept the connection, and what
          * X display to connect to. Actually connect to it.
          */
-        sshfwd_x11_is_local(xconn->c);
+        xconn->chan.initial_fixed_window_size = 0;
+        sshfwd_window_override_removed(xconn->c);
         xconn->disp = auth_matched->disp;
         xconn->s = new_connection(sk_addr_dup(xconn->disp->addr),
                                   xconn->disp->realhost, xconn->disp->port, 
@@ -984,8 +996,11 @@ int x11_send(struct X11Connection *xconn, const void *vdata, int len)
     return sk_write(xconn->s, data, len);
 }
 
-void x11_send_eof(struct X11Connection *xconn)
+static void x11_send_eof(Channel *chan)
 {
+    assert(chan->vt == &X11Connection_channelvt);
+    X11Connection *xconn = FROMFIELD(chan, X11Connection, chan);
+
     if (xconn->s) {
         sk_write_eof(xconn->s);
     } else {
@@ -1000,6 +1015,11 @@ void x11_send_eof(struct X11Connection *xconn)
     }
 }
 
+static char *x11_log_close_msg(Channel *chan)
+{
+    return dupstr("Forwarded X11 connection terminated");
+}
+
 /*
  * Utility functions used by connection sharing to convert textual
  * representations of an X11 auth protocol name + hex cookie into our

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff