mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
Rewrite .Xauthority parsing using BinarySource.
This rewrite replaces a particularly hairy macro-based system.
This commit is contained in:
parent
ae3edcdfc0
commit
5acd523ae6
103
x11fwd.c
103
x11fwd.c
@ -429,15 +429,28 @@ static const char *x11_verify(unsigned long peer_ip, int peer_port,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ptrlen BinarySource_get_string_xauth(BinarySource *src)
|
||||||
|
{
|
||||||
|
size_t len = get_uint16(src);
|
||||||
|
return get_data(src, len);
|
||||||
|
}
|
||||||
|
#define get_string_xauth(src) \
|
||||||
|
BinarySource_get_string_xauth(BinarySource_UPCAST(src))
|
||||||
|
|
||||||
void x11_get_auth_from_authfile(struct X11Display *disp,
|
void x11_get_auth_from_authfile(struct X11Display *disp,
|
||||||
const char *authfilename)
|
const char *authfilename)
|
||||||
{
|
{
|
||||||
FILE *authfp;
|
FILE *authfp;
|
||||||
char *buf, *ptr, *str[4];
|
char *buf;
|
||||||
int len[4];
|
int size;
|
||||||
|
BinarySource src[1];
|
||||||
int family, protocol;
|
int family, protocol;
|
||||||
|
ptrlen addr, protoname, data;
|
||||||
|
char *displaynum_string;
|
||||||
|
int displaynum;
|
||||||
int ideal_match = FALSE;
|
int ideal_match = FALSE;
|
||||||
char *ourhostname;
|
char *ourhostname;
|
||||||
|
const size_t MAX_RECORD_SIZE = 0x80, BUF_SIZE = 2 * MAX_RECORD_SIZE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Normally we should look for precisely the details specified in
|
* Normally we should look for precisely the details specified in
|
||||||
@ -468,29 +481,41 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
|||||||
|
|
||||||
ourhostname = get_hostname();
|
ourhostname = get_hostname();
|
||||||
|
|
||||||
/* Records in .Xauthority contain four strings of up to 64K each */
|
/*
|
||||||
buf = snewn(65537 * 4, char);
|
* Allocate enough space to hold two maximally sized records, so
|
||||||
|
* that a full record can start anywhere in the first half. That
|
||||||
|
* way we avoid the accidentally-quadratic algorithm that would
|
||||||
|
* arise if we moved everything to the front of the buffer after
|
||||||
|
* consuming each record; instead, we only move everything to the
|
||||||
|
* front after our current position gets past the half-way mark.
|
||||||
|
* Before then, there's no need to move anyway; so this guarantees
|
||||||
|
* linear time, in that every byte written into this buffer moves
|
||||||
|
* at most once (because every move is from the second half of the
|
||||||
|
* buffer to the first half).
|
||||||
|
*/
|
||||||
|
buf = snewn(BUF_SIZE, char);
|
||||||
|
size = fread(buf, 1, BUF_SIZE, authfp);
|
||||||
|
BinarySource_BARE_INIT(src, buf, size);
|
||||||
|
|
||||||
while (!ideal_match) {
|
while (!ideal_match) {
|
||||||
int c, i, j, match = FALSE;
|
int match = FALSE;
|
||||||
|
|
||||||
#define GET do { c = fgetc(authfp); if (c == EOF) goto done; c = (unsigned char)c; } while (0)
|
if (src->pos >= MAX_RECORD_SIZE) {
|
||||||
/* Expect a big-endian 2-byte number giving address family */
|
size -= src->pos;
|
||||||
GET; family = c;
|
memcpy(buf, buf + src->pos, size);
|
||||||
GET; family = (family << 8) | c;
|
size += fread(buf + size, 1, BUF_SIZE - size, authfp);
|
||||||
/* Then expect four strings, each composed of a big-endian 2-byte
|
BinarySource_BARE_INIT(src, buf, size);
|
||||||
* length field followed by that many bytes of data */
|
}
|
||||||
ptr = buf;
|
|
||||||
for (i = 0; i < 4; i++) {
|
family = get_uint16(src);
|
||||||
GET; len[i] = c;
|
addr = get_string_xauth(src);
|
||||||
GET; len[i] = (len[i] << 8) | c;
|
displaynum_string = mkstr(get_string_xauth(src));
|
||||||
str[i] = ptr;
|
displaynum = atoi(displaynum_string);
|
||||||
for (j = 0; j < len[i]; j++) {
|
sfree(displaynum_string);
|
||||||
GET; *ptr++ = c;
|
protoname = get_string_xauth(src);
|
||||||
}
|
data = get_string_xauth(src);
|
||||||
*ptr++ = '\0';
|
if (get_err(src))
|
||||||
}
|
break;
|
||||||
#undef GET
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we have a full X authority record in memory. See
|
* Now we have a full X authority record in memory. See
|
||||||
@ -504,7 +529,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
|||||||
* connect to the display. 0 means IPv4; 6 means IPv6;
|
* connect to the display. 0 means IPv4; 6 means IPv6;
|
||||||
* 256 means Unix-domain sockets.
|
* 256 means Unix-domain sockets.
|
||||||
*
|
*
|
||||||
* - str[0] is the network address itself. For IPv4 and
|
* - 'addr' is the network address itself. For IPv4 and
|
||||||
* IPv6, this is a string of binary data of the
|
* IPv6, this is a string of binary data of the
|
||||||
* appropriate length (respectively 4 and 16 bytes)
|
* appropriate length (respectively 4 and 16 bytes)
|
||||||
* representing the address in big-endian format, e.g.
|
* representing the address in big-endian format, e.g.
|
||||||
@ -515,24 +540,23 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
|||||||
* authority entries for Unix-domain displays on
|
* authority entries for Unix-domain displays on
|
||||||
* several machines without them clashing).
|
* several machines without them clashing).
|
||||||
*
|
*
|
||||||
* - str[1] is the display number. I've no idea why
|
* - 'displaynum' is the display number. I've no idea why
|
||||||
* .Xauthority stores this as a string when it has a
|
* .Xauthority stores this as a string when it has a
|
||||||
* perfectly good integer format, but there we go.
|
* perfectly good integer format, but there we go.
|
||||||
*
|
*
|
||||||
* - str[2] is the authorisation method, encoded as its
|
* - 'protoname' is the authorisation protocol, encoded as
|
||||||
* canonical string name (i.e. "MIT-MAGIC-COOKIE-1",
|
* its canonical string name (i.e. "MIT-MAGIC-COOKIE-1",
|
||||||
* "XDM-AUTHORIZATION-1" or something we don't
|
* "XDM-AUTHORIZATION-1" or something we don't recognise).
|
||||||
* recognise).
|
|
||||||
*
|
*
|
||||||
* - str[3] is the actual authorisation data, stored in
|
* - 'data' is the actual authorisation data, stored in
|
||||||
* binary form.
|
* binary form.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (disp->displaynum < 0 || disp->displaynum != atoi(str[1]))
|
if (disp->displaynum < 0 || disp->displaynum != displaynum)
|
||||||
continue; /* not the one */
|
continue; /* not the one */
|
||||||
|
|
||||||
for (protocol = 1; protocol < lenof(x11_authnames); protocol++)
|
for (protocol = 1; protocol < lenof(x11_authnames); protocol++)
|
||||||
if (!strcmp(str[2], x11_authnames[protocol]))
|
if (ptrlen_eq_string(protoname, x11_authnames[protocol]))
|
||||||
break;
|
break;
|
||||||
if (protocol == lenof(x11_authnames))
|
if (protocol == lenof(x11_authnames))
|
||||||
continue; /* don't recognise this protocol, look for another */
|
continue; /* don't recognise this protocol, look for another */
|
||||||
@ -543,7 +567,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
|||||||
sk_addrtype(disp->addr) == ADDRTYPE_IPV4) {
|
sk_addrtype(disp->addr) == ADDRTYPE_IPV4) {
|
||||||
char buf[4];
|
char buf[4];
|
||||||
sk_addrcopy(disp->addr, buf);
|
sk_addrcopy(disp->addr, buf);
|
||||||
if (len[0] == 4 && !memcmp(str[0], buf, 4)) {
|
if (addr.len == 4 && !memcmp(addr.ptr, buf, 4)) {
|
||||||
match = TRUE;
|
match = TRUE;
|
||||||
/* If this is a "localhost" entry, note it down
|
/* If this is a "localhost" entry, note it down
|
||||||
* but carry on looking for a Unix-domain entry. */
|
* but carry on looking for a Unix-domain entry. */
|
||||||
@ -556,7 +580,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
|||||||
sk_addrtype(disp->addr) == ADDRTYPE_IPV6) {
|
sk_addrtype(disp->addr) == ADDRTYPE_IPV6) {
|
||||||
char buf[16];
|
char buf[16];
|
||||||
sk_addrcopy(disp->addr, buf);
|
sk_addrcopy(disp->addr, buf);
|
||||||
if (len[0] == 16 && !memcmp(str[0], buf, 16)) {
|
if (addr.len == 16 && !memcmp(addr.ptr, buf, 16)) {
|
||||||
match = TRUE;
|
match = TRUE;
|
||||||
ideal_match = !localhost;
|
ideal_match = !localhost;
|
||||||
}
|
}
|
||||||
@ -564,7 +588,7 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
|||||||
break;
|
break;
|
||||||
case 256: /* Unix-domain / localhost */
|
case 256: /* Unix-domain / localhost */
|
||||||
if ((disp->unixdomain || localhost)
|
if ((disp->unixdomain || localhost)
|
||||||
&& ourhostname && !strcmp(ourhostname, str[0]))
|
&& ourhostname && ptrlen_eq_string(addr, ourhostname))
|
||||||
/* A matching Unix-domain socket is always the best
|
/* A matching Unix-domain socket is always the best
|
||||||
* match. */
|
* match. */
|
||||||
match = ideal_match = TRUE;
|
match = ideal_match = TRUE;
|
||||||
@ -575,15 +599,14 @@ void x11_get_auth_from_authfile(struct X11Display *disp,
|
|||||||
/* Current best guess -- may be overridden if !ideal_match */
|
/* Current best guess -- may be overridden if !ideal_match */
|
||||||
disp->localauthproto = protocol;
|
disp->localauthproto = protocol;
|
||||||
sfree(disp->localauthdata); /* free previous guess, if any */
|
sfree(disp->localauthdata); /* free previous guess, if any */
|
||||||
disp->localauthdata = snewn(len[3], unsigned char);
|
disp->localauthdata = snewn(data.len, unsigned char);
|
||||||
memcpy(disp->localauthdata, str[3], len[3]);
|
memcpy(disp->localauthdata, data.ptr, data.len);
|
||||||
disp->localauthdatalen = len[3];
|
disp->localauthdatalen = data.len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
|
||||||
fclose(authfp);
|
fclose(authfp);
|
||||||
smemclr(buf, 65537 * 4);
|
smemclr(buf, 2 * MAX_RECORD_SIZE);
|
||||||
sfree(buf);
|
sfree(buf);
|
||||||
sfree(ourhostname);
|
sfree(ourhostname);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user