From 0a4022a169cfdd133882ecae233352e769685a1d Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 28 Jan 2005 11:39:45 +0000 Subject: [PATCH] Overhaul of client-side XDM-AUTHORIZATION-1: * 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 | 4 ++-- unix/unix.h | 2 +- unix/uxnet.c | 61 ++++++++++++++++++++++++++++++++++++++++-------------- windows/winstuff.h | 4 ++-- x11fwd.c | 20 ++++++++++-------- 5 files changed, 62 insertions(+), 29 deletions(-) diff --git a/mac/macstuff.h b/mac/macstuff.h index b0633c60..a4cab6e6 100644 --- a/mac/macstuff.h +++ b/mac/macstuff.h @@ -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 */ diff --git a/unix/unix.h b/unix/unix.h index 909b3d49..daf42e1c 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -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 diff --git a/unix/uxnet.c b/unix/uxnet.c index 71c45151..97dcffc9 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -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; } /* diff --git a/windows/winstuff.h b/windows/winstuff.h index 020f43b8..97e9bdc1 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -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, diff --git a/x11fwd.c b/x11fwd.c index 17ab3a25..c912e448 100644 --- 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 */ -- 2.11.0