Introduce framework for authenticating with the local X server.
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 10 Jan 2003 18:33:35 +0000 (18:33 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 10 Jan 2003 18:33:35 +0000 (18:33 +0000)
Windows and Mac backends have acquired auth-finding functions which
do nothing; Unix backend has acquired one which actually works, so
Plink can now do X forwarding believably.
(This checkin stretches into some unlikely parts of the code because
there have been one or two knock-on effects involving `const'. Bah.)

git-svn-id: svn://svn.tartarus.org/sgt/putty@2536 cda61777-01e9-0310-a592-d414129be87e

14 files changed:
Recipe
mac/mac.c
misc.c
misc.h
network.h
proxy.c
putty.h
ssh.c
ssh.h
unix/ux_x11.c [new file with mode: 0644]
unix/uxnet.c
winmisc.c [new file with mode: 0644]
winnet.c
x11fwd.c

diff --git a/Recipe b/Recipe
index e3443c0..2416af2 100644 (file)
--- a/Recipe
+++ b/Recipe
@@ -109,7 +109,7 @@ SFTP     = sftp int64 logging
 # Miscellaneous objects appearing in all the network utilities (not
 # Pageant or PuTTYgen).
 WINMISC  = misc version winstore settings tree234 winnet proxy cmdline
-         + windefs
+         + windefs winmisc
 UXMISC   = misc version uxstore settings tree234 uxnet proxy cmdline
 MACMISC  = misc version macstore settings tree234 mtcpnet proxy
 
@@ -145,7 +145,7 @@ puttygen : [G] puttygen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version
 pterm    : [X] pterm terminal wcwidth uxucs uxmisc tree234 misc ldisc ldiscucs
          + logging uxprint settings pty be_none uxstore signal CHARSET
 
-plink    : [U] uxplink uxcons NONSSH UXSSH be_all logging UXMISC signal
+plink    : [U] uxplink uxcons NONSSH UXSSH be_all logging UXMISC signal ux_x11
 
 PuTTY    : [M] terminal wcwidth ldiscucs logging be_all mac macdlg
          + macterm macucs mac_res.rsrc testback NONSSH MACSSH MACMISC CHARSET
index a0ec60b..fe46f3f 100644 (file)
--- a/mac/mac.c
+++ b/mac/mac.c
@@ -1,4 +1,4 @@
-/* $Id: mac.c,v 1.22 2003/01/09 22:39:47 ben Exp $ */
+/* $Id: mac.c,v 1.23 2003/01/10 18:33:35 simon Exp $ */
 /*
  * Copyright (c) 1999 Ben Harris
  * All rights reserved.
@@ -740,6 +740,12 @@ int platform_default_i(char *name, int def)
     return def;
 }
 
+void platform_get_x11_auth(char *display, int *proto,
+                           unsigned char *data, int *datalen)
+{
+    /* SGT: I have no idea whether Mac X servers need anything here. */
+}
+
 /*
  * Local Variables:
  * c-file-style: "simon"
diff --git a/misc.c b/misc.c
index 496d30e..e4c6d4a 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -174,9 +174,9 @@ int bufchain_size(bufchain *ch)
     return ch->buffersize;
 }
 
-void bufchain_add(bufchain *ch, void *data, int len)
+void bufchain_add(bufchain *ch, const void *data, int len)
 {
-    char *buf = (char *)data;
+    const char *buf = (const char *)data;
 
     ch->buffersize += len;
 
diff --git a/misc.h b/misc.h
index 21540a3..456cda0 100644 (file)
--- a/misc.h
+++ b/misc.h
@@ -28,7 +28,7 @@ typedef struct bufchain_tag {
 void bufchain_init(bufchain *ch);
 void bufchain_clear(bufchain *ch);
 int bufchain_size(bufchain *ch);
-void bufchain_add(bufchain *ch, void *data, int len);
+void bufchain_add(bufchain *ch, const void *data, int len);
 void bufchain_prefix(bufchain *ch, void **data, int *len);
 void bufchain_consume(bufchain *ch, int len);
 void bufchain_fetch(bufchain *ch, void *data, int len);
index e9ad518..673831f 100644 (file)
--- a/network.h
+++ b/network.h
@@ -24,8 +24,8 @@ struct socket_function_table {
     /* if p is NULL, it doesn't change the plug */
     /* but it does return the one it's using */
     void (*close) (Socket s);
-    int (*write) (Socket s, char *data, int len);
-    int (*write_oob) (Socket s, char *data, int len);
+    int (*write) (Socket s, const char *data, int len);
+    int (*write_oob) (Socket s, const char *data, int len);
     void (*flush) (Socket s);
     void (*set_private_ptr) (Socket s, void *ptr);
     void *(*get_private_ptr) (Socket s);
diff --git a/proxy.c b/proxy.c
index ce31001..a4847b9 100644 (file)
--- a/proxy.c
+++ b/proxy.c
@@ -91,7 +91,7 @@ static void sk_proxy_close (Socket s)
     sfree(ps);
 }
 
-static int sk_proxy_write (Socket s, char *data, int len)
+static int sk_proxy_write (Socket s, const char *data, int len)
 {
     Proxy_Socket ps = (Proxy_Socket) s;
 
@@ -102,7 +102,7 @@ static int sk_proxy_write (Socket s, char *data, int len)
     return sk_write(ps->sub_socket, data, len);
 }
 
-static int sk_proxy_write_oob (Socket s, char *data, int len)
+static int sk_proxy_write_oob (Socket s, const char *data, int len)
 {
     Proxy_Socket ps = (Proxy_Socket) s;
 
diff --git a/putty.h b/putty.h
index c4e6d98..6f32be3 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -691,4 +691,14 @@ extern int cmdline_tooltype;
 
 void cmdline_error(char *, ...);
 
+/*
+ * X11 auth mechanisms we know about.
+ */
+enum {
+    X11_NO_AUTH,
+    X11_MIT,                           /* MIT-MAGIC-COOKIE-1 */
+    X11_NAUTHS
+};
+extern const char *const x11_authnames[];  /* declared in x11fwd.c */
+
 #endif
diff --git a/ssh.c b/ssh.c
index eac3112..c0f06ef 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -3019,6 +3019,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt)
        logevent("Requesting X11 forwarding");
        ssh->x11auth = x11_invent_auth(proto, sizeof(proto),
                                       data, sizeof(data));
+        x11_get_real_auth(ssh->x11auth, cfg.x11_display);
        if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) {
            send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING,
                        PKT_STR, proto, PKT_STR, data,
@@ -5068,6 +5069,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
        logevent("Requesting X11 forwarding");
        ssh->x11auth = x11_invent_auth(proto, sizeof(proto),
                                       data, sizeof(data));
+        x11_get_real_auth(ssh->x11auth, cfg.x11_display);
        ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST);
        ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid);
        ssh2_pkt_addstring(ssh, "x11-req");
diff --git a/ssh.h b/ssh.h
index 659a543..0a38e94 100644 (file)
--- a/ssh.h
+++ b/ssh.h
@@ -273,6 +273,7 @@ extern void *x11_invent_auth(char *, int, char *, int);
 extern void x11_unthrottle(Socket s);
 extern void x11_override_throttle(Socket s, int enable);
 extern int x11_get_screen_number(char *display);
+void x11_get_real_auth(void *authv, char *display);
 
 Bignum copybn(Bignum b);
 Bignum bn_power_2(int n);
diff --git a/unix/ux_x11.c b/unix/ux_x11.c
new file mode 100644 (file)
index 0000000..7753c85
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * ux_x11.c: fetch local auth data for X forwarding.
+ */
+
+#include <ctype.h>
+#include <unistd.h>
+#include "putty.h"
+
+void platform_get_x11_auth(char *display, int *protocol,
+                           unsigned char *data, int *datalen)
+{
+    FILE *fp;
+    char *command;
+    int maxsize = *datalen;
+    char *localbuf;
+
+    command = dupprintf("xauth list %s 2>/dev/null", display);
+    fp = popen(command, "r");
+    sfree(command);
+
+    if (!fp)
+        return;                        /* assume no auth */
+
+    localbuf = smalloc(maxsize);
+
+    while (1) {
+        /*
+         * Read a line from stdin, and attempt to parse it into a
+         * display name (ignored), auth protocol, and auth string.
+         */
+        int c, i, hexdigit, proto;
+        char protoname[64];
+
+        /* Skip the display name. */
+        while (c = getc(fp), c != EOF && c != '\n' && !isspace(c));
+        if (c == EOF) break;
+        if (c == '\n') continue;
+
+        /* Skip white space. */
+        while (c != EOF && c != '\n' && isspace(c))
+            c = getc(fp);
+        if (c == EOF) break;
+        if (c == '\n') continue;
+
+        /* Read the auth protocol name, and see if it matches any we
+         * know about. */
+        i = 0;
+        while (c != EOF && c != '\n' && !isspace(c)) {
+            if (i < lenof(protoname)-1) protoname[i++] = c;
+            c = getc(fp);
+        }
+        protoname[i] = '\0';
+
+        for (i = X11_NO_AUTH; ++i < X11_NAUTHS ;) {
+            if (!strcmp(protoname, x11_authnames[i]))
+                break;
+        }
+        if (i >= X11_NAUTHS || i <= proto) {
+            /* Unrecognised protocol name, or a worse one than we already have.
+            * Skip this line. */
+            while (c != EOF && c != '\n')
+                c = getc(fp);
+            if (c == EOF) break;
+        }
+        proto = i;
+
+        /* Skip white space. */
+        while (c != EOF && c != '\n' && isspace(c))
+            c = getc(fp);
+        if (c == EOF) break;
+        if (c == '\n') continue;
+
+        /*
+         * Now grab pairs of hex digits and shove them into `data'.
+         */
+        i = 0;
+        hexdigit = -1;
+        while (c != EOF && c != '\n') {
+            int hexval = -1;
+            if (c >= 'A' && c <= 'F')
+                hexval = c + 10 - 'A';
+            if (c >= 'a' && c <= 'f')
+                hexval = c + 10 - 'a';
+            if (c >= '0' && c <= '9')
+                hexval = c - '0';
+            if (hexval >= 0) {
+                if (hexdigit >= 0) {
+                    hexdigit = (hexdigit << 4) + hexval;
+                    if (i < maxsize)
+                        localbuf[i++] = hexdigit;
+                    hexdigit = -1;
+                } else
+                    hexdigit = hexval;
+            }
+            c = getc(fp);
+        }
+
+        *datalen = i;
+        *protocol = proto;
+       memcpy(data, localbuf, i);
+
+       /* Nonetheless, continue looping round; we might find a better one. */
+    }
+    pclose(fp);
+    sfree(localbuf);
+}
index 26f32be..722ab47 100644 (file)
@@ -298,8 +298,8 @@ static void sk_tcp_flush(Socket s)
 }
 
 static void sk_tcp_close(Socket s);
