1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-06-30 11:02:48 -05:00

Revamp of the local X11 connection code. We now parse X display

strings more rigorously, and then we look up the local X authority
data in .Xauthority _ourself_ rather than delegating to an external
xauth program. This is (negligibly) more efficient on Unix, assuming
I haven't got it wrong in some subtle way, but its major benefit is
that we can now support X authority lookups on Windows as well
provided the user points us at an appropriate X authority file in
the standard format. A new Windows-specific config option has been
added for this purpose.

[originally from svn r8305]
This commit is contained in:
Simon Tatham
2008-11-17 18:38:09 +00:00
parent 0cef8a897d
commit ca6fc3a4da
15 changed files with 534 additions and 313 deletions

View File

@ -5,117 +5,66 @@
#include <ctype.h>
#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
#include "putty.h"
#include "ssh.h"
#include "network.h"
void platform_get_x11_auth(char *display, int *protocol,
unsigned char *data, int *datalen)
void platform_get_x11_auth(struct X11Display *disp, const Config *cfg)
{
FILE *fp;
char *command;
int maxsize = *datalen;
char *localbuf;
int proto = -1;
char *xauthfile;
int needs_free;
display = x11_display(display);
/*
* Normally we should run `xauth list DISPLAYNAME'. However,
* there's an oddity when the display is local: the display
* `localhost:0' (or `:0') should become just `:0'.
* Upgrade an IP-style localhost display to a Unix-socket
* display.
*/
if (!strncmp(display, "localhost:", 10)
|| !strncmp(display, "unix:", 5))
command = dupprintf("xauth list %s 2>/dev/null",
strchr(display, ':'));
else
command = dupprintf("xauth list %s 2>/dev/null", display);
sfree(display);
fp = popen(command, "r");
sfree(command);
if (!fp)
return; /* assume no auth */
localbuf = snewn(maxsize, char);
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;
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. */
if (!disp->unixdomain && sk_address_is_local(disp->addr)) {
sk_addr_free(disp->addr);
disp->unixdomain = TRUE;
disp->addr = platform_get_x11_unix_address(NULL, disp->displaynum);
disp->realhost = dupprintf("unix:%d", disp->displaynum);
disp->port = 0;
}
/*
* Set the hostname for Unix-socket displays, so that we'll
* look it up correctly in the X authority file.
*/
if (disp->unixdomain) {
int len;
sfree(disp->hostname);
len = 128;
do {
len *= 2;
disp->hostname = snewn(len, char);
if (gethostname(disp->hostname, len) < 0) {
disp->hostname = NULL;
return;
}
} while (strlen(disp->hostname) >= len-1);
}
/*
* Find the .Xauthority file.
*/
needs_free = FALSE;
xauthfile = getenv("XAUTHORITY");
if (!xauthfile) {
xauthfile = getenv("HOME");
if (xauthfile) {
xauthfile = dupcat(xauthfile, "/.Xauthority", NULL);
needs_free = TRUE;
}
}
if (xauthfile) {
x11_get_auth_from_authfile(disp, xauthfile);
if (needs_free)
sfree(xauthfile);
}
pclose(fp);
sfree(localbuf);
}
const int platform_uses_x11_unix_by_default = TRUE;

View File

@ -1390,8 +1390,7 @@ int net_service_lookup(char *service)
return 0;
}
SockAddr platform_get_x11_unix_address(const char *display, int displaynum,
char **canonicalname)
SockAddr platform_get_x11_unix_address(const char *sockpath, int displaynum)
{
SockAddr ret = snew(struct SockAddr_tag);
int n;
@ -1399,26 +1398,22 @@ SockAddr platform_get_x11_unix_address(const char *display, int displaynum,
memset(ret, 0, sizeof *ret);
ret->superfamily = UNIX;
/*
* Mac OS X Leopard uses an innovative X display naming
* convention in which the entire display name is the path to
* the Unix socket, including the trailing :0 which only
* _looks_ like a display number. Heuristically, I think
* detecting this by means of a leading slash ought to be
* adequate.
* In special circumstances (notably Mac OS X Leopard), we'll
* have been passed an explicit Unix socket path.
*/
if (display[0] == '/') {
if (sockpath) {
n = snprintf(ret->hostname, sizeof ret->hostname,
"%s", display);
"%s", sockpath);
} else {
n = snprintf(ret->hostname, sizeof ret->hostname,
"%s%d", X11_UNIX_PATH, displaynum);
}
if(n < 0)
if (n < 0)
ret->error = "snprintf failed";
else if(n >= sizeof ret->hostname)
else if (n >= sizeof ret->hostname)
ret->error = "X11 UNIX name too long";
else
*canonicalname = dupstr(ret->hostname);
#ifndef NO_IPV6
ret->ais = NULL;
#else

View File

@ -18,6 +18,7 @@
#endif
#include "putty.h"
#include "ssh.h"
#include "psftp.h"
#include "int64.h"
@ -33,11 +34,11 @@ char *x_get_default(const char *key)
return NULL; /* this is a stub */
}
void platform_get_x11_auth(char *display, int *protocol,
unsigned char *data, int *datalen)
void platform_get_x11_auth(struct X11Display *display, const Config *cfg)
{
/* Do nothing, therefore no auth. */
}
const int platform_uses_x11_unix_by_default = TRUE;
/*
* Default settings that are specific to PSFTP.