Overhaul of client-side XDM-AUTHORIZATION-1:
authorben <ben@cda61777-01e9-0310-a592-d414129be87e>
Fri, 28 Jan 2005 11:39:45 +0000 (11:39 +0000)
committerben <ben@cda61777-01e9-0310-a592-d414129be87e>
Fri, 28 Jan 2005 11:39:45 +0000 (11:39 +0000)
* Make sk_getxdmdata() return an arbitrary string rather than two integers.
  This better matches the spec, even if the current version always returns
  six bytes
* On Unix, for PF_UNIX sockets, return a counter rather than a constant along
  with the PID.  This should allow multiple clients to connect within one
  second, and is what Xlib does.
* On Unix, interpret AF_INET6 addresses like Xlib does, returning the
  embedded IPv4 address for v4-mapped addresses, and six bytes of zeroes
  otherwise.  The latter is silly, but if I'm going to do anything more sane
  I need to check that X servers won't reject it.

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

mac/macstuff.h
unix/unix.h
unix/uxnet.c
windows/winstuff.h
x11fwd.c

index b0633c6..a4cab6e 100644 (file)
@@ -48,9 +48,9 @@ struct FontSpec {
 /*
  * sk_getxdmdata() does not exist under the Mac (SGT: I have no
  * idea whatsoever how to write it, and furthermore I'm unconvinced
- * it's necessary), so it's a macro which always returns FALSE.
+ * it's necessary), so it's a macro which always returns NULL.
  */
-#define sk_getxdmdata(socket, ip, port) (0)
+#define sk_getxdmdata(socket, lenp) (NULL)
 
 /* To make it compile */
 
index 909b3d4..daf42e1 100644 (file)
@@ -126,7 +126,7 @@ int init_ucs(struct unicode_data *ucsdata, char *line_codepage,
 /*
  * Spare function exported directly from uxnet.c.
  */
-int sk_getxdmdata(void *sock, unsigned long *ip, int *port);
+void *sk_getxdmdata(void *sock, int *lenp);
 
 /*
  * General helpful Unix stuff: more helpful version of the FD_SET
index 71c4515..97dcffc 100644 (file)
@@ -811,42 +811,73 @@ static void sk_tcp_close(Socket sock)
     sfree(s);
 }
 
-int sk_getxdmdata(void *sock, unsigned long *ip, int *port)
+#define PUT_32BIT_MSB_FIRST(cp, value) ( \
+  (cp)[0] = (char)((value) >> 24), \
+  (cp)[1] = (char)((value) >> 16), \
+  (cp)[2] = (char)((value) >> 8), \
+  (cp)[3] = (char)(value) )
+
+#define PUT_16BIT_MSB_FIRST(cp, value) ( \
+  (cp)[0] = (char)((value) >> 8), \
+  (cp)[1] = (char)(value) )
+
+void *sk_getxdmdata(void *sock, int *lenp)
 {
     Actual_Socket s = (Actual_Socket) sock;
+#ifdef NO_IPV6
     struct sockaddr_in addr;
+#else
+    struct sockaddr_storage addr;
+    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
+#endif
+    struct sockaddr *sa = (struct sockaddr *)&addr;
+    struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
     socklen_t addrlen;
+    char *buf;
+    static unsigned int unix_addr = 0xFFFFFFFF;
 
     /*
      * We must check that this socket really _is_ an Actual_Socket.
      */
     if (s->fn != &tcp_fn_table)
-       return 0;                      /* failure */
+       return NULL;                   /* failure */
 
     addrlen = sizeof(addr);
-    if (getsockname(s->s, (struct sockaddr *)&addr, &addrlen) < 0)
-       return 0;
-    switch(addr.sin_family) {
+    if (getsockname(s->s, sa, &addrlen) < 0)
+       return NULL;
+    switch(sa->sa_family) {
       case AF_INET:
-       *ip = ntohl(addr.sin_addr.s_addr);
-       *port = ntohs(addr.sin_port);
+       *lenp = 6;
+       buf = snewn(*lenp, char);
+       PUT_32BIT_MSB_FIRST(buf, ntohl(sin->sin_addr.s_addr));
+       PUT_16BIT_MSB_FIRST(buf+4, ntohs(sin->sin_port));
+       break;
+#ifndef NO_IPV6
+    case AF_INET6:
+       *lenp = 6;
+       buf = snewn(*lenp, char);
+       if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+           memcpy(buf, sin6->sin6_addr.s6_addr + 12, 4);
+           PUT_16BIT_MSB_FIRST(buf+4, ntohs(sin6->sin6_port));
+       } else
+           /* This is stupid, but it's what XLib does. */
+           memset(buf, 0, 6);
        break;
+#endif
       case AF_UNIX:
-       /*
-        * For a Unix socket, we return 0xFFFFFFFF for the IP address and
-        * our current pid for the port. Bizarre, but such is life.
-        */
-       *ip = ntohl(0xFFFFFFFF);
-       *port = getpid();
+       *lenp = 6;
+       buf = snewn(*lenp, char);
+       PUT_32BIT_MSB_FIRST(buf, unix_addr--);
+        PUT_16BIT_MSB_FIRST(buf+4, getpid());
        break;
 
        /* XXX IPV6 */
 
       default:
-       return 0;
+       return NULL;
     }
 
-    return 1;
+    return buf;
 }
 
 /*
index 020f43b..97e9bdc 100644 (file)
@@ -117,11 +117,11 @@ GLOBAL void *logctx;
 /*
  * sk_getxdmdata() does not exist under Windows (not that I
  * couldn't write it if I wanted to, but I haven't bothered), so
- * it's a macro which always returns FALSE. With any luck this will
+ * it's a macro which always returns NULL. With any luck this will
  * cause the compiler to notice it can optimise away the
  * implementation of XDM-AUTHORIZATION-1 in x11fwd.c :-)
  */
-#define sk_getxdmdata(socket, ip, port) (0)
+#define sk_getxdmdata(socket, lenp) (NULL)
 
 /*
  * File-selector filter strings used in the config box. On Windows,
index 17ab3a2..c912e44 100644 (file)
--- a/x11fwd.c
+++ b/x11fwd.c
@@ -481,9 +481,9 @@ int x11_send(Socket s, char *data, int len)
             char realauthdata[64];
             int realauthlen = 0;
             int authstrlen = strlen(x11_authnames[pr->auth->realproto]);
-           unsigned long ip;
-           int port;
+           int buflen;
             static const char zeroes[4] = { 0,0,0,0 };
+           void *buf;
 
             if (pr->auth->realproto == X11_MIT) {
                 assert(pr->auth->reallen <= lenof(realauthdata));
@@ -491,17 +491,19 @@ int x11_send(Socket s, char *data, int len)
                 memcpy(realauthdata, pr->auth->realdata, realauthlen);
             } else if (pr->auth->realproto == X11_XDM &&
                       pr->auth->reallen == 16 &&
-                      sk_getxdmdata(s, &ip, &port)) {
+                      (buf = sk_getxdmdata(s, &buflen))) {
                time_t t;
-                realauthlen = 24;
-               memset(realauthdata, 0, 24);
+                realauthlen = (buflen+12+7) & ~7;
+               assert(realauthlen <= lenof(realauthdata));
+               memset(realauthdata, 0, realauthlen);
                memcpy(realauthdata, pr->auth->realdata, 8);
-               PUT_32BIT_MSB_FIRST(realauthdata+8, ip);
-               PUT_16BIT_MSB_FIRST(realauthdata+12, port);
+               memcpy(realauthdata+8, buf, buflen);
                t = time(NULL);
-               PUT_32BIT_MSB_FIRST(realauthdata+14, t);
+               PUT_32BIT_MSB_FIRST(realauthdata+8+buflen, t);
                des_encrypt_xdmauth(pr->auth->realdata+9,
-                                   (unsigned char *)realauthdata, 24);
+                                   (unsigned char *)realauthdata,
+                                   realauthlen);
+               sfree(buf);
            }
             /* implement other auth methods here if required */