-static int sk_tcp_write(Socket s, char *data, int len);
-static int sk_tcp_write_oob(Socket s, char *data, int len);
+static int sk_tcp_write(Socket s, const char *data, int len);
+static int sk_tcp_write_oob(Socket s, const char *data, int len);
 static void sk_tcp_set_private_ptr(Socket s, void *ptr);
 static void *sk_tcp_get_private_ptr(Socket s);
 static void sk_tcp_set_frozen(Socket s, int is_frozen);
@@ -726,7 +726,7 @@ void try_send(Actual_Socket s)
     }
 }
 
-static int sk_tcp_write(Socket sock, char *buf, int len)
+static int sk_tcp_write(Socket sock, const char *buf, int len)
 {
     Actual_Socket s = (Actual_Socket) sock;
 
@@ -744,7 +744,7 @@ static int sk_tcp_write(Socket sock, char *buf, int len)
     return bufchain_size(&s->output_data);
 }
 
-static int sk_tcp_write_oob(Socket sock, char *buf, int len)
+static int sk_tcp_write_oob(Socket sock, const char *buf, int len)
 {
     Actual_Socket s = (Actual_Socket) sock;
 
diff --git a/winmisc.c b/winmisc.c
new file mode 100644 (file)
index 0000000..a4f666e
--- /dev/null
+++ b/winmisc.c
@@ -0,0 +1,14 @@
+/*
+ * winmisc.c: miscellaneous Windows-specific things.
+ */
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "putty.h"
+
+void platform_get_x11_auth(char *display, int *proto,
+                           unsigned char *data, int *datalen)
+{
+    /* We don't support this at all under Windows. */
+}
index 4bebe6d..f2e8454 100644 (file)
--- a/winnet.c
+++ b/winnet.c
@@ -460,8 +460,8 @@ static void sk_tcp_flush(Socket s)
 }
 
 static void sk_tcp_close(Socket s);
