* 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
/*
* 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 */
/*
* 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
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;
}
/*
/*
* 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,
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));
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 */