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:
159
unix/ux_x11.c
159
unix/ux_x11.c
@ -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;
|
||||
|
23
unix/uxnet.c
23
unix/uxnet.c
@ -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
|
||||
|
@ -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.
|
||||
|
Reference in New Issue
Block a user