-static int sk_tcp_write(Socket s, char *data, int len);
-static int sk_tcp_write_oob(Socket s, char *data, int len);
+static int sk_tcp_write(Socket s, const char *data, int len);
+static int sk_tcp_write_oob(Socket s, const char *data, int len);
 static void sk_tcp_set_private_ptr(Socket s, void *ptr);
 static void *sk_tcp_get_private_ptr(Socket s);
 static void sk_tcp_set_frozen(Socket s, int is_frozen);
@@ -924,7 +924,7 @@ void try_send(Actual_Socket s)
     }
 }
 
-static int sk_tcp_write(Socket sock, char *buf, int len)
+static int sk_tcp_write(Socket sock, const char *buf, int len)
 {
     Actual_Socket s = (Actual_Socket) sock;
 
@@ -942,7 +942,7 @@ static int sk_tcp_write(Socket sock, char *buf, int len)
     return bufchain_size(&s->output_data);
 }
 
-static int sk_tcp_write_oob(Socket sock, char *buf, int len)
+static int sk_tcp_write_oob(Socket sock, const char *buf, int len)
 {
     Actual_Socket s = (Actual_Socket) sock;
 
index 80e0eb5..184a330 100644 (file)
--- a/x11fwd.c
+++ b/x11fwd.c
@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <assert.h>
 
 #include "putty.h"
 #include "ssh.h"
 #define PUT_16BIT(endian, cp, val) \
   (endian=='B' ? PUT_16BIT_MSB_FIRST(cp, val) : PUT_16BIT_LSB_FIRST(cp, val))
 
+const char *const x11_authnames[] = {
+    "", "MIT-MAGIC-COOKIE-1"
+};
+
 struct X11Auth {
-    unsigned char data[64];
-    int len;
+    unsigned char fakedata[64], realdata[64];
+    int fakeproto, realproto;
+    int fakelen, reallen;
 };
 
+extern void platform_get_x11_auth(char *display, int *proto,
+                                  unsigned char *data, int *datalen);
+
 struct X11Private {
     const struct plug_function_table *fn;
     /* the above variable absolutely *must* be the first in this structure */
@@ -76,30 +85,51 @@ void *x11_invent_auth(char *proto, int protomaxlen,
     char ourdata[64];
     int i;
 
+    auth->fakeproto = X11_MIT;
+
     /* MIT-MAGIC-COOKIE-1. Cookie size is 128 bits (16 bytes). */
-    auth->len = 16;
+    auth->fakelen = 16;
     for (i = 0; i < 16; i++)
-       auth->data[i] = random_byte();
+       auth->fakedata[i] = random_byte();
 
     /* Now format for the recipient. */
-    strncpy(proto, "MIT-MAGIC-COOKIE-1", protomaxlen);
+    strncpy(proto, x11_authnames[auth->fakeproto], protomaxlen);
     ourdata[0] = '\0';
-    for (i = 0; i < auth->len; i++)
-       sprintf(ourdata + strlen(ourdata), "%02x", auth->data[i]);
+    for (i = 0; i < auth->fakelen; i++)
+       sprintf(ourdata + strlen(ourdata), "%02x", auth->fakedata[i]);
     strncpy(data, ourdata, datamaxlen);
 
     return auth;
 }
 
+/*
+ * Fetch the real auth data for a given display string, and store
+ * it in an X11Auth structure. Returns NULL on success, or an error
+ * string.
+ */
+void x11_get_real_auth(void *authv, char *display)
+{
+    struct X11Auth *auth = (struct X11Auth *)authv;
+
+    auth->realproto = X11_NO_AUTH;     /* in case next call does nothing */
+
+    auth->reallen = sizeof(auth->realdata);
+    platform_get_x11_auth(display, &auth->realproto,
+                          auth->realdata, &auth->reallen);
+}
+
 static int x11_verify(struct X11Auth *auth,
                      char *proto, unsigned char *data, int dlen)
 {
-    if (strcmp(proto, "MIT-MAGIC-COOKIE-1") != 0)
+    if (strcmp(proto, x11_authnames[auth->fakeproto]) != 0)
        return 0;                      /* wrong protocol attempted */
-    if (dlen != auth->len)
-       return 0;                      /* cookie was wrong length */
-    if (memcmp(auth->data, data, dlen) != 0)
-       return 0;                      /* cookie was wrong cookie! */
+    if (auth->fakeproto == X11_MIT) {
+        if (dlen != auth->fakelen)
+            return 0;                 /* cookie was wrong length */
+        if (memcmp(auth->fakedata, data, dlen) != 0)
+            return 0;                 /* cookie was wrong cookie! */
+    }
+    /* implement other protocols here if ever required */
     return 1;
 }
 
@@ -344,12 +374,36 @@ int x11_send(Socket s, char *data, int len)
 
        /*
         * Now we know we're going to accept the connection. Strip
-        * the auth data. (TODO: if we ever work out how, we should
-        * replace some real auth data in here.)
+        * the fake auth data, and optionally put real auth data in
+        * instead.
         */
-       PUT_16BIT(pr->firstpkt[0], pr->firstpkt + 6, 0);        /* auth proto */
-       PUT_16BIT(pr->firstpkt[0], pr->firstpkt + 8, 0);        /* auth data */
-       sk_write(s, (char *)pr->firstpkt, 12);
+        {
+            char realauthdata[64];
+            int realauthlen = 0;
+            int authstrlen = strlen(x11_authnames[pr->auth->realproto]);
+            static const char zeroes[4] = { 0,0,0,0 };
+
+            if (pr->auth->realproto == X11_MIT) {
+                assert(pr->auth->reallen <= lenof(realauthdata));
+                realauthlen = pr->auth->reallen;
+                memcpy(realauthdata, pr->auth->realdata, realauthlen);
+            }
+            /* 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);
+        
+            sk_write(s, (char *)pr->firstpkt, 12);
+
+            if (authstrlen) {
+                sk_write(s, x11_authnames[pr->auth->realproto], authstrlen);
+                sk_write(s, zeroes, 3 & (-authstrlen));
+            }
+            if (realauthlen) {
+                sk_write(s, realauthdata, realauthlen);
+                sk_write(s, zeroes, 3 & (-realauthlen));
+            }
+        }
        pr->verified = 1;
     }