]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Refactor ssh.c's APIs to x11fwd.c and portfwd.c.
authorSimon Tatham <anakin@pobox.com>
Sun, 17 Nov 2013 14:04:41 +0000 (14:04 +0000)
committerSimon Tatham <anakin@pobox.com>
Sun, 17 Nov 2013 14:04:41 +0000 (14:04 +0000)
The most important change is that, where previously ssh.c held the
Socket pointer for each X11 and port forwarding, and the support
modules would find their internal state structure by calling
sk_get_private_ptr on that Socket, it's now the other way round. ssh.c
now directly holds the internal state structure pointer for each
forwarding, and when the support module needs the Socket it looks it
up in a field of that. This will come in handy when I decouple socket
creation from logical forwarding setup, so that X forwardings can
delay actually opening a connection to an X server until they look at
the authentication data and see which server it has to be.

However, while I'm here, I've also taken the opportunity to clean up a
few other points, notably error message handling, and also the fact
that the same kind of state structure was used for both
connection-type and listening-type port forwardings. Now there are
separate PortForwarding and PortListener structure types, which seems
far more sensible.

[originally from svn r10074]

portfwd.c
ssh.c
ssh.h
x11fwd.c

index b14458b931e0ac0f639993f5f9ee18189eee4cd6..e3e63e39aafbb3355e0c3c5fbc465bbede9e823f 100644 (file)
--- a/portfwd.c
+++ b/portfwd.c
 #define TRUE 1
 #endif
 
-struct PFwdPrivate {
+struct PortForwarding {
     const struct plug_function_table *fn;
     /* the above variable absolutely *must* be the first in this structure */
-    void *c;                          /* (channel) data used by ssh.c */
+    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 */
     Socket s;
@@ -27,8 +27,8 @@ struct PFwdPrivate {
     /*
      * `dynamic' does double duty. It's set to 0 for an ordinary
      * forwarded port, and nonzero for SOCKS-style dynamic port
-     * forwarding; but it also represents the state of the SOCKS
-     * exchange.
+     * forwarding; but the nonzero values are also a state machine
+     * tracking where the SOCKS exchange has got to.
      */
     int dynamic;
     /*
@@ -52,24 +52,57 @@ struct PFwdPrivate {
     int buflen;
 };
 
-static struct PFwdPrivate *new_portfwd_private(void)
+struct PortListener {
+    const struct plug_function_table *fn;
+    /* the above variable absolutely *must* be the first in this structure */
+    void *backhandle;                 /* instance of SSH backend itself */
+    Socket s;
+    /*
+     * `dynamic' is set to 0 for an ordinary forwarded port, and
+     * nonzero for SOCKS-style dynamic port forwarding.
+     */
+    int dynamic;
+    /*
+     * `hostname' and `port' are the real hostname and port, for
+     * ordinary forwardings.
+     */
+    char *hostname;
+    int port;
+};
+
+static struct PortForwarding *new_portfwd_state(void)
 {
-    struct PFwdPrivate *pr = snew(struct PFwdPrivate);
-    pr->hostname = NULL;
-    pr->socksbuf = NULL;
-    pr->sockslen = pr->sockssize = 0;
-    pr->buffer = NULL;
-    return pr;
+    struct PortForwarding *pf = snew(struct PortForwarding);
+    pf->hostname = NULL;
+    pf->socksbuf = NULL;
+    pf->sockslen = pf->sockssize = 0;
+    pf->buffer = NULL;
+    return pf;
 }
 
-static void free_portfwd_private(struct PFwdPrivate *pr)
+static void free_portfwd_state(struct PortForwarding *pf)
 {
-    if (!pr)
+    if (!pf)
         return;
-    sfree(pr->hostname);
-    sfree(pr->socksbuf);
-    sfree(pr->buffer);
-    sfree(pr);
+    sfree(pf->hostname);
+    sfree(pf->socksbuf);
+    sfree(pf->buffer);
+    sfree(pf);
+}
+
+static struct PortListener *new_portlistener_state(void)
+{
+    struct PortListener *pl = snew(struct PortListener);
+    pl->hostname = NULL;
+    return pl;
+}
+
+static void free_portlistener_state(struct PortListener *pl)
+{
+    if (!pl)
+        return;
+    sfree(pl->hostname);
+    sfree(pl);
 }
 
 static void pfd_log(Plug plug, int type, SockAddr addr, int port,
@@ -78,17 +111,23 @@ static void pfd_log(Plug plug, int type, SockAddr addr, int port,
     /* we have to dump these since we have no interface to logging.c */
 }
 
+static void pfl_log(Plug plug, int type, SockAddr addr, int port,
+                   const char *error_msg, int error_code)
+{
+    /* we have to dump these since we have no interface to logging.c */
+}
+
 static int pfd_closing(Plug plug, const char *error_msg, int error_code,
                       int calling_back)
 {
-    struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;
+    struct PortForwarding *pf = (struct PortForwarding *) plug;
 
     if (error_msg) {
         /*
          * Socket error. Slam the connection instantly shut.
          */
-        if (pr->c) {
-            sshfwd_unclean_close(pr->c, error_msg);
+        if (pf->c) {
+            sshfwd_unclean_close(pf->c, error_msg);
         } else {
             /*
              * We might not have an SSH channel, if a socket error
@@ -96,64 +135,72 @@ static int pfd_closing(Plug plug, const char *error_msg, int error_code,
              * clean ourself up without sshfwd_unclean_close's call
              * back to pfd_close.
              */
-            pfd_close(pr->s);
+            pfd_close(pf);
         }
     } else {
         /*
          * Ordinary EOF received on socket. Send an EOF on the SSH
          * channel.
          */
-        if (pr->c)
-            sshfwd_write_eof(pr->c);
+        if (pf->c)
+            sshfwd_write_eof(pf->c);
     }
 
     return 1;
 }
 
+static int pfl_closing(Plug plug, const char *error_msg, int error_code,
+                      int calling_back)
+{
+    struct PortListener *pl = (struct PortListener *) plug;
+    pfl_terminate(pl);
+    return 1;
+}
+
 static int pfd_receive(Plug plug, int urgent, char *data, int len)
 {
-    struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;
-    if (pr->dynamic) {
+    struct PortForwarding *pf = (struct PortForwarding *) plug;
+    if (pf->dynamic) {
        while (len--) {
-           if (pr->sockslen >= pr->sockssize) {
-                pr->sockssize = pr->sockslen * 5 / 4 + 256;
-                pr->socksbuf = sresize(pr->socksbuf, pr->sockssize, char);
+           if (pf->sockslen >= pf->sockssize) {
+                pf->sockssize = pf->sockslen * 5 / 4 + 256;
+                pf->socksbuf = sresize(pf->socksbuf, pf->sockssize, char);
            }
-           pr->socksbuf[pr->sockslen++] = *data++;
+           pf->socksbuf[pf->sockslen++] = *data++;
 
            /*
             * Now check what's in the buffer to see if it's a
             * valid and complete message in the SOCKS exchange.
             */
-           if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 4) &&
-               pr->socksbuf[0] == 4) {
+           if ((pf->dynamic == 1 || (pf->dynamic >> 12) == 4) &&
+               pf->socksbuf[0] == 4) {
                /*
                 * SOCKS 4.
                 */
-               if (pr->dynamic == 1)
-                   pr->dynamic = 0x4000;
-               if (pr->sockslen < 2)
+               if (pf->dynamic == 1)
+                   pf->dynamic = 0x4000;
+               if (pf->sockslen < 2)
                     continue;        /* don't have command code yet */
-               if (pr->socksbuf[1] != 1) {
+               if (pf->socksbuf[1] != 1) {
                    /* Not CONNECT. */
                    /* Send back a SOCKS 4 error before closing. */
                    char data[8];
                    memset(data, 0, sizeof(data));
                    data[1] = 91;      /* generic `request rejected' */
-                   sk_write(pr->s, data, 8);
-                   pfd_close(pr->s);
+                   sk_write(pf->s, data, 8);
+                   pfd_close(pf);
                    return 1;
                }
-               if (pr->sockslen <= 8)
+               if (pf->sockslen <= 8)
                     continue;      /* haven't started user/hostname */
-               if (pr->socksbuf[pr->sockslen-1] != 0)
+               if (pf->socksbuf[pf->sockslen-1] != 0)
                    continue;          /* haven't _finished_ user/hostname */
                /*
                 * Now we have a full SOCKS 4 request. Check it to
                 * see if it's a SOCKS 4A request.
                 */
-               if (pr->socksbuf[4] == 0 && pr->socksbuf[5] == 0 &&
-                   pr->socksbuf[6] == 0 && pr->socksbuf[7] != 0) {
+               if (pf->socksbuf[4] == 0 && pf->socksbuf[5] == 0 &&
+                   pf->socksbuf[6] == 0 && pf->socksbuf[7] != 0) {
                    /*
                     * It's SOCKS 4A. So if we haven't yet
                     * collected the host name, we should continue
@@ -161,19 +208,19 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len)
                     * have, we can go ahead.
                     */
                    int len;
-                   if (pr->dynamic == 0x4000) {
-                       pr->dynamic = 0x4001;
-                       pr->sockslen = 8; /* reset buffer to overwrite name */
+                   if (pf->dynamic == 0x4000) {
+                       pf->dynamic = 0x4001;
+                       pf->sockslen = 8; /* reset buffer to overwrite name */
                        continue;
                    }
-                   pr->socksbuf[0] = 0;   /* reply version code */
-                   pr->socksbuf[1] = 90;   /* request granted */
-                   sk_write(pr->s, pr->socksbuf, 8);
-                   len = pr->sockslen - 8;
-                   pr->port = GET_16BIT_MSB_FIRST(pr->socksbuf+2);
-                    pr->hostname = snewn(len+1, char);
-                    pr->hostname[len] = '\0';
-                   memcpy(pr->hostname, pr->socksbuf + 8, len);
+                   pf->socksbuf[0] = 0;   /* reply version code */
+                   pf->socksbuf[1] = 90;   /* request granted */
+                   sk_write(pf->s, pf->socksbuf, 8);
+                   len = pf->sockslen - 8;
+                   pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+2);
+                    pf->hostname = snewn(len+1, char);
+                    pf->hostname[len] = '\0';
+                   memcpy(pf->hostname, pf->socksbuf + 8, len);
                    goto connect;
                } else {
                    /*
@@ -181,52 +228,52 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len)
                     * the IP address into the hostname string and
                     * then just go.
                     */
-                   pr->socksbuf[0] = 0;   /* reply version code */
-                   pr->socksbuf[1] = 90;   /* request granted */
-                   sk_write(pr->s, pr->socksbuf, 8);
-                   pr->port = GET_16BIT_MSB_FIRST(pr->socksbuf+2);
-                   pr->hostname = dupprintf("%d.%d.%d.%d",
-                                             (unsigned char)pr->socksbuf[4],
-                                             (unsigned char)pr->socksbuf[5],
-                                             (unsigned char)pr->socksbuf[6],
-                                             (unsigned char)pr->socksbuf[7]);
+                   pf->socksbuf[0] = 0;   /* reply version code */
+                   pf->socksbuf[1] = 90;   /* request granted */
+                   sk_write(pf->s, pf->socksbuf, 8);
+                   pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+2);
+                   pf->hostname = dupprintf("%d.%d.%d.%d",
+                                             (unsigned char)pf->socksbuf[4],
+                                             (unsigned char)pf->socksbuf[5],
+                                             (unsigned char)pf->socksbuf[6],
+                                             (unsigned char)pf->socksbuf[7]);
                    goto connect;
                }
            }
 
-           if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 5) &&
-               pr->socksbuf[0] == 5) {
+           if ((pf->dynamic == 1 || (pf->dynamic >> 12) == 5) &&
+               pf->socksbuf[0] == 5) {
                /*
                 * SOCKS 5.
                 */
-               if (pr->dynamic == 1)
-                   pr->dynamic = 0x5000;
+               if (pf->dynamic == 1)
+                   pf->dynamic = 0x5000;
 
-               if (pr->dynamic == 0x5000) {
+               if (pf->dynamic == 0x5000) {
                    int i, method;
                    char data[2];
                    /*
                     * We're receiving a set of method identifiers.
                     */
-                   if (pr->sockslen < 2)
+                   if (pf->sockslen < 2)
                         continue;      /* no method count yet */
-                   if (pr->sockslen < 2 + (unsigned char)pr->socksbuf[1])
+                   if (pf->sockslen < 2 + (unsigned char)pf->socksbuf[1])
                        continue;      /* no methods yet */
                    method = 0xFF;     /* invalid */
-                   for (i = 0; i < (unsigned char)pr->socksbuf[1]; i++)
-                       if (pr->socksbuf[2+i] == 0) {
+                   for (i = 0; i < (unsigned char)pf->socksbuf[1]; i++)
+                       if (pf->socksbuf[2+i] == 0) {
                            method = 0;/* no auth */
                            break;
                        }
                    data[0] = 5;
                    data[1] = method;
-                   sk_write(pr->s, data, 2);
-                   pr->dynamic = 0x5001;
-                   pr->sockslen = 0;      /* re-empty the buffer */
+                   sk_write(pf->s, data, 2);
+                   pf->dynamic = 0x5001;
+                   pf->sockslen = 0;      /* re-empty the buffer */
                    continue;
                }
 
-               if (pr->dynamic == 0x5001) {
+               if (pf->dynamic == 0x5001) {
                    /*
                     * We're receiving a SOCKS request.
                     */
@@ -244,50 +291,50 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len)
                    reply[0] = 5; /* VER */
                    reply[3] = 1; /* ATYP = 1 (IPv4, 0.0.0.0:0) */
 
-                   if (pr->sockslen < 6) continue;
-                   atype = (unsigned char)pr->socksbuf[3];
+                   if (pf->sockslen < 6) continue;
+                   atype = (unsigned char)pf->socksbuf[3];
                    if (atype == 1)    /* IPv4 address */
                        alen = 4;
                    if (atype == 4)    /* IPv6 address */
                        alen = 16;
                    if (atype == 3)    /* domain name has leading length */
-                       alen = 1 + (unsigned char)pr->socksbuf[4];
-                   if (pr->sockslen < 6 + alen) continue;
-                   if (pr->socksbuf[1] != 1 || pr->socksbuf[2] != 0) {
+                       alen = 1 + (unsigned char)pf->socksbuf[4];
+                   if (pf->sockslen < 6 + alen) continue;
+                   if (pf->socksbuf[1] != 1 || pf->socksbuf[2] != 0) {
                        /* Not CONNECT or reserved field nonzero - error */
                        reply[1] = 1;   /* generic failure */
-                       sk_write(pr->s, (char *) reply, lenof(reply));
-                       pfd_close(pr->s);
+                       sk_write(pf->s, (char *) reply, lenof(reply));
+                       pfd_close(pf);
                        return 1;
                    }
                    /*
                     * Now we have a viable connect request. Switch
                     * on atype.
                     */
-                   pr->port = GET_16BIT_MSB_FIRST(pr->socksbuf+4+alen);
+                   pf->port = GET_16BIT_MSB_FIRST(pf->socksbuf+4+alen);
                    if (atype == 1) {
                        /* REP=0 (success) already */
-                       sk_write(pr->s, (char *) reply, lenof(reply));
-                       pr->hostname = dupprintf("%d.%d.%d.%d",
-                                                 (unsigned char)pr->socksbuf[4],
-                                                 (unsigned char)pr->socksbuf[5],
-                                                 (unsigned char)pr->socksbuf[6],
-                                                 (unsigned char)pr->socksbuf[7]);
+                       sk_write(pf->s, (char *) reply, lenof(reply));
+                       pf->hostname = dupprintf("%d.%d.%d.%d",
+                                                 (unsigned char)pf->socksbuf[4],
+                                                 (unsigned char)pf->socksbuf[5],
+                                                 (unsigned char)pf->socksbuf[6],
+                                                 (unsigned char)pf->socksbuf[7]);
                        goto connect;
                    } else if (atype == 3) {
                        /* REP=0 (success) already */
-                       sk_write(pr->s, (char *) reply, lenof(reply));
-                        pr->hostname = snewn(alen, char);
-                       pr->hostname[alen-1] = '\0';
-                       memcpy(pr->hostname, pr->socksbuf + 5, alen-1);
+                       sk_write(pf->s, (char *) reply, lenof(reply));
+                        pf->hostname = snewn(alen, char);
+                       pf->hostname[alen-1] = '\0';
+                       memcpy(pf->hostname, pf->socksbuf + 5, alen-1);
                        goto connect;
                    } else {
                        /*
                         * Unknown address type. (FIXME: support IPv6!)
                         */
                        reply[1] = 8;   /* atype not supported */
-                       sk_write(pr->s, (char *) reply, lenof(reply));
-                       pfd_close(pr->s);
+                       sk_write(pf->s, (char *) reply, lenof(reply));
+                       pfd_close(pf);
                        return 1;
                    }
                }
@@ -299,7 +346,7 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len)
             * sensible interpretation of what's in our buffer. So
             * close the connection rudely.
             */
-           pfd_close(pr->s);
+           pfd_close(pf);
            return 1;
        }
        return 1;
@@ -309,39 +356,39 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len)
         * connection.
         */
        connect:
-        sfree(pr->socksbuf);
-        pr->socksbuf = NULL;
+        sfree(pf->socksbuf);
+        pf->socksbuf = NULL;
 
        /*
         * Freeze the socket until the SSH server confirms the
         * connection.
         */
-       sk_set_frozen(pr->s, 1);
+       sk_set_frozen(pf->s, 1);
 
-       pr->c = new_sock_channel(pr->backhandle, pr->s);
-       if (pr->c == NULL) {
-           pfd_close(pr->s);
+       pf->c = new_sock_channel(pf->backhandle, pf);
+       if (pf->c == NULL) {
+           pfd_close(pf);
            return 1;
        } else {
            /* asks to forward to the specified host/port for this */
-           ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding");
+           ssh_send_port_open(pf->c, pf->hostname, pf->port, "forwarding");
        }
-       pr->dynamic = 0;
+       pf->dynamic = 0;
 
        /*
         * If there's any data remaining in our current buffer,
         * save it to be sent on pfd_confirm().
         */
        if (len > 0) {
-           pr->buffer = snewn(len, char);
-           memcpy(pr->buffer, data, len);
-           pr->buflen = len;
+           pf->buffer = snewn(len, char);
+           memcpy(pf->buffer, data, len);
+           pf->buflen = len;
        }
     }
-    if (pr->ready) {
-       if (sshfwd_write(pr->c, data, len) > 0) {
-           pr->throttled = 1;
-           sk_set_frozen(pr->s, 1);
+    if (pf->ready) {
+       if (sshfwd_write(pf->c, data, len) > 0) {
+           pf->throttled = 1;
+           sk_set_frozen(pf->s, 1);
        }
     }
     return 1;
@@ -349,17 +396,21 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len)
 
 static void pfd_sent(Plug plug, int bufsize)
 {
-    struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;
+    struct PortForwarding *pf = (struct PortForwarding *) plug;
 
-    if (pr->c)
-       sshfwd_unthrottle(pr->c, bufsize);
+    if (pf->c)
+       sshfwd_unthrottle(pf->c, bufsize);
 }
 
 /*
- * Called when receiving a PORT OPEN from the server
+ * 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.
  */
-const char *pfd_newconnect(Socket *s, char *hostname, int port,
-                          void *c, Conf *conf, int addressfamily)
+char *pfd_connect(struct PortForwarding **pf_ret, char *hostname,int port,
+                  void *c, Conf *conf, int addressfamily)
 {
     static const struct plug_function_table fn_table = {
        pfd_log,
@@ -372,38 +423,41 @@ const char *pfd_newconnect(Socket *s, char *hostname, int port,
     SockAddr addr;
     const char *err;
     char *dummy_realhost;
-    struct PFwdPrivate *pr;
+    struct PortForwarding *pf;
 
     /*
      * Try to find host.
      */
     addr = name_lookup(hostname, port, &dummy_realhost, conf, addressfamily);
     if ((err = sk_addr_error(addr)) != NULL) {
+        char *err_ret = dupstr(err);
        sk_addr_free(addr);
         sfree(dummy_realhost);
-       return err;
+       return err_ret;
     }
 
     /*
      * Open socket.
      */
-    pr = new_portfwd_private();
-    pr->fn = &fn_table;
-    pr->throttled = pr->throttle_override = 0;
-    pr->ready = 1;
-    pr->c = c;
-    pr->backhandle = NULL;            /* we shouldn't need this */
-    pr->dynamic = 0;
-
-    pr->s = *s = new_connection(addr, dummy_realhost, port,
-                               0, 1, 0, 0, (Plug) pr, conf);
+    pf = *pf_ret = new_portfwd_state();
+    pf->fn = &fn_table;
+    pf->throttled = pf->throttle_override = 0;
+    pf->ready = 1;
+    pf->c = c;
+    pf->backhandle = NULL;            /* we shouldn't need this */
+    pf->dynamic = 0;
+
+    pf->s = new_connection(addr, dummy_realhost, port,
+                           0, 1, 0, 0, (Plug) pf, conf);
     sfree(dummy_realhost);
-    if ((err = sk_socket_error(*s)) != NULL) {
-       free_portfwd_private(pr);
-       return err;
+    if ((err = sk_socket_error(pf->s)) != NULL) {
+        char *err_ret = dupstr(err);
+        sk_close(pf->s);
+       free_portfwd_state(pf);
+        *pf_ret = NULL;
+       return err_ret;
     }
 
-    sk_set_private_ptr(*s, pr);
     return NULL;
 }
 
@@ -411,7 +465,7 @@ const char *pfd_newconnect(Socket *s, char *hostname, int port,
  called when someone connects to the local port
  */
 
-static int pfd_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
+static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
 {
     static const struct plug_function_table fn_table = {
        pfd_log,
@@ -420,44 +474,43 @@ static int pfd_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
        pfd_sent,
        NULL
     };
-    struct PFwdPrivate *pr, *org;
+    struct PortForwarding *pf;
+    struct PortListener *pl;
     Socket s;
     const char *err;
 
-    org = (struct PFwdPrivate *)p;
-    pr = new_portfwd_private();
-    pr->fn = &fn_table;
+    pl = (struct PortListener *)p;
+    pf = new_portfwd_state();
+    pf->fn = &fn_table;
 
-    pr->c = NULL;
-    pr->backhandle = org->backhandle;
+    pf->c = NULL;
+    pf->backhandle = pl->backhandle;
 
-    pr->s = s = constructor(ctx, (Plug) pr);
+    pf->s = s = constructor(ctx, (Plug) pf);
     if ((err = sk_socket_error(s)) != NULL) {
-       free_portfwd_private(pr);
+       free_portfwd_state(pf);
        return err != NULL;
     }
 
-    sk_set_private_ptr(s, pr);
-
-    pr->throttled = pr->throttle_override = 0;
-    pr->ready = 0;
+    pf->throttled = pf->throttle_override = 0;
+    pf->ready = 0;
 
-    if (org->dynamic) {
-       pr->dynamic = 1;
-       pr->port = 0;                  /* "hostname" buffer is so far empty */
+    if (pl->dynamic) {
+       pf->dynamic = 1;
+       pf->port = 0;                  /* "hostname" buffer is so far empty */
        sk_set_frozen(s, 0);           /* we want to receive SOCKS _now_! */
     } else {
-       pr->dynamic = 0;
-       pr->hostname = dupstr(org->hostname);
-       pr->port = org->port;   
-       pr->c = new_sock_channel(org->backhandle, s);
+       pf->dynamic = 0;
+       pf->hostname = dupstr(pl->hostname);
+       pf->port = pl->port;    
+       pf->c = new_sock_channel(pl->backhandle, pf);
 
-       if (pr->c == NULL) {
-           free_portfwd_private(pr);
+       if (pf->c == NULL) {
+           free_portfwd_state(pf);
            return 1;
        } else {
            /* asks to forward to the specified host/port for this */
-           ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding");
+           ssh_send_port_open(pf->c, pf->hostname, pf->port, "forwarding");
        }
     }
 
@@ -465,129 +518,119 @@ static int pfd_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
 }
 
 
-/* Add a new forwarding from port -> desthost:destport
- sets up a listener on the local machine on (srcaddr:)port
+/*
+ * Add a new port-forwarding listener from srcaddr:port -> desthost:destport.
+ *
+ * On success, returns NULL and fills in *pl_ret. On error, returns a
+ * dynamically allocated error message string.
  */
-const char *pfd_addforward(char *desthost, int destport, char *srcaddr,
-                          int port, void *backhandle, Conf *conf,
-                          void **sockdata, int address_family)
+char *pfl_listen(char *desthost, int destport, char *srcaddr,
+                 int port, void *backhandle, Conf *conf,
+                 struct PortListener **pl_ret, int address_family)
 {
     static const struct plug_function_table fn_table = {
-       pfd_log,
-       pfd_closing,
-       pfd_receive,                   /* should not happen... */
-       pfd_sent,                      /* also should not happen */
-       pfd_accepting
+       pfl_log,
+       pfl_closing,
+        NULL,                          /* recv */
+        NULL,                          /* send */
+       pfl_accepting
     };
 
     const char *err;
-    struct PFwdPrivate *pr;
-    Socket s;
+    struct PortListener *pl;
 
     /*
      * Open socket.
      */
-    pr = new_portfwd_private();
-    pr->fn = &fn_table;
-    pr->c = NULL;
+    pl = *pl_ret = new_portlistener_state();
+    pl->fn = &fn_table;
     if (desthost) {
-       pr->hostname = dupstr(desthost);
-       pr->port = destport;
-       pr->dynamic = 0;
+       pl->hostname = dupstr(desthost);
+       pl->port = destport;
+       pl->dynamic = 0;
     } else
-       pr->dynamic = 1;
-    pr->throttled = pr->throttle_override = 0;
-    pr->ready = 0;
-    pr->backhandle = backhandle;
-
-    pr->s = s = new_listener(srcaddr, port, (Plug) pr,
-                            !conf_get_int(conf, CONF_lport_acceptall),
-                            conf, address_family);
-    if ((err = sk_socket_error(s)) != NULL) {
-       free_portfwd_private(pr);
-       return err;
+       pl->dynamic = 1;
+    pl->backhandle = backhandle;
+
+    pl->s = new_listener(srcaddr, port, (Plug) pl,
+                         !conf_get_int(conf, CONF_lport_acceptall),
+                         conf, address_family);
+    if ((err = sk_socket_error(pl->s)) != NULL) {
+        char *err_ret = dupstr(err);
+        sk_close(pl->s);
+       free_portlistener_state(pl);
+        *pl_ret = NULL;
+       return err_ret;
     }
 
-    sk_set_private_ptr(s, pr);
-
-    *sockdata = (void *)s;
-
     return NULL;
 }
 
-void pfd_close(Socket s)
+void pfd_close(struct PortForwarding *pf)
 {
-    struct PFwdPrivate *pr;
-
-    if (!s)
+    if (!pf)
        return;
 
-    pr = (struct PFwdPrivate *) sk_get_private_ptr(s);
-
-    free_portfwd_private(pr);
-
-    sk_close(s);
+    sk_close(pf->s);
+    free_portfwd_state(pf);
 }
 
 /*
  * Terminate a listener.
  */
-void pfd_terminate(void *sv)
+void pfl_terminate(struct PortListener *pl)
 {
-    pfd_close((Socket)sv);
+    if (!pl)
+       return;
+
+    sk_close(pl->s);
+    free_portlistener_state(pl);
 }
 
-void pfd_unthrottle(Socket s)
+void pfd_unthrottle(struct PortForwarding *pf)
 {
-    struct PFwdPrivate *pr;
-    if (!s)
+    if (!pf)
        return;
-    pr = (struct PFwdPrivate *) sk_get_private_ptr(s);
 
-    pr->throttled = 0;
-    sk_set_frozen(s, pr->throttled || pr->throttle_override);
+    pf->throttled = 0;
+    sk_set_frozen(pf->s, pf->throttled || pf->throttle_override);
 }
 
-void pfd_override_throttle(Socket s, int enable)
+void pfd_override_throttle(struct PortForwarding *pf, int enable)
 {
-    struct PFwdPrivate *pr;
-    if (!s)
+    if (!pf)
        return;
-    pr = (struct PFwdPrivate *) sk_get_private_ptr(s);
 
-    pr->throttle_override = enable;
-    sk_set_frozen(s, pr->throttled || pr->throttle_override);
+    pf->throttle_override = enable;
+    sk_set_frozen(pf->s, pf->throttled || pf->throttle_override);
 }
 
 /*
  * Called to send data down the raw connection.
  */
-int pfd_send(Socket s, char *data, int len)
+int pfd_send(struct PortForwarding *pf, char *data, int len)
 {
-    if (s == NULL)
+    if (pf == NULL)
        return 0;
-    return sk_write(s, data, len);
+    return sk_write(pf->s, data, len);
 }
 
-void pfd_send_eof(Socket s)
+void pfd_send_eof(struct PortForwarding *pf)
 {
-    sk_write_eof(s);
+    sk_write_eof(pf->s);
 }
 
-void pfd_confirm(Socket s)
+void pfd_confirm(struct PortForwarding *pf)
 {
-    struct PFwdPrivate *pr;
-
-    if (s == NULL)
+    if (pf == NULL)
        return;
 
-    pr = (struct PFwdPrivate *) sk_get_private_ptr(s);
-    pr->ready = 1;
-    sk_set_frozen(s, 0);
-    sk_write(s, NULL, 0);
-    if (pr->buffer) {
-       sshfwd_write(pr->c, pr->buffer, pr->buflen);
-       sfree(pr->buffer);
-       pr->buffer = NULL;
+    pf->ready = 1;
+    sk_set_frozen(pf->s, 0);
+    sk_write(pf->s, NULL, 0);
+    if (pf->buffer) {
+       sshfwd_write(pf->c, pf->buffer, pf->buflen);
+       sfree(pf->buffer);
+       pf->buffer = NULL;
     }
 }
diff --git a/ssh.c b/ssh.c
index 0983f7d3c0016828317f5427a70c5e7f2056ee02..fa9bc745d13ee4f785b942248d6cec5882427d74 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -544,10 +544,10 @@ struct ssh_channel {
             int outstanding_requests;
        } a;
        struct ssh_x11_channel {
-           Socket s;
+           struct X11Connection *xconn;
        } x11;
        struct ssh_pfd_channel {
-           Socket s;
+            struct PortForwarding *pf;
        } pfd;
     } u;
 };
@@ -613,7 +613,7 @@ struct ssh_portfwd {
     char *sserv, *dserv;
     struct ssh_rportfwd *remote;
     int addressfamily;
-    void *local;
+    struct PortListener *local;
 };
 #define free_portfwd(pf) ( \
     ((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \
@@ -3005,11 +3005,11 @@ static int ssh_do_close(Ssh ssh, int notify_exit)
        while (NULL != (c = index234(ssh->channels, 0))) {
            switch (c->type) {
              case CHAN_X11:
-               x11_close(c->u.x11.s);
+               x11_close(c->u.x11.xconn);
                break;
              case CHAN_SOCKDATA:
              case CHAN_SOCKDATA_DORMANT:
-               pfd_close(c->u.pfd.s);
+               pfd_close(c->u.pfd.pf);
                break;
            }
            del234(ssh->channels, c); /* moving next one to index 0 */
@@ -3027,7 +3027,7 @@ static int ssh_do_close(Ssh ssh, int notify_exit)
        while (NULL != (pf = index234(ssh->portfwds, 0))) {
            /* Dispose of any listening socket. */
            if (pf->local)
-               pfd_terminate(pf->local);
+               pfl_terminate(pf->local);
            del234(ssh->portfwds, pf); /* moving next one to index 0 */
            free_portfwd(pf);
        }
@@ -3238,13 +3238,13 @@ static void ssh_throttle_all(Ssh ssh, int enable, int bufsize)
             */
            break;
          case CHAN_X11:
-           x11_override_throttle(c->u.x11.s, enable);
+           x11_override_throttle(c->u.x11.xconn, enable);
            break;
          case CHAN_AGENT:
            /* Agent channels require no buffer management. */
            break;
          case CHAN_SOCKDATA:
-           pfd_override_throttle(c->u.pfd.s, enable);
+           pfd_override_throttle(c->u.pfd.pf, enable);
            break;
        }
     }
@@ -4376,13 +4376,13 @@ void sshfwd_unclean_close(struct ssh_channel *c, const char *err)
 
     switch (c->type) {
       case CHAN_X11:
-        x11_close(c->u.x11.s);
+        x11_close(c->u.x11.xconn);
         logeventf(ssh, "Forwarded X11 connection terminated due to local "
                   "error: %s", err);
         break;
       case CHAN_SOCKDATA:
       case CHAN_SOCKDATA_DORMANT:
-        pfd_close(c->u.pfd.s);
+        pfd_close(c->u.pfd.pf);
         logeventf(ssh, "Forwarded port closed due to local error: %s", err);
         break;
     }
@@ -4720,7 +4720,7 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf)
                del234(ssh->rportfwds, rpf);
                free_rportfwd(rpf);
            } else if (epf->local) {
-               pfd_terminate(epf->local);
+               pfl_terminate(epf->local);
            }
 
            delpos234(ssh->portfwds, i);
@@ -4753,29 +4753,31 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf)
            }
 
            if (epf->type == 'L') {
-               const char *err = pfd_addforward(epf->daddr, epf->dport,
-                                                epf->saddr, epf->sport,
-                                                ssh, conf,
-                                                &epf->local,
-                                                epf->addressfamily);
+                char *err = pfl_listen(epf->daddr, epf->dport,
+                                       epf->saddr, epf->sport,
+                                       ssh, conf, &epf->local,
+                                       epf->addressfamily);
 
                logeventf(ssh, "Local %sport %s forwarding to %s%s%s",
                          epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
                          epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
                          sportdesc, dportdesc,
                          err ? " failed: " : "", err ? err : "");
+                if (err)
+                    sfree(err);
            } else if (epf->type == 'D') {
-               const char *err = pfd_addforward(NULL, -1,
-                                                epf->saddr, epf->sport,
-                                                ssh, conf,
-                                                &epf->local,
-                                                epf->addressfamily);
+               char *err = pfl_listen(NULL, -1, epf->saddr, epf->sport,
+                                       ssh, conf, &epf->local,
+                                       epf->addressfamily);
 
                logeventf(ssh, "Local %sport %s SOCKS dynamic forwarding%s%s",
                          epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
                          epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
                          sportdesc,
                          err ? " failed: " : "", err ? err : "");
+
+                if (err)
+                    sfree(err);
            } else {
                struct ssh_rportfwd *pf;
 
@@ -4875,12 +4877,15 @@ static void ssh1_smsg_x11_open(Ssh ssh, struct Packet *pktin)
                    PKT_INT, remoteid, PKT_END);
        logevent("Rejected X11 connect request");
     } else {
+        char *err;
+
        c = snew(struct ssh_channel);
        c->ssh = ssh;
 
-       if (x11_init(&c->u.x11.s, ssh->x11disp, c,
-                    NULL, -1, ssh->conf) != NULL) {
-           logevent("Opening X11 forward connection failed");
+       if ((err = x11_init(&c->u.x11.xconn, ssh->x11disp, c,
+                            NULL, -1, ssh->conf)) != NULL) {
+           logeventf(ssh, "Opening X11 forward connection failed: %s", err);
+            sfree(err);
            sfree(c);
            send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
                        PKT_INT, remoteid, PKT_END);
@@ -4942,7 +4947,7 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin)
     int remoteid;
     int hostsize, port;
     char *host;
-    const char *e;
+    char *err;
 
     remoteid = ssh_pkt_getuint32(pktin);
     ssh_pkt_getstring(pktin, &host, &hostsize);
@@ -4963,10 +4968,11 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin)
 
        logeventf(ssh, "Received remote port open request for %s:%d",
                  pf.dhost, port);
-       e = pfd_newconnect(&c->u.pfd.s, pf.dhost, port,
-                          c, ssh->conf, pfp->pfrec->addressfamily);
-       if (e != NULL) {
-           logeventf(ssh, "Port open failed: %s", e);
+       err = pfd_connect(&c->u.pfd.pf, pf.dhost, port,
+                          c, ssh->conf, pfp->pfrec->addressfamily);
+       if (err != NULL) {
+           logeventf(ssh, "Port open failed: %s", err);
+            sfree(err);
            sfree(c);
            send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
                        PKT_INT, remoteid, PKT_END);
@@ -5001,7 +5007,7 @@ static void ssh1_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)
        c->halfopen = FALSE;
        c->type = CHAN_SOCKDATA;
        c->throttling_conn = 0;
-       pfd_confirm(c->u.pfd.s);
+       pfd_confirm(c->u.pfd.pf);
     }
 
     if (c && c->pending_eof) {
@@ -5023,7 +5029,7 @@ static void ssh1_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)
     c = find234(ssh->channels, &remoteid, ssh_channelfind);
     if (c && c->type == CHAN_SOCKDATA_DORMANT) {
        logevent("Forwarded connection refused by server");
-       pfd_close(c->u.pfd.s);
+       pfd_close(c->u.pfd.pf);
        del234(ssh->channels, c);
        sfree(c);
     }
@@ -5049,14 +5055,14 @@ static void ssh1_msg_channel_close(Ssh ssh, struct Packet *pktin)
 
             switch (c->type) {
               case CHAN_X11:
-                if (c->u.x11.s)
-                    x11_send_eof(c->u.x11.s);
+                if (c->u.x11.xconn)
+                    x11_send_eof(c->u.x11.xconn);
                 else
                     send_close = TRUE;
                break;
               case CHAN_SOCKDATA:
-                if (c->u.pfd.s)
-                    pfd_send_eof(c->u.pfd.s);
+                if (c->u.pfd.pf)
+                    pfd_send_eof(c->u.pfd.pf);
                 else
                     send_close = TRUE;
                break;
@@ -5115,10 +5121,10 @@ static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin)
        int bufsize = 0;
        switch (c->type) {
          case CHAN_X11:
-           bufsize = x11_send(c->u.x11.s, p, len);
+           bufsize = x11_send(c->u.x11.xconn, p, len);
            break;
          case CHAN_SOCKDATA:
-           bufsize = pfd_send(c->u.pfd.s, p, len);
+           bufsize = pfd_send(c->u.pfd.pf, p, len);
            break;
          case CHAN_AGENT:
            /* Data for an agent message. Buffer it. */
@@ -6660,14 +6666,14 @@ static void ssh2_try_send_and_unthrottle(Ssh ssh, struct ssh_channel *c)
             * notification since it will be polled */
            break;
          case CHAN_X11:
-           x11_unthrottle(c->u.x11.s);
+           x11_unthrottle(c->u.x11.xconn);
            break;
          case CHAN_AGENT:
            /* agent sockets are request/response and need no
             * buffer management */
            break;
          case CHAN_SOCKDATA:
-           pfd_unthrottle(c->u.pfd.s);
+           pfd_unthrottle(c->u.pfd.pf);
            break;
        }
     }
@@ -6930,10 +6936,10 @@ static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin)
                             data, length);
            break;
          case CHAN_X11:
-           bufsize = x11_send(c->u.x11.s, data, length);
+           bufsize = x11_send(c->u.x11.xconn, data, length);
            break;
          case CHAN_SOCKDATA:
-           bufsize = pfd_send(c->u.pfd.s, data, length);
+           bufsize = pfd_send(c->u.pfd.pf, data, length);
            break;
          case CHAN_AGENT:
            while (length > 0) {
@@ -7021,16 +7027,16 @@ static void ssh_channel_destroy(struct ssh_channel *c)
         update_specials_menu(ssh->frontend);
         break;
       case CHAN_X11:
-        if (c->u.x11.s != NULL)
-            x11_close(c->u.x11.s);
+        if (c->u.x11.xconn != NULL)
+            x11_close(c->u.x11.xconn);
         logevent("Forwarded X11 connection terminated");
         break;
       case CHAN_AGENT:
         sfree(c->u.a.message);
         break;
       case CHAN_SOCKDATA:
-        if (c->u.pfd.s != NULL)
-            pfd_close(c->u.pfd.s);
+        if (c->u.pfd.pf != NULL)
+            pfd_close(c->u.pfd.pf);
         logevent("Forwarded port closed");
         break;
     }
@@ -7112,14 +7118,14 @@ static void ssh2_channel_got_eof(struct ssh_channel *c)
     c->closes |= CLOSES_RCVD_EOF;
 
     if (c->type == CHAN_X11) {
-       x11_send_eof(c->u.x11.s);
+       x11_send_eof(c->u.x11.xconn);
     } else if (c->type == CHAN_AGENT) {
         if (c->u.a.outstanding_requests == 0) {
             /* Manufacture an outgoing EOF in response to the incoming one. */
             sshfwd_write_eof(c);
         }
     } else if (c->type == CHAN_SOCKDATA) {
-       pfd_send_eof(c->u.pfd.s);
+       pfd_send_eof(c->u.pfd.pf);
     } else if (c->type == CHAN_MAINSESSION) {
         Ssh ssh = c->ssh;
 
@@ -7182,10 +7188,10 @@ static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin)
             ssh->send_ok = 0;     /* stop trying to read from stdin */
             break;
           case CHAN_X11:
-           x11_override_throttle(c->u.x11.s, 1);
+           x11_override_throttle(c->u.x11.xconn, 1);
            break;
          case CHAN_SOCKDATA:
-           pfd_override_throttle(c->u.pfd.s, 1);
+           pfd_override_throttle(c->u.pfd.pf, 1);
            break;
         }
 
@@ -7228,8 +7234,8 @@ static void ssh2_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)
 
     if (c->type == CHAN_SOCKDATA_DORMANT) {
         c->type = CHAN_SOCKDATA;
-        if (c->u.pfd.s)
-            pfd_confirm(c->u.pfd.s);
+        if (c->u.pfd.pf)
+            pfd_confirm(c->u.pfd.pf);
     } else if (c->type == CHAN_ZOMBIE) {
         /*
          * This case can occur if a local socket error occurred
@@ -7285,7 +7291,7 @@ static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)
         logeventf(ssh, "Forwarded connection refused by server: %s [%.*s]",
                   reasons[reason_code], reason_length, reason_string);
 
-        pfd_close(c->u.pfd.s);
+        pfd_close(c->u.pfd.pf);
     } else if (c->type == CHAN_ZOMBIE) {
         /*
          * This case can occur if a local socket error occurred
@@ -7536,7 +7542,7 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin)
 
     if (typelen == 3 && !memcmp(type, "x11", 3)) {
        char *addrstr;
-       const char *x11err;
+       char *x11err;
 
        ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen);
        addrstr = snewn(peeraddrlen+1, char);
@@ -7549,9 +7555,10 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin)
 
        if (!ssh->X11_fwd_enabled)
            error = "X11 forwarding is not enabled";
-       else if ((x11err = x11_init(&c->u.x11.s, ssh->x11disp, c,
+       else if ((x11err = x11_init(&c->u.x11.xconn, ssh->x11disp, c,
                                    addrstr, peerport, ssh->conf)) != NULL) {
            logeventf(ssh, "Local X11 connection failed: %s", x11err);
+            sfree(x11err);
            error = "Unable to open an X11 connection";
        } else {
            logevent("Opening X11 forward connection succeeded");
@@ -7577,15 +7584,16 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin)
        if (realpf == NULL) {
            error = "Remote port is not recognised";
        } else {
-           const char *e = pfd_newconnect(&c->u.pfd.s,
-                                          realpf->dhost,
-                                          realpf->dport, c,
-                                          ssh->conf,
-                                          realpf->pfrec->addressfamily);
+           char *err = pfd_connect(&c->u.pfd.pf,
+                                    realpf->dhost,
+                                    realpf->dport, c,
+                                    ssh->conf,
+                                    realpf->pfrec->addressfamily);
            logeventf(ssh, "Attempting to forward remote port to "
                      "%s:%d", realpf->dhost, realpf->dport);
-           if (e != NULL) {
-               logeventf(ssh, "Port open failed: %s", e);
+           if (err != NULL) {
+               logeventf(ssh, "Port open failed: %s", err);
+                sfree(err);
                error = "Port open failed";
            } else {
                logevent("Forwarded port opened successfully");
@@ -9909,13 +9917,13 @@ static void ssh_free(void *handle)
        while ((c = delpos234(ssh->channels, 0)) != NULL) {
            switch (c->type) {
              case CHAN_X11:
-               if (c->u.x11.s != NULL)
-                   x11_close(c->u.x11.s);
+               if (c->u.x11.xconn != NULL)
+                   x11_close(c->u.x11.xconn);
                break;
              case CHAN_SOCKDATA:
              case CHAN_SOCKDATA_DORMANT:
-               if (c->u.pfd.s != NULL)
-                   pfd_close(c->u.pfd.s);
+               if (c->u.pfd.pf != NULL)
+                   pfd_close(c->u.pfd.pf);
                break;
            }
            if (ssh->version == 2) {
@@ -10288,7 +10296,7 @@ static void ssh_special(void *handle, Telnet_Special code)
     }
 }
 
-void *new_sock_channel(void *handle, Socket s)
+void *new_sock_channel(void *handle, struct PortForwarding *pf)
 {
     Ssh ssh = (Ssh) handle;
     struct ssh_channel *c;
@@ -10298,7 +10306,7 @@ void *new_sock_channel(void *handle, Socket s)
     ssh2_channel_init(c);
     c->halfopen = TRUE;
     c->type = CHAN_SOCKDATA_DORMANT;/* identify channel type */
-    c->u.pfd.s = s;
+    c->u.pfd.pf = pf;
     add234(ssh->channels, c);
     return c;
 }
diff --git a/ssh.h b/ssh.h
index 9404e8247a4cbe4e135102edfe580166871e6ca1..b900738e316e4f7e47a6d8badaf05ed24d143d0e 100644 (file)
--- a/ssh.h
+++ b/ssh.h
@@ -330,24 +330,27 @@ void random_add_heavynoise(void *noise, int length);
 
 void logevent(void *, const char *);
 
+struct PortForwarding;
+
 /* Allocate and register a new channel for port forwarding */
-void *new_sock_channel(void *handle, Socket s);
+void *new_sock_channel(void *handle, struct PortForwarding *pf);
 void ssh_send_port_open(void *channel, char *hostname, int port, char *org);
 
 /* Exports from portfwd.c */
-extern const char *pfd_newconnect(Socket * s, char *hostname, int port,
-                                 void *c, Conf *conf, int addressfamily);
+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 *, char *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);
+struct PortListener;
 /* desthost == NULL indicates dynamic (SOCKS) port forwarding */
-extern const char *pfd_addforward(char *desthost, int destport, char *srcaddr,
-                                 int port, void *backhandle, Conf *conf,
-                                 void **sockdata, int address_family);
-extern void pfd_close(Socket s);
-extern void pfd_terminate(void *sockdata);
-extern int pfd_send(Socket s, char *data, int len);
-extern void pfd_send_eof(Socket s);
-extern void pfd_confirm(Socket s);
-extern void pfd_unthrottle(Socket s);
-extern void pfd_override_throttle(Socket s, int enable);
+extern char *pfl_listen(char *desthost, int destport, char *srcaddr,
+                        int port, void *backhandle, Conf *conf,
+                        struct PortListener **pl, int address_family);
+extern void pfl_terminate(struct PortListener *);
 
 /* Exports from x11fwd.c */
 enum {
@@ -396,13 +399,14 @@ struct X11Display {
 extern struct X11Display *x11_setup_display(char *display, int authtype,
                                            Conf *);
 void x11_free_display(struct X11Display *disp);
-extern const char *x11_init(Socket *, struct X11Display *, void *,
-                           const char *, int, Conf *);
-extern void x11_close(Socket);
-extern int x11_send(Socket, char *, int);
-extern void x11_send_eof(Socket s);
-extern void x11_unthrottle(Socket s);
-extern void x11_override_throttle(Socket s, int enable);
+struct X11Connection;                  /* opaque outside x11fwd.c */
+extern char *x11_init(struct X11Connection **, struct X11Display *,
+                      void *, const char *, int, Conf *);
+extern void x11_close(struct X11Connection *);
+extern int x11_send(struct X11Connection *, char *, 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);
 char *x11_display(const char *display);
 /* Platform-dependent X11 functions */
 extern void platform_get_x11_auth(struct X11Display *display, Conf *);
index ba729d1816f90a24642891a6197b7a3ac3946c0c..7f4b06c41f22d95598be797322f45b91545cb13e 100644 (file)
--- a/x11fwd.c
+++ b/x11fwd.c
@@ -26,7 +26,7 @@ struct XDMSeen {
     unsigned char clientid[6];
 };
 
-struct X11Private {
+struct X11Connection {
     const struct plug_function_table *fn;
     /* the above variable absolutely *must* be the first in this structure */
     unsigned char firstpkt[12];               /* first X data packet */
@@ -38,7 +38,7 @@ struct X11Private {
     int throttled, throttle_override;
     unsigned long peer_ip;
     int peer_port;
-    void *c;                          /* data used by ssh.c */
+    struct ssh_channel *c;        /* channel structure held by ssh.c */
     Socket s;
 };
 
@@ -504,20 +504,20 @@ static void x11_log(Plug p, int type, SockAddr addr, int port,
 static int x11_closing(Plug plug, const char *error_msg, int error_code,
                       int calling_back)
 {
-    struct X11Private *pr = (struct X11Private *) plug;
+    struct X11Connection *xconn = (struct X11Connection *) plug;
 
     if (error_msg) {
         /*
          * Socket error. Slam the connection instantly shut.
          */
-        sshfwd_unclean_close(pr->c, error_msg);
+        sshfwd_unclean_close(xconn->c, error_msg);
     } else {
         /*
          * Ordinary EOF received on socket. Send an EOF on the SSH
          * channel.
          */
-        if (pr->c)
-            sshfwd_write_eof(pr->c);
+        if (xconn->c)
+            sshfwd_write_eof(xconn->c);
     }
 
     return 1;
@@ -525,11 +525,11 @@ static int x11_closing(Plug plug, const char *error_msg, int error_code,
 
 static int x11_receive(Plug plug, int urgent, char *data, int len)
 {
-    struct X11Private *pr = (struct X11Private *) plug;
+    struct X11Connection *xconn = (struct X11Connection *) plug;
 
-    if (sshfwd_write(pr->c, data, len) > 0) {
-       pr->throttled = 1;
-       sk_set_frozen(pr->s, 1);
+    if (sshfwd_write(xconn->c, data, len) > 0) {
+       xconn->throttled = 1;
+       sk_set_frozen(xconn->s, 1);
     }
 
     return 1;
@@ -537,9 +537,9 @@ static int x11_receive(Plug plug, int urgent, char *data, int len)
 
 static void x11_sent(Plug plug, int bufsize)
 {
-    struct X11Private *pr = (struct X11Private *) plug;
+    struct X11Connection *xconn = (struct X11Connection *) plug;
 
-    sshfwd_unthrottle(pr->c, bufsize);
+    sshfwd_unthrottle(xconn->c, bufsize);
 }
 
 /*
@@ -563,11 +563,12 @@ int x11_get_screen_number(char *display)
 /*
  * Called to set up the raw connection.
  * 
- * Returns an error message, or NULL on success.
- * also, fills the SocketsStructure
+ * On success, returns NULL and fills in *xconnret. On error, returns
+ * a dynamically allocated error message string.
  */
-extern const char *x11_init(Socket *s, struct X11Display *disp, void *c,
-                           const char *peeraddr, int peerport, Conf *conf)
+extern char *x11_init(struct X11Connection **xconnret,
+                      struct X11Display *disp, void *c,
+                      const char *peeraddr, int peerport, Conf *conf)
 {
     static const struct plug_function_table fn_table = {
        x11_log,
@@ -578,26 +579,29 @@ extern const char *x11_init(Socket *s, struct X11Display *disp, void *c,
     };
 
     const char *err;
-    struct X11Private *pr;
+    struct X11Connection *xconn;
 
     /*
      * Open socket.
      */
-    pr = snew(struct X11Private);
-    pr->fn = &fn_table;
-    pr->auth_protocol = NULL;
-    pr->disp = disp;
-    pr->verified = 0;
-    pr->data_read = 0;
-    pr->throttled = pr->throttle_override = 0;
-    pr->c = c;
-
-    pr->s = *s = new_connection(sk_addr_dup(disp->addr),
-                               disp->realhost, disp->port,
-                               0, 1, 0, 0, (Plug) pr, conf);
-    if ((err = sk_socket_error(*s)) != NULL) {
-       sfree(pr);
-       return err;
+    xconn = *xconnret = snew(struct X11Connection);
+    xconn->fn = &fn_table;
+    xconn->auth_protocol = NULL;
+    xconn->disp = disp;
+    xconn->verified = 0;
+    xconn->data_read = 0;
+    xconn->throttled = xconn->throttle_override = 0;
+    xconn->c = c;
+
+    xconn->s = new_connection(sk_addr_dup(disp->addr),
+                           disp->realhost, disp->port,
+                           0, 1, 0, 0, (Plug) xconn, conf);
+    if ((err = sk_socket_error(xconn->s)) != NULL) {
+        char *err_ret = dupstr(err);
+        sk_close(xconn->s);
+       sfree(xconn);
+        *xconnret = NULL;
+       return err_ret;
     }
 
     /*
@@ -607,109 +611,102 @@ extern const char *x11_init(Socket *s, struct X11Display *disp, void *c,
        int i[4];
        if (peeraddr &&
            4 == sscanf(peeraddr, "%d.%d.%d.%d", i+0, i+1, i+2, i+3)) {
-           pr->peer_ip = (i[0] << 24) | (i[1] << 16) | (i[2] << 8) | i[3];
-           pr->peer_port = peerport;
+           xconn->peer_ip = (i[0] << 24) | (i[1] << 16) | (i[2] << 8) | i[3];
+           xconn->peer_port = peerport;
        } else {
-           pr->peer_ip = 0;
-           pr->peer_port = -1;
+           xconn->peer_ip = 0;
+           xconn->peer_port = -1;
        }
     }
 
-    sk_set_private_ptr(*s, pr);
     return NULL;
 }
 
-void x11_close(Socket s)
+void x11_close(struct X11Connection *xconn)
 {
-    struct X11Private *pr;
-    if (!s)
+    if (!xconn)
        return;
-    pr = (struct X11Private *) sk_get_private_ptr(s);
-    if (pr->auth_protocol) {
-       sfree(pr->auth_protocol);
-       sfree(pr->auth_data);
-    }
 
-    sfree(pr);
+    if (xconn->auth_protocol) {
+       sfree(xconn->auth_protocol);
+       sfree(xconn->auth_data);
+    }
 
-    sk_close(s);
+    sk_close(xconn->s);
+    sfree(xconn);
 }
 
-void x11_unthrottle(Socket s)
+void x11_unthrottle(struct X11Connection *xconn)
 {
-    struct X11Private *pr;
-    if (!s)
+    if (!xconn)
        return;
-    pr = (struct X11Private *) sk_get_private_ptr(s);
 
-    pr->throttled = 0;
-    sk_set_frozen(s, pr->throttled || pr->throttle_override);
+    xconn->throttled = 0;
+    sk_set_frozen(xconn->s, xconn->throttled || xconn->throttle_override);
 }
 
-void x11_override_throttle(Socket s, int enable)
+void x11_override_throttle(struct X11Connection *xconn, int enable)
 {
-    struct X11Private *pr;
-    if (!s)
+    if (!xconn)
        return;
-    pr = (struct X11Private *) sk_get_private_ptr(s);
 
-    pr->throttle_override = enable;
-    sk_set_frozen(s, pr->throttled || pr->throttle_override);
+    xconn->throttle_override = enable;
+    sk_set_frozen(xconn->s, xconn->throttled || xconn->throttle_override);
 }
 
 /*
  * Called to send data down the raw connection.
  */
-int x11_send(Socket s, char *data, int len)
+int x11_send(struct X11Connection *xconn, char *data, int len)
 {
-    struct X11Private *pr;
-    if (!s)
+    if (!xconn)
        return 0;
-    pr = (struct X11Private *) sk_get_private_ptr(s);
 
     /*
      * Read the first packet.
      */
-    while (len > 0 && pr->data_read < 12)
-       pr->firstpkt[pr->data_read++] = (unsigned char) (len--, *data++);
-    if (pr->data_read < 12)
+    while (len > 0 && xconn->data_read < 12)
+       xconn->firstpkt[xconn->data_read++] = (unsigned char) (len--, *data++);
+    if (xconn->data_read < 12)
        return 0;
 
     /*
      * If we have not allocated the auth_protocol and auth_data
      * strings, do so now.
      */
-    if (!pr->auth_protocol) {
-       pr->auth_plen = GET_16BIT(pr->firstpkt[0], pr->firstpkt + 6);
-       pr->auth_dlen = GET_16BIT(pr->firstpkt[0], pr->firstpkt + 8);
-       pr->auth_psize = (pr->auth_plen + 3) & ~3;
-       pr->auth_dsize = (pr->auth_dlen + 3) & ~3;
+    if (!xconn->auth_protocol) {
+       xconn->auth_plen = GET_16BIT(xconn->firstpkt[0], xconn->firstpkt + 6);
+       xconn->auth_dlen = GET_16BIT(xconn->firstpkt[0], xconn->firstpkt + 8);
+       xconn->auth_psize = (xconn->auth_plen + 3) & ~3;
+       xconn->auth_dsize = (xconn->auth_dlen + 3) & ~3;
        /* Leave room for a terminating zero, to make our lives easier. */
-       pr->auth_protocol = snewn(pr->auth_psize + 1, char);
-       pr->auth_data = snewn(pr->auth_dsize, unsigned char);
+       xconn->auth_protocol = snewn(xconn->auth_psize + 1, char);
+       xconn->auth_data = snewn(xconn->auth_dsize, unsigned char);
     }
 
     /*
      * Read the auth_protocol and auth_data strings.
      */
-    while (len > 0 && pr->data_read < 12 + pr->auth_psize)
-       pr->auth_protocol[pr->data_read++ - 12] = (len--, *data++);
-    while (len > 0 && pr->data_read < 12 + pr->auth_psize + pr->auth_dsize)
-       pr->auth_data[pr->data_read++ - 12 -
-                     pr->auth_psize] = (unsigned char) (len--, *data++);
-    if (pr->data_read < 12 + pr->auth_psize + pr->auth_dsize)
+    while (len > 0 &&
+           xconn->data_read < 12 + xconn->auth_psize)
+       xconn->auth_protocol[xconn->data_read++ - 12] = (len--, *data++);
+    while (len > 0 &&
+           xconn->data_read < 12 + xconn->auth_psize + xconn->auth_dsize)
+       xconn->auth_data[xconn->data_read++ - 12 -
+                     xconn->auth_psize] = (unsigned char) (len--, *data++);
+    if (xconn->data_read < 12 + xconn->auth_psize + xconn->auth_dsize)
        return 0;
 
     /*
      * If we haven't verified the authorisation, do so now.
      */
-    if (!pr->verified) {
+    if (!xconn->verified) {
        char *err;
 
-       pr->auth_protocol[pr->auth_plen] = '\0';        /* ASCIZ */
-       err = x11_verify(pr->peer_ip, pr->peer_port,
-                        pr->disp, pr->auth_protocol,
-                        pr->auth_data, pr->auth_dlen);
+       xconn->auth_protocol[xconn->auth_plen] = '\0';  /* ASCIZ */
+       err = x11_verify(xconn->peer_ip, xconn->peer_port,
+                        xconn->disp, xconn->auth_protocol,
+                        xconn->auth_data, xconn->auth_dlen);
 
        /*
         * If authorisation failed, construct and send an error
@@ -726,12 +723,12 @@ int x11_send(Socket s, char *data, int len)
            msgsize = (msglen + 3) & ~3;
            reply[0] = 0;              /* failure */
            reply[1] = msglen;         /* length of reason string */
-           memcpy(reply + 2, pr->firstpkt + 2, 4);     /* major/minor proto vsn */
-           PUT_16BIT(pr->firstpkt[0], reply + 6, msgsize >> 2);/* data len */
+           memcpy(reply + 2, xconn->firstpkt + 2, 4);  /* major/minor proto vsn */
+           PUT_16BIT(xconn->firstpkt[0], reply + 6, msgsize >> 2);/* data len */
            memset(reply + 8, 0, msgsize);
            memcpy(reply + 8, message, msglen);
-           sshfwd_write(pr->c, (char *)reply, 8 + msgsize);
-           sshfwd_write_eof(pr->c);
+           sshfwd_write(xconn->c, (char *)reply, 8 + msgsize);
+           sshfwd_write_eof(xconn->c);
            sfree(reply);
            sfree(message);
            return 0;
@@ -745,59 +742,59 @@ int x11_send(Socket s, char *data, int len)
         {
             char realauthdata[64];
             int realauthlen = 0;
-            int authstrlen = strlen(x11_authnames[pr->disp->localauthproto]);
+            int authstrlen = strlen(x11_authnames[xconn->disp->localauthproto]);
            int buflen = 0;            /* initialise to placate optimiser */
             static const char zeroes[4] = { 0,0,0,0 };
            void *buf;
 
-            if (pr->disp->localauthproto == X11_MIT) {
-                assert(pr->disp->localauthdatalen <= lenof(realauthdata));
-                realauthlen = pr->disp->localauthdatalen;
-                memcpy(realauthdata, pr->disp->localauthdata, realauthlen);
-            } else if (pr->disp->localauthproto == X11_XDM &&
-                      pr->disp->localauthdatalen == 16 &&
-                      ((buf = sk_getxdmdata(s, &buflen))!=0)) {
+            if (xconn->disp->localauthproto == X11_MIT) {
+                assert(xconn->disp->localauthdatalen <= lenof(realauthdata));
+                realauthlen = xconn->disp->localauthdatalen;
+                memcpy(realauthdata, xconn->disp->localauthdata, realauthlen);
+            } else if (xconn->disp->localauthproto == X11_XDM &&
+                      xconn->disp->localauthdatalen == 16 &&
+                      ((buf = sk_getxdmdata(xconn->s, &buflen))!=0)) {
                time_t t;
                 realauthlen = (buflen+12+7) & ~7;
                assert(realauthlen <= lenof(realauthdata));
                memset(realauthdata, 0, realauthlen);
-               memcpy(realauthdata, pr->disp->localauthdata, 8);
+               memcpy(realauthdata, xconn->disp->localauthdata, 8);
                memcpy(realauthdata+8, buf, buflen);
                t = time(NULL);
                PUT_32BIT_MSB_FIRST(realauthdata+8+buflen, t);
-               des_encrypt_xdmauth(pr->disp->localauthdata+9,
+               des_encrypt_xdmauth(xconn->disp->localauthdata+9,
                                    (unsigned char *)realauthdata,
                                    realauthlen);
                sfree(buf);
            }
             /* implement other auth methods here if required */
 
-            PUT_16BIT(pr->firstpkt[0], pr->firstpkt + 6, authstrlen);
-            PUT_16BIT(pr->firstpkt[0], pr->firstpkt + 8, realauthlen);
+            PUT_16BIT(xconn->firstpkt[0], xconn->firstpkt + 6, authstrlen);
+            PUT_16BIT(xconn->firstpkt[0], xconn->firstpkt + 8, realauthlen);
         
-            sk_write(s, (char *)pr->firstpkt, 12);
+            sk_write(xconn->s, (char *)xconn->firstpkt, 12);
 
             if (authstrlen) {
-                sk_write(s, x11_authnames[pr->disp->localauthproto],
+                sk_write(xconn->s, x11_authnames[xconn->disp->localauthproto],
                         authstrlen);
-                sk_write(s, zeroes, 3 & (-authstrlen));
+                sk_write(xconn->s, zeroes, 3 & (-authstrlen));
             }
             if (realauthlen) {
-                sk_write(s, realauthdata, realauthlen);
-                sk_write(s, zeroes, 3 & (-realauthlen));
+                sk_write(xconn->s, realauthdata, realauthlen);
+                sk_write(xconn->s, zeroes, 3 & (-realauthlen));
             }
         }
-       pr->verified = 1;
+       xconn->verified = 1;
     }
 
     /*
      * After initialisation, just copy data simply.
      */
 
-    return sk_write(s, data, len);
+    return sk_write(xconn->s, data, len);
 }
 
-void x11_send_eof(Socket s)
+void x11_send_eof(struct X11Connection *xconn)
 {
-    sk_write_eof(s);
+    sk_write_eof(xconn->s);
 }