Introduce framework for authenticating with the local X server.
[u/mdw/putty] / unix / ux_x11.c
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);
+}