]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Decouple X socket opening from x11_init().
authorSimon Tatham <anakin@pobox.com>
Sun, 17 Nov 2013 14:05:04 +0000 (14:05 +0000)
committerSimon Tatham <anakin@pobox.com>
Sun, 17 Nov 2013 14:05:04 +0000 (14:05 +0000)
Now we wait to open the socket to the X server until we've seen the
authorisation data. This prepares us to do something else with the
channel if we see different auth data, which will come up in
connection sharing.

[originally from svn r10078]

ssh.c
ssh.h
x11fwd.c

diff --git a/ssh.c b/ssh.c
index e6b2d6be9cf6158d1a28777aa6fbf5879bef9c54..fd3d4cf50dcdcc996281e1a5acfdc1d2ac66cdf1 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -4355,6 +4355,12 @@ static void ssh_channel_try_eof(struct ssh_channel *c)
     }
 }
 
+Conf *sshfwd_get_conf(struct ssh_channel *c)
+{
+    Ssh ssh = c->ssh;
+    return ssh->conf;
+}
+
 void sshfwd_write_eof(struct ssh_channel *c)
 {
     Ssh ssh = c->ssh;
@@ -4885,7 +4891,7 @@ static void ssh1_smsg_x11_open(Ssh ssh, struct Packet *pktin)
        c->ssh = ssh;
 
        if ((err = x11_init(&c->u.x11.xconn, ssh->x11disp, c,
-                            NULL, -1, ssh->conf)) != NULL) {
+                            NULL, -1)) != NULL) {
            logeventf(ssh, "Opening X11 forward connection failed: %s", err);
             sfree(err);
            sfree(c);
@@ -7558,7 +7564,7 @@ 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.xconn, ssh->x11disp, c,
-                                   addrstr, peerport, ssh->conf)) != NULL) {
+                                   addrstr, peerport)) != NULL) {
            logeventf(ssh, "Local X11 connection failed: %s", x11err);
             sfree(x11err);
            error = "Unable to open an X11 connection";
diff --git a/ssh.h b/ssh.h
index a7c22cd7ee37e297be9a2ab36467125183f2d7d5..ee629ee58d193485c02c7eb2827ef08d48c94373 100644 (file)
--- a/ssh.h
+++ b/ssh.h
@@ -13,6 +13,7 @@ extern int sshfwd_write(struct ssh_channel *c, char *, 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);
 
 /*
  * Useful thing.
@@ -401,7 +402,7 @@ extern struct X11Display *x11_setup_display(char *display, int authtype,
 void x11_free_display(struct X11Display *disp);
 struct X11Connection;                  /* opaque outside x11fwd.c */
 extern char *x11_init(struct X11Connection **, struct X11Display *,
-                      void *, const char *, int, Conf *);
+                      void *, const char *, int);
 extern void x11_close(struct X11Connection *);
 extern int x11_send(struct X11Connection *, char *, int);
 extern void x11_send_eof(struct X11Connection *s);
index 7f4b06c41f22d95598be797322f45b91545cb13e..80a0206c0ebf954ee6ec0535281e8b8c733c4fc5 100644 (file)
--- a/x11fwd.c
+++ b/x11fwd.c
@@ -36,6 +36,7 @@ struct X11Connection {
     int data_read, auth_plen, auth_psize, auth_dlen, auth_dsize;
     int verified;
     int throttled, throttle_override;
+    int no_data_sent_to_x_client;
     unsigned long peer_ip;
     int peer_port;
     struct ssh_channel *c;        /* channel structure held by ssh.c */
@@ -501,6 +502,9 @@ static void x11_log(Plug p, int type, SockAddr addr, int port,
     /* We have no interface to the logging module here, so we drop these. */
 }
 
+static void x11_send_init_error(struct X11Connection *conn,
+                                const char *err_message);
+
 static int x11_closing(Plug plug, const char *error_msg, int error_code,
                       int calling_back)
 {
@@ -508,7 +512,19 @@ static int x11_closing(Plug plug, const char *error_msg, int error_code,
 
     if (error_msg) {
         /*
-         * Socket error. Slam the connection instantly shut.
+         * Socket error. If we're still at the connection setup stage,
+         * construct an X11 error packet passing on the problem.
+         */
+        if (xconn->no_data_sent_to_x_client) {
+            char *err_message = dupprintf("unable to connect to forwarded "
+                                          "X server: %s", error_msg);
+            x11_send_init_error(xconn, err_message);
+            sfree(err_message);
+        }
+
+        /*
+         * Whether we did that or not, now we slam the connection
+         * shut.
          */
         sshfwd_unclean_close(xconn->c, error_msg);
     } else {
@@ -529,6 +545,7 @@ static int x11_receive(Plug plug, int urgent, char *data, int len)
 
     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);
     }
 
@@ -568,7 +585,7 @@ int x11_get_screen_number(char *display)
  */
 extern char *x11_init(struct X11Connection **xconnret,
                       struct X11Display *disp, void *c,
-                      const char *peeraddr, int peerport, Conf *conf)
+                      const char *peeraddr, int peerport)
 {
     static const struct plug_function_table fn_table = {
        x11_log,
@@ -578,7 +595,6 @@ extern char *x11_init(struct X11Connection **xconnret,
        NULL
     };
 
-    const char *err;
     struct X11Connection *xconn;
 
     /*
@@ -591,18 +607,17 @@ extern char *x11_init(struct X11Connection **xconnret,
     xconn->verified = 0;
     xconn->data_read = 0;
     xconn->throttled = xconn->throttle_override = 0;
+    xconn->no_data_sent_to_x_client = TRUE;
     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;
-    }
+    /*
+     * We don't actually open a local socket to the X server just yet.
+     * Instead, we'll wait until we see the incoming authentication
+     * data, which may tell us we have to divert this X forwarding
+     * channel to a connection-sharing downstream rather than handling
+     * it ourself.
+     */
+    xconn->s = NULL;
 
     /*
      * See if we can make sense of the peer address we were given.
@@ -632,7 +647,8 @@ void x11_close(struct X11Connection *xconn)
        sfree(xconn->auth_data);
     }
 
-    sk_close(xconn->s);
+    if (xconn->s)
+        sk_close(xconn->s);
     sfree(xconn);
 }
 
@@ -642,7 +658,8 @@ void x11_unthrottle(struct X11Connection *xconn)
        return;
 
     xconn->throttled = 0;
-    sk_set_frozen(xconn->s, xconn->throttled || xconn->throttle_override);
+    if (xconn->s)
+        sk_set_frozen(xconn->s, xconn->throttled || xconn->throttle_override);
 }
 
 void x11_override_throttle(struct X11Connection *xconn, int enable)
@@ -651,7 +668,33 @@ void x11_override_throttle(struct X11Connection *xconn, int enable)
        return;
 
     xconn->throttle_override = enable;
-    sk_set_frozen(xconn->s, xconn->throttled || xconn->throttle_override);
+    if (xconn->s)
+        sk_set_frozen(xconn->s, xconn->throttled || xconn->throttle_override);
+}
+
+static void x11_send_init_error(struct X11Connection *xconn,
+                                const char *err_message)
+{
+    char *full_message;
+    int msglen, msgsize;
+    unsigned char *reply;
+
+    full_message = dupprintf("%s X11 proxy: %s\n", appname, err_message);
+
+    msglen = strlen(full_message);
+    reply = snewn(8 + msglen+1 + 4, unsigned char); /* include zero */
+    msgsize = (msglen + 3) & ~3;
+    reply[0] = 0;             /* failure */
+    reply[1] = msglen;        /* length of reason string */
+    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, full_message, msglen);
+    sshfwd_write(xconn->c, (char *)reply, 8 + msgsize);
+    sshfwd_write_eof(xconn->c);
+    xconn->no_data_sent_to_x_client = FALSE;
+    sfree(reply);
+    sfree(full_message);
 }
 
 /*
@@ -701,43 +744,38 @@ int x11_send(struct X11Connection *xconn, char *data, int len)
      * If we haven't verified the authorisation, do so now.
      */
     if (!xconn->verified) {
-       char *err;
+       const char *err;
+
+        assert(!xconn->s);
 
        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
-        * packet, then terminate the connection.
-        */
        if (err) {
-           char *message;
-           int msglen, msgsize;
-           unsigned char *reply;
-
-           message = dupprintf("%s X11 proxy: %s", appname, err);
-           msglen = strlen(message);
-           reply = snewn(8 + msglen+1 + 4, unsigned char); /* include zero */
-           msgsize = (msglen + 3) & ~3;
-           reply[0] = 0;              /* failure */
-           reply[1] = msglen;         /* length of reason string */
-           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(xconn->c, (char *)reply, 8 + msgsize);
-           sshfwd_write_eof(xconn->c);
-           sfree(reply);
-           sfree(message);
-           return 0;
-       }
+            x11_send_init_error(xconn, err);
+            return 0;
+        }
 
-       /*
-        * Now we know we're going to accept the connection. Strip
-        * the fake auth data, and optionally put real auth data in
-        * instead.
+        /*
+         * Now we know we're going to accept the connection. Actually
+         * connect to the X server.
+         */
+        xconn->s = new_connection(sk_addr_dup(xconn->disp->addr),
+                                  xconn->disp->realhost, xconn->disp->port, 
+                                  0, 1, 0, 0, (Plug) xconn,
+                                  sshfwd_get_conf(xconn->c));
+        if ((err = sk_socket_error(xconn->s)) != NULL) {
+            char *err_message = dupprintf("unable to connect to"
+                                          " forwarded X server: %s", err);
+            x11_send_init_error(xconn, err_message);
+            sfree(err_message);
+            return 0;
+        }
+
+        /*
+         * Strip the fake auth data, and optionally put real auth data
+        * in instead.
         */
         {
             char realauthdata[64];
@@ -796,5 +834,16 @@ int x11_send(struct X11Connection *xconn, char *data, int len)
 
 void x11_send_eof(struct X11Connection *xconn)
 {
-    sk_write_eof(xconn->s);
+    if (xconn->s) {
+        sk_write_eof(xconn->s);
+    } else {
+        /*
+         * If EOF is received from the X client before we've got to
+         * the point of actually connecting to an X server, then we
+         * should send an EOF back to the client so that the
+         * forwarded channel will be terminated.
+         */
+        if (xconn->c)
+            sshfwd_write_eof(xconn->c);
+    }
 }