1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-03-22 14:39:24 -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

4
Recipe
View File

@ -302,10 +302,10 @@ U_BE_NOSSH = be_nos_s uxser nocproxy
# keywords [G] for Windows GUI app, [C] for Console app, [X] for # keywords [G] for Windows GUI app, [C] for Console app, [X] for
# X/GTK Unix app, [U] for command-line Unix app, [M] for Macintosh app. # X/GTK Unix app, [U] for command-line Unix app, [M] for Macintosh app.
putty : [G] GUITERM NONSSH WINSSH W_BE_ALL WINMISC putty.res LIBS putty : [G] GUITERM NONSSH WINSSH W_BE_ALL WINMISC winx11 putty.res LIBS
puttytel : [G] GUITERM NONSSH W_BE_NOSSH WINMISC puttytel.res LIBS puttytel : [G] GUITERM NONSSH W_BE_NOSSH WINMISC puttytel.res LIBS
plink : [C] winplink wincons NONSSH WINSSH W_BE_ALL logging WINMISC plink : [C] winplink wincons NONSSH WINSSH W_BE_ALL logging WINMISC
+ plink.res LIBS + winx11 plink.res LIBS
pscp : [C] pscp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC pscp : [C] pscp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC
+ pscp.res LIBS + pscp.res LIBS
psftp : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC psftp : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC

View File

@ -2728,6 +2728,27 @@ connections fail.
PuTTY's default is \cw{MIT-MAGIC-COOKIE-1}. If you change it, you PuTTY's default is \cw{MIT-MAGIC-COOKIE-1}. If you change it, you
should be sure you know what you're doing. should be sure you know what you're doing.
\S{config-ssh-xauthority} X authority file for local display
\cfg{winhelp-topic}{ssh.tunnels.xauthority}
If you are using X11 forwarding, the local X server to which your
forwarded connections are eventually directed may itself require
authorisation.
Some Windows X servers do not require this: they do authorisation by
simpler means, such as accepting any connection from the local
machine but not from anywhere else. However, if your X server does
require authorisation, then PuTTY needs to know what authorisation
is required.
One way in which this data might be made available is for the X
server to store it somewhere in a file which has the same format
as the Unix \c{.Xauthority} file. If this is how your Windows X
server works, then you can tell PuTTY where to find this file by
configuring this option. By default, PuTTY will not attempt to find
any authorisation for your local display.
\H{config-ssh-portfwd} \I{port forwarding}The Tunnels panel \H{config-ssh-portfwd} \I{port forwarding}The Tunnels panel
\cfg{winhelp-topic}{ssh.tunnels.portfwd} \cfg{winhelp-topic}{ssh.tunnels.portfwd}

View File

@ -572,6 +572,7 @@ struct config_tag {
int x11_forward; int x11_forward;
char x11_display[128]; char x11_display[128];
int x11_auth; int x11_auth;
Filename xauthfile;
/* port forwarding */ /* port forwarding */
int lport_acceptall; /* accept conns from hosts other than localhost */ int lport_acceptall; /* accept conns from hosts other than localhost */
int rport_acceptall; /* same for remote forwarded ports (SSH-2 only) */ int rport_acceptall; /* same for remote forwarded ports (SSH-2 only) */

View File

@ -446,6 +446,7 @@ void save_open_settings(void *sesskey, Config *cfg)
write_setting_i(sesskey, "X11Forward", cfg->x11_forward); write_setting_i(sesskey, "X11Forward", cfg->x11_forward);
write_setting_s(sesskey, "X11Display", cfg->x11_display); write_setting_s(sesskey, "X11Display", cfg->x11_display);
write_setting_i(sesskey, "X11AuthType", cfg->x11_auth); write_setting_i(sesskey, "X11AuthType", cfg->x11_auth);
write_setting_filename(sesskey, "X11AuthFile", cfg->xauthfile);
write_setting_i(sesskey, "LocalPortAcceptAll", cfg->lport_acceptall); write_setting_i(sesskey, "LocalPortAcceptAll", cfg->lport_acceptall);
write_setting_i(sesskey, "RemotePortAcceptAll", cfg->rport_acceptall); write_setting_i(sesskey, "RemotePortAcceptAll", cfg->rport_acceptall);
wmap(sesskey, "PortForwardings", cfg->portfwd, lenof(cfg->portfwd)); wmap(sesskey, "PortForwardings", cfg->portfwd, lenof(cfg->portfwd));
@ -775,6 +776,7 @@ void load_open_settings(void *sesskey, Config *cfg)
gpps(sesskey, "X11Display", "", cfg->x11_display, gpps(sesskey, "X11Display", "", cfg->x11_display,
sizeof(cfg->x11_display)); sizeof(cfg->x11_display));
gppi(sesskey, "X11AuthType", X11_MIT, &cfg->x11_auth); gppi(sesskey, "X11AuthType", X11_MIT, &cfg->x11_auth);
gppfile(sesskey, "X11AuthFile", &cfg->xauthfile);
gppi(sesskey, "LocalPortAcceptAll", 0, &cfg->lport_acceptall); gppi(sesskey, "LocalPortAcceptAll", 0, &cfg->lport_acceptall);
gppi(sesskey, "RemotePortAcceptAll", 0, &cfg->rport_acceptall); gppi(sesskey, "RemotePortAcceptAll", 0, &cfg->rport_acceptall);

50
ssh.c
View File

@ -824,7 +824,7 @@ struct ssh_tag {
Pkt_KCtx pkt_kctx; Pkt_KCtx pkt_kctx;
Pkt_ACtx pkt_actx; Pkt_ACtx pkt_actx;
void *x11auth; struct X11Display *x11disp;
int version; int version;
int conn_throttle_count; int conn_throttle_count;
@ -4578,8 +4578,8 @@ static void ssh1_smsg_x11_open(Ssh ssh, struct Packet *pktin)
c = snew(struct ssh_channel); c = snew(struct ssh_channel);
c->ssh = ssh; c->ssh = ssh;
if (x11_init(&c->u.x11.s, ssh->cfg.x11_display, c, if (x11_init(&c->u.x11.s, ssh->x11disp, c,
ssh->x11auth, NULL, -1, &ssh->cfg) != NULL) { NULL, -1, &ssh->cfg) != NULL) {
logevent("Opening X11 forward connection failed"); logevent("Opening X11 forward connection failed");
sfree(c); sfree(c);
send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
@ -4914,11 +4914,9 @@ static void do_ssh1_connection(Ssh ssh, unsigned char *in, int inlen,
} }
if (ssh->cfg.x11_forward) { if (ssh->cfg.x11_forward) {
char proto[20], data[64];
logevent("Requesting X11 forwarding"); logevent("Requesting X11 forwarding");
ssh->x11auth = x11_invent_auth(proto, sizeof(proto), ssh->x11disp = x11_setup_display(ssh->cfg.x11_display,
data, sizeof(data), ssh->cfg.x11_auth); ssh->cfg.x11_auth, &ssh->cfg);
x11_get_real_auth(ssh->x11auth, ssh->cfg.x11_display);
/* /*
* Note that while we blank the X authentication data here, we don't * Note that while we blank the X authentication data here, we don't
* take any special action to blank the start of an X11 channel, * take any special action to blank the start of an X11 channel,
@ -4928,14 +4926,19 @@ static void do_ssh1_connection(Ssh ssh, unsigned char *in, int inlen,
*/ */
if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) { if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) {
send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING, send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING,
PKT_STR, proto, PKT_STR, ssh->x11disp->remoteauthprotoname,
PKTT_PASSWORD, PKT_STR, data, PKTT_OTHER, PKTT_PASSWORD,
PKT_INT, x11_get_screen_number(ssh->cfg.x11_display), PKT_STR, ssh->x11disp->remoteauthdatastring,
PKTT_OTHER,
PKT_INT, ssh->x11disp->screennum,
PKT_END); PKT_END);
} else { } else {
send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING, send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING,
PKT_STR, proto, PKT_STR, ssh->x11disp->remoteauthprotoname,
PKTT_PASSWORD, PKT_STR, data, PKTT_OTHER, PKT_END); PKTT_PASSWORD,
PKT_STR, ssh->x11disp->remoteauthdatastring,
PKTT_OTHER,
PKT_END);
} }
do { do {
crReturnV; crReturnV;
@ -6939,9 +6942,8 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin)
if (!ssh->X11_fwd_enabled) if (!ssh->X11_fwd_enabled)
error = "X11 forwarding is not enabled"; error = "X11 forwarding is not enabled";
else if (x11_init(&c->u.x11.s, ssh->cfg.x11_display, c, else if (x11_init(&c->u.x11.s, ssh->x11disp, c,
ssh->x11auth, addrstr, peerport, addrstr, peerport, &ssh->cfg) != NULL) {
&ssh->cfg) != NULL) {
error = "Unable to open an X11 connection"; error = "Unable to open an X11 connection";
} else { } else {
logevent("Opening X11 forward connection succeeded"); logevent("Opening X11 forward connection succeeded");
@ -8479,17 +8481,15 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
* Potentially enable X11 forwarding. * Potentially enable X11 forwarding.
*/ */
if (ssh->mainchan && !ssh->ncmode && ssh->cfg.x11_forward) { if (ssh->mainchan && !ssh->ncmode && ssh->cfg.x11_forward) {
char proto[20], data[64];
logevent("Requesting X11 forwarding"); logevent("Requesting X11 forwarding");
ssh->x11auth = x11_invent_auth(proto, sizeof(proto), ssh->x11disp = x11_setup_display(ssh->cfg.x11_display,
data, sizeof(data), ssh->cfg.x11_auth); ssh->cfg.x11_auth, &ssh->cfg);
x11_get_real_auth(ssh->x11auth, ssh->cfg.x11_display);
s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);
ssh2_pkt_addstring(s->pktout, "x11-req"); ssh2_pkt_addstring(s->pktout, "x11-req");
ssh2_pkt_addbool(s->pktout, 1); /* want reply */ ssh2_pkt_addbool(s->pktout, 1); /* want reply */
ssh2_pkt_addbool(s->pktout, 0); /* many connections */ ssh2_pkt_addbool(s->pktout, 0); /* many connections */
ssh2_pkt_addstring(s->pktout, proto); ssh2_pkt_addstring(s->pktout, ssh->x11disp->remoteauthprotoname);
/* /*
* Note that while we blank the X authentication data here, we don't * Note that while we blank the X authentication data here, we don't
* take any special action to blank the start of an X11 channel, * take any special action to blank the start of an X11 channel,
@ -8498,9 +8498,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
* cookie into the log. * cookie into the log.
*/ */
dont_log_password(ssh, s->pktout, PKTLOG_BLANK); dont_log_password(ssh, s->pktout, PKTLOG_BLANK);
ssh2_pkt_addstring(s->pktout, data); ssh2_pkt_addstring(s->pktout, ssh->x11disp->remoteauthdatastring);
end_log_omission(ssh, s->pktout); end_log_omission(ssh, s->pktout);
ssh2_pkt_adduint32(s->pktout, x11_get_screen_number(ssh->cfg.x11_display)); ssh2_pkt_adduint32(s->pktout, ssh->x11disp->screennum);
ssh2_pkt_send(ssh, s->pktout); ssh2_pkt_send(ssh, s->pktout);
crWaitUntilV(pktin); crWaitUntilV(pktin);
@ -8991,7 +8991,7 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle,
ssh->fallback_cmd = 0; ssh->fallback_cmd = 0;
ssh->pkt_kctx = SSH2_PKTCTX_NOKEX; ssh->pkt_kctx = SSH2_PKTCTX_NOKEX;
ssh->pkt_actx = SSH2_PKTCTX_NOAUTH; ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;
ssh->x11auth = NULL; ssh->x11disp = NULL;
ssh->v1_compressing = FALSE; ssh->v1_compressing = FALSE;
ssh->v2_outgoing_sequence = 0; ssh->v2_outgoing_sequence = 0;
ssh->ssh1_rdpkt_crstate = 0; ssh->ssh1_rdpkt_crstate = 0;
@ -9129,8 +9129,8 @@ static void ssh_free(void *handle)
ssh->rportfwds = NULL; ssh->rportfwds = NULL;
} }
sfree(ssh->deferred_send_data); sfree(ssh->deferred_send_data);
if (ssh->x11auth) if (ssh->x11disp)
x11_free_auth(ssh->x11auth); x11_free_display(ssh->x11disp);
sfree(ssh->do_ssh_init_state); sfree(ssh->do_ssh_init_state);
sfree(ssh->do_ssh1_login_state); sfree(ssh->do_ssh1_login_state);
sfree(ssh->do_ssh2_transport_state); sfree(ssh->do_ssh2_transport_state);

88
ssh.h
View File

@ -2,6 +2,7 @@
#include <string.h> #include <string.h>
#include "puttymem.h" #include "puttymem.h"
#include "tree234.h"
#include "network.h" #include "network.h"
#include "int64.h" #include "int64.h"
#include "misc.h" #include "misc.h"
@ -327,28 +328,85 @@ extern void pfd_unthrottle(Socket s);
extern void pfd_override_throttle(Socket s, int enable); extern void pfd_override_throttle(Socket s, int enable);
/* Exports from x11fwd.c */ /* Exports from x11fwd.c */
extern const char *x11_init(Socket *, char *, void *, void *, const char *, enum {
int, const Config *); X11_TRANS_IPV4 = 0, X11_TRANS_IPV6 = 6, X11_TRANS_UNIX = 256
};
struct X11Display {
/* Broken-down components of the display name itself */
int unixdomain;
char *hostname;
int displaynum;
int screennum;
/* OSX sometimes replaces all the above with a full Unix-socket pathname */
char *unixsocketpath;
/* PuTTY networking SockAddr to connect to the display, and associated
* gubbins */
SockAddr addr;
int port;
char *realhost;
/* Auth details we invented for the virtual display on the SSH server. */
int remoteauthproto;
unsigned char *remoteauthdata;
int remoteauthdatalen;
char *remoteauthprotoname;
char *remoteauthdatastring;
/* Our local auth details for talking to the real X display. */
int localauthproto;
unsigned char *localauthdata;
int localauthdatalen;
/*
* Used inside x11fwd.c to remember recently seen
* XDM-AUTHORIZATION-1 strings, to avoid replay attacks.
*/
tree234 *xdmseen;
};
/*
* x11_setup_display() parses the display variable and fills in an
* X11Display structure. Some remote auth details are invented;
* the supplied authtype parameter configures the preferred
* authorisation protocol to use at the remote end. The local auth
* details are looked up by calling platform_get_x11_auth.
*/
extern struct X11Display *x11_setup_display(char *display, int authtype,
const Config *);
void x11_free_display(struct X11Display *disp);
extern const char *x11_init(Socket *, struct X11Display *, void *,
const char *, int, const Config *);
extern void x11_close(Socket); extern void x11_close(Socket);
extern int x11_send(Socket, char *, int); extern int x11_send(Socket, char *, int);
extern void *x11_invent_auth(char *, int, char *, int, int);
extern void x11_free_auth(void *);
extern void x11_unthrottle(Socket s); extern void x11_unthrottle(Socket s);
extern void x11_override_throttle(Socket s, int enable); extern void x11_override_throttle(Socket s, int enable);
extern int x11_get_screen_number(char *display);
void x11_get_real_auth(void *authv, char *display);
char *x11_display(const char *display); char *x11_display(const char *display);
/* Platform-dependent X11 functions */ /* Platform-dependent X11 functions */
extern void platform_get_x11_auth(char *display, int *proto, extern void platform_get_x11_auth(struct X11Display *display,
unsigned char *data, int *datalen); const Config *);
extern const char platform_x11_best_transport[]; /* examine a mostly-filled-in X11Display and fill in localauth* */
/* best X11 hostname for this platform if none specified */ extern const int platform_uses_x11_unix_by_default;
SockAddr platform_get_x11_unix_address(const char *display, int displaynum, /* choose default X transport in the absence of a specified one */
char **canonicalname); SockAddr platform_get_x11_unix_address(const char *path, int displaynum);
/* make up a SockAddr naming the address for displaynum */ /* make up a SockAddr naming the address for displaynum */
char *platform_get_x_display(void); char *platform_get_x_display(void);
/* allocated local X display string, if any */ /* allocated local X display string, if any */
/* Callbacks in x11.c usable _by_ platform X11 functions */
/*
* This function does the job of platform_get_x11_auth, provided
* it is told where to find a normally formatted .Xauthority file:
* it opens that file, parses it to find an auth record which
* matches the display details in "display", and fills in the
* localauth fields.
*
* It is expected that most implementations of
* platform_get_x11_auth() will work by finding their system's
* .Xauthority file, adjusting the display details if necessary
* for local oddities like Unix-domain socket transport, and
* calling this function to do the rest of the work.
*/
void x11_get_auth_from_authfile(struct X11Display *display,
const char *authfilename);
Bignum copybn(Bignum b); Bignum copybn(Bignum b);
Bignum bn_power_2(int n); Bignum bn_power_2(int n);

View File

@ -5,117 +5,66 @@
#include <ctype.h> #include <ctype.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h>
#include "putty.h" #include "putty.h"
#include "ssh.h" #include "ssh.h"
#include "network.h"
void platform_get_x11_auth(char *display, int *protocol, void platform_get_x11_auth(struct X11Display *disp, const Config *cfg)
unsigned char *data, int *datalen)
{ {
FILE *fp; char *xauthfile;
char *command; int needs_free;
int maxsize = *datalen;
char *localbuf;
int proto = -1;
display = x11_display(display);
/* /*
* Normally we should run `xauth list DISPLAYNAME'. However, * Upgrade an IP-style localhost display to a Unix-socket
* there's an oddity when the display is local: the display * display.
* `localhost:0' (or `:0') should become just `:0'.
*/ */
if (!strncmp(display, "localhost:", 10) if (!disp->unixdomain && sk_address_is_local(disp->addr)) {
|| !strncmp(display, "unix:", 5)) sk_addr_free(disp->addr);
command = dupprintf("xauth list %s 2>/dev/null", disp->unixdomain = TRUE;
strchr(display, ':')); disp->addr = platform_get_x11_unix_address(NULL, disp->displaynum);
else disp->realhost = dupprintf("unix:%d", disp->displaynum);
command = dupprintf("xauth list %s 2>/dev/null", display); disp->port = 0;
sfree(display); }
fp = popen(command, "r");
sfree(command); /*
* Set the hostname for Unix-socket displays, so that we'll
if (!fp) * look it up correctly in the X authority file.
return; /* assume no auth */ */
if (disp->unixdomain) {
localbuf = snewn(maxsize, char); int len;
while (1) { sfree(disp->hostname);
/* len = 128;
* Read a line from stdin, and attempt to parse it into a do {
* display name (ignored), auth protocol, and auth string. len *= 2;
*/ disp->hostname = snewn(len, char);
int c, i, hexdigit; if (gethostname(disp->hostname, len) < 0) {
char protoname[64]; disp->hostname = NULL;
return;
/* Skip the display name. */ }
while (c = getc(fp), c != EOF && c != '\n' && !isspace(c)); } while (strlen(disp->hostname) >= len-1);
if (c == EOF) break; }
if (c == '\n') continue;
/*
/* Skip white space. */ * Find the .Xauthority file.
while (c != EOF && c != '\n' && isspace(c)) */
c = getc(fp); needs_free = FALSE;
if (c == EOF) break; xauthfile = getenv("XAUTHORITY");
if (c == '\n') continue; if (!xauthfile) {
xauthfile = getenv("HOME");
/* Read the auth protocol name, and see if it matches any we if (xauthfile) {
* know about. */ xauthfile = dupcat(xauthfile, "/.Xauthority", NULL);
i = 0; needs_free = TRUE;
while (c != EOF && c != '\n' && !isspace(c)) { }
if (i < lenof(protoname)-1) protoname[i++] = c; }
c = getc(fp);
} if (xauthfile) {
protoname[i] = '\0'; x11_get_auth_from_authfile(disp, xauthfile);
if (needs_free)
for (i = X11_NO_AUTH; ++i < X11_NAUTHS ;) { sfree(xauthfile);
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. */
} }
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; return 0;
} }
SockAddr platform_get_x11_unix_address(const char *display, int displaynum, SockAddr platform_get_x11_unix_address(const char *sockpath, int displaynum)
char **canonicalname)
{ {
SockAddr ret = snew(struct SockAddr_tag); SockAddr ret = snew(struct SockAddr_tag);
int n; int n;
@ -1399,26 +1398,22 @@ SockAddr platform_get_x11_unix_address(const char *display, int displaynum,
memset(ret, 0, sizeof *ret); memset(ret, 0, sizeof *ret);
ret->superfamily = UNIX; ret->superfamily = UNIX;
/* /*
* Mac OS X Leopard uses an innovative X display naming * In special circumstances (notably Mac OS X Leopard), we'll
* convention in which the entire display name is the path to * have been passed an explicit Unix socket path.
* 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.
*/ */
if (display[0] == '/') { if (sockpath) {
n = snprintf(ret->hostname, sizeof ret->hostname, n = snprintf(ret->hostname, sizeof ret->hostname,
"%s", display); "%s", sockpath);
} else { } else {
n = snprintf(ret->hostname, sizeof ret->hostname, n = snprintf(ret->hostname, sizeof ret->hostname,
"%s%d", X11_UNIX_PATH, displaynum); "%s%d", X11_UNIX_PATH, displaynum);
} }
if(n < 0)
if (n < 0)
ret->error = "snprintf failed"; ret->error = "snprintf failed";
else if(n >= sizeof ret->hostname) else if (n >= sizeof ret->hostname)
ret->error = "X11 UNIX name too long"; ret->error = "X11 UNIX name too long";
else
*canonicalname = dupstr(ret->hostname);
#ifndef NO_IPV6 #ifndef NO_IPV6
ret->ais = NULL; ret->ais = NULL;
#else #else

View File

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

View File

@ -377,4 +377,14 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help,
*/ */
if (!midsession || (protocol == PROT_SERIAL)) if (!midsession || (protocol == PROT_SERIAL))
ser_setup_config_box(b, midsession, 0x1F, 0x0F); ser_setup_config_box(b, midsession, 0x1F, 0x0F);
/*
* $XAUTHORITY is not reliable on Windows, so we provide a
* means to override it.
*/
s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
ctrl_filesel(s, "X authority file for local display", 't',
NULL, FALSE, "Select X authority file",
HELPCTX(ssh_tunnels_xauthority),
dlg_stdfilesel_handler, I(offsetof(Config, xauthfile)));
} }

View File

@ -121,6 +121,7 @@
#define WINHELP_CTX_translation_linedraw "translation.linedraw:config-linedraw" #define WINHELP_CTX_translation_linedraw "translation.linedraw:config-linedraw"
#define WINHELP_CTX_ssh_tunnels_x11 "ssh.tunnels.x11:config-ssh-x11" #define WINHELP_CTX_ssh_tunnels_x11 "ssh.tunnels.x11:config-ssh-x11"
#define WINHELP_CTX_ssh_tunnels_x11auth "ssh.tunnels.x11auth:config-ssh-x11auth" #define WINHELP_CTX_ssh_tunnels_x11auth "ssh.tunnels.x11auth:config-ssh-x11auth"
#define WINHELP_CTX_ssh_tunnels_xauthority "ssh.tunnels.xauthority:config-ssh-xauthority"
#define WINHELP_CTX_ssh_tunnels_portfwd "ssh.tunnels.portfwd:config-ssh-portfwd" #define WINHELP_CTX_ssh_tunnels_portfwd "ssh.tunnels.portfwd:config-ssh-portfwd"
#define WINHELP_CTX_ssh_tunnels_portfwd_localhost "ssh.tunnels.portfwd.localhost:config-ssh-portfwd-localhost" #define WINHELP_CTX_ssh_tunnels_portfwd_localhost "ssh.tunnels.portfwd.localhost:config-ssh-portfwd-localhost"
#define WINHELP_CTX_ssh_tunnels_portfwd_ipversion "ssh.tunnels.portfwd.ipversion:config-ssh-portfwd-address-family" #define WINHELP_CTX_ssh_tunnels_portfwd_ipversion "ssh.tunnels.portfwd.ipversion:config-ssh-portfwd-address-family"

View File

@ -8,14 +8,6 @@
OSVERSIONINFO osVersion; OSVERSIONINFO osVersion;
void platform_get_x11_auth(char *display, int *proto,
unsigned char *data, int *datalen)
{
/* We don't support this at all under Windows. */
}
const char platform_x11_best_transport[] = "localhost";
char *platform_get_x_display(void) { char *platform_get_x_display(void) {
/* We may as well check for DISPLAY in case it's useful. */ /* We may as well check for DISPLAY in case it's useful. */
return dupstr(getenv("DISPLAY")); return dupstr(getenv("DISPLAY"));

View File

@ -19,6 +19,12 @@ int get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
return ret; return ret;
} }
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;
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
* File access abstraction. * File access abstraction.
*/ */

18
windows/winx11.c Normal file
View File

@ -0,0 +1,18 @@
/*
* winx11.c: fetch local auth data for X forwarding.
*/
#include <ctype.h>
#include <assert.h>
#include <stdlib.h>
#include "putty.h"
#include "ssh.h"
void platform_get_x11_auth(struct X11Display *disp, const Config *cfg)
{
if (cfg->xauthfile.path[0])
x11_get_auth_from_authfile(disp, cfg->xauthfile.path);
}
const int platform_uses_x11_unix_by_default = FALSE;

451
x11fwd.c
View File

@ -26,18 +26,11 @@ struct XDMSeen {
unsigned char clientid[6]; unsigned char clientid[6];
}; };
struct X11Auth {
unsigned char fakedata[64], realdata[64];
int fakeproto, realproto;
int fakelen, reallen;
tree234 *xdmseen;
};
struct X11Private { struct X11Private {
const struct plug_function_table *fn; const struct plug_function_table *fn;
/* the above variable absolutely *must* be the first in this structure */ /* the above variable absolutely *must* be the first in this structure */
unsigned char firstpkt[12]; /* first X data packet */ unsigned char firstpkt[12]; /* first X data packet */
struct X11Auth *auth; struct X11Display *disp;
char *auth_protocol; char *auth_protocol;
unsigned char *auth_data; unsigned char *auth_data;
int data_read, auth_plen, auth_psize, auth_dlen, auth_dsize; int data_read, auth_plen, auth_psize, auth_dlen, auth_dsize;
@ -57,86 +50,197 @@ static int xdmseen_cmp(void *a, void *b)
memcmp(sa->clientid, sb->clientid, sizeof(sa->clientid)); memcmp(sa->clientid, sb->clientid, sizeof(sa->clientid));
} }
void *x11_invent_auth(char *proto, int protomaxlen, struct X11Display *x11_setup_display(char *display, int authtype,
char *data, int datamaxlen, int proto_id) const Config *cfg)
{ {
struct X11Auth *auth = snew(struct X11Auth); struct X11Display *disp = snew(struct X11Display);
char ourdata[64]; char *localcopy;
int i; int i;
if (proto_id == X11_MIT) { if (!display || !*display) {
auth->fakeproto = X11_MIT; localcopy = platform_get_x_display();
if (!localcopy || !*localcopy) {
sfree(localcopy);
localcopy = dupstr(":0"); /* plausible default for any platform */
}
} else
localcopy = dupstr(display);
/*
* Parse the display name.
*
* We expect this to have one of the following forms:
*
* - the standard X format which looks like
* [ [ protocol '/' ] host ] ':' displaynumber [ '.' screennumber ]
* (X11 also permits a double colon to indicate DECnet, but
* that's not our problem, thankfully!)
*
* - only seen in the wild on MacOS (so far): a pathname to a
* Unix-domain socket, which will typically and confusingly
* end in ":0", and which I'm currently distinguishing from
* the standard scheme by noting that it starts with '/'.
*/
if (localcopy[0] == '/') {
disp->unixsocketpath = localcopy;
disp->unixdomain = TRUE;
disp->hostname = NULL;
disp->displaynum = -1;
disp->screennum = 0;
} else {
char *colon, *dot, *slash;
char *protocol, *hostname;
colon = strrchr(localcopy, ':');
if (!colon) {
sfree(disp);
sfree(localcopy);
return NULL; /* FIXME: report a specific error? */
}
*colon++ = '\0';
dot = strchr(colon, '.');
if (dot)
*dot++ = '\0';
disp->displaynum = atoi(colon);
if (dot)
disp->screennum = atoi(dot);
else
disp->screennum = 0;
protocol = NULL;
hostname = localcopy;
if (colon > localcopy) {
slash = strchr(localcopy, '/');
if (slash) {
*slash++ = '\0';
protocol = localcopy;
hostname = slash;
}
}
disp->hostname = *hostname ? dupstr(hostname) : NULL;
if (protocol)
disp->unixdomain = (!strcmp(protocol, "local") ||
!strcmp(protocol, "unix"));
else
disp->unixdomain = platform_uses_x11_unix_by_default;
if (!disp->hostname && !disp->unixdomain)
disp->hostname = dupstr("localhost");
disp->unixsocketpath = NULL;
sfree(localcopy);
}
/*
* Look up the display hostname, if we need to.
*/
if (disp->unixdomain) {
disp->addr = platform_get_x11_unix_address(disp->unixsocketpath,
disp->displaynum);
if (disp->unixsocketpath)
disp->realhost = dupstr(disp->unixsocketpath);
else
disp->realhost = dupprintf("unix:%d", disp->displaynum);
disp->port = 0;
} else {
const char *err;
disp->port = 6000 + disp->displaynum;
disp->addr = name_lookup(disp->hostname, disp->port,
&disp->realhost, cfg, ADDRTYPE_UNSPEC);
if ((err = sk_addr_error(disp->addr)) != NULL) {
sk_addr_free(disp->addr);
sfree(disp->hostname);
sfree(disp->unixsocketpath);
return NULL; /* FIXME: report an error */
}
}
/*
* Invent the remote authorisation details.
*/
if (authtype == X11_MIT) {
disp->remoteauthproto = X11_MIT;
/* MIT-MAGIC-COOKIE-1. Cookie size is 128 bits (16 bytes). */ /* MIT-MAGIC-COOKIE-1. Cookie size is 128 bits (16 bytes). */
auth->fakelen = 16; disp->remoteauthdata = snewn(16, unsigned char);
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
auth->fakedata[i] = random_byte(); disp->remoteauthdata[i] = random_byte();
auth->xdmseen = NULL; disp->remoteauthdatalen = 16;
disp->xdmseen = NULL;
} else { } else {
assert(proto_id == X11_XDM); assert(authtype == X11_XDM);
auth->fakeproto = X11_XDM; disp->remoteauthproto = X11_XDM;
/* XDM-AUTHORIZATION-1. Cookie size is 16 bytes; byte 8 is zero. */ /* XDM-AUTHORIZATION-1. Cookie size is 16 bytes; byte 8 is zero. */
auth->fakelen = 16; disp->remoteauthdata = snewn(16, unsigned char);
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
auth->fakedata[i] = (i == 8 ? 0 : random_byte()); disp->remoteauthdata[i] = (i == 8 ? 0 : random_byte());
auth->xdmseen = newtree234(xdmseen_cmp); disp->remoteauthdatalen = 16;
disp->xdmseen = newtree234(xdmseen_cmp);
} }
disp->remoteauthprotoname = dupstr(x11_authnames[disp->remoteauthproto]);
disp->remoteauthdatastring = snewn(disp->remoteauthdatalen * 2 + 1, char);
for (i = 0; i < disp->remoteauthdatalen; i++)
sprintf(disp->remoteauthdatastring + i*2, "%02x",
disp->remoteauthdata[i]);
/* Now format for the recipient. */ /*
strncpy(proto, x11_authnames[auth->fakeproto], protomaxlen); * Fetch the local authorisation details.
ourdata[0] = '\0'; */
for (i = 0; i < auth->fakelen; i++) disp->localauthproto = X11_NO_AUTH;
sprintf(ourdata + strlen(ourdata), "%02x", auth->fakedata[i]); disp->localauthdata = NULL;
strncpy(data, ourdata, datamaxlen); disp->localauthdatalen = 0;
platform_get_x11_auth(disp, cfg);
return auth; return disp;
} }
void x11_free_auth(void *authv) void x11_free_display(struct X11Display *disp)
{ {
struct X11Auth *auth = (struct X11Auth *)authv; if (disp->xdmseen != NULL) {
struct XDMSeen *seen; struct XDMSeen *seen;
while ((seen = delpos234(disp->xdmseen, 0)) != NULL)
if (auth->xdmseen != NULL) {
while ((seen = delpos234(auth->xdmseen, 0)) != NULL)
sfree(seen); sfree(seen);
freetree234(auth->xdmseen); freetree234(disp->xdmseen);
} }
sfree(auth); sfree(disp->hostname);
} sfree(disp->unixsocketpath);
if (disp->localauthdata)
/* memset(disp->localauthdata, 0, disp->localauthdatalen);
* Fetch the real auth data for a given display string, and store sfree(disp->localauthdata);
* it in an X11Auth structure. Returns NULL on success, or an error if (disp->remoteauthdata)
* string. memset(disp->remoteauthdata, 0, disp->remoteauthdatalen);
*/ sfree(disp->remoteauthdata);
void x11_get_real_auth(void *authv, char *display) sfree(disp->remoteauthprotoname);
{ sfree(disp->remoteauthdatastring);
struct X11Auth *auth = (struct X11Auth *)authv; sk_addr_free(disp->addr);
sfree(disp);
auth->realproto = X11_NO_AUTH; /* in case next call does nothing */
auth->reallen = sizeof(auth->realdata);
platform_get_x11_auth(display, &auth->realproto,
auth->realdata, &auth->reallen);
} }
#define XDM_MAXSKEW 20*60 /* 20 minute clock skew should be OK */ #define XDM_MAXSKEW 20*60 /* 20 minute clock skew should be OK */
static char *x11_verify(unsigned long peer_ip, int peer_port, static char *x11_verify(unsigned long peer_ip, int peer_port,
struct X11Auth *auth, char *proto, struct X11Display *disp, char *proto,
unsigned char *data, int dlen) unsigned char *data, int dlen)
{ {
if (strcmp(proto, x11_authnames[auth->fakeproto]) != 0) if (strcmp(proto, x11_authnames[disp->remoteauthproto]) != 0)
return "wrong authentication protocol attempted"; return "wrong authorisation protocol attempted";
if (auth->fakeproto == X11_MIT) { if (disp->remoteauthproto == X11_MIT) {
if (dlen != auth->fakelen) if (dlen != disp->remoteauthdatalen)
return "MIT-MAGIC-COOKIE-1 data was wrong length"; return "MIT-MAGIC-COOKIE-1 data was wrong length";
if (memcmp(auth->fakedata, data, dlen) != 0) if (memcmp(disp->remoteauthdata, data, dlen) != 0)
return "MIT-MAGIC-COOKIE-1 data did not match"; return "MIT-MAGIC-COOKIE-1 data did not match";
} }
if (auth->fakeproto == X11_XDM) { if (disp->remoteauthproto == X11_XDM) {
unsigned long t; unsigned long t;
time_t tim; time_t tim;
int i; int i;
@ -146,8 +250,8 @@ static char *x11_verify(unsigned long peer_ip, int peer_port,
return "XDM-AUTHORIZATION-1 data was wrong length"; return "XDM-AUTHORIZATION-1 data was wrong length";
if (peer_port == -1) if (peer_port == -1)
return "cannot do XDM-AUTHORIZATION-1 without remote address data"; return "cannot do XDM-AUTHORIZATION-1 without remote address data";
des_decrypt_xdmauth(auth->fakedata+9, data, 24); des_decrypt_xdmauth(disp->remoteauthdata+9, data, 24);
if (memcmp(auth->fakedata, data, 8) != 0) if (memcmp(disp->remoteauthdata, data, 8) != 0)
return "XDM-AUTHORIZATION-1 data failed check"; /* cookie wrong */ return "XDM-AUTHORIZATION-1 data failed check"; /* cookie wrong */
if (GET_32BIT_MSB_FIRST(data+8) != peer_ip) if (GET_32BIT_MSB_FIRST(data+8) != peer_ip)
return "XDM-AUTHORIZATION-1 data failed check"; /* IP wrong */ return "XDM-AUTHORIZATION-1 data failed check"; /* IP wrong */
@ -163,25 +267,144 @@ static char *x11_verify(unsigned long peer_ip, int peer_port,
seen = snew(struct XDMSeen); seen = snew(struct XDMSeen);
seen->time = t; seen->time = t;
memcpy(seen->clientid, data+8, 6); memcpy(seen->clientid, data+8, 6);
assert(auth->xdmseen != NULL); assert(disp->xdmseen != NULL);
ret = add234(auth->xdmseen, seen); ret = add234(disp->xdmseen, seen);
if (ret != seen) { if (ret != seen) {
sfree(seen); sfree(seen);
return "XDM-AUTHORIZATION-1 data replayed"; return "XDM-AUTHORIZATION-1 data replayed";
} }
/* While we're here, purge entries too old to be replayed. */ /* While we're here, purge entries too old to be replayed. */
for (;;) { for (;;) {
seen = index234(auth->xdmseen, 0); seen = index234(disp->xdmseen, 0);
assert(seen != NULL); assert(seen != NULL);
if (t - seen->time <= XDM_MAXSKEW) if (t - seen->time <= XDM_MAXSKEW)
break; break;
sfree(delpos234(auth->xdmseen, 0)); sfree(delpos234(disp->xdmseen, 0));
} }
} }
/* implement other protocols here if ever required */ /* implement other protocols here if ever required */
return NULL; return NULL;
} }
void x11_get_auth_from_authfile(struct X11Display *disp,
const char *authfilename)
{
FILE *authfp;
char *buf, *ptr, *str[4];
int len[4];
int family, protocol;
authfp = fopen(authfilename, "rb");
if (!authfp)
return;
/* Records in .Xauthority contain four strings of up to 64K each */
buf = snewn(65537 * 4, char);
while (1) {
int c, i, j;
#define GET do { c = fgetc(authfp); if (c == EOF) goto done; c = (unsigned char)c; } while (0)
/* Expect a big-endian 2-byte number giving address family */
GET; family = c;
GET; family = (family << 8) | c;
/* Then expect four strings, each composed of a big-endian 2-byte
* length field followed by that many bytes of data */
ptr = buf;
for (i = 0; i < 4; i++) {
GET; len[i] = c;
GET; len[i] = (len[i] << 8) | c;
str[i] = ptr;
for (j = 0; j < len[i]; j++) {
GET; *ptr++ = c;
}
*ptr++ = '\0';
}
#undef GET
/*
* Now we have a full X authority record in memory. See
* whether it matches the display we're trying to
* authenticate to.
*
* The details we've just read should be interpreted as
* follows:
*
* - 'family' is the network address family used to
* connect to the display. 0 means IPv4; 6 means IPv6;
* 256 means Unix-domain sockets.
*
* - str[0] is the network address itself. For IPv4 and
* IPv6, this is a string of binary data of the
* appropriate length (respectively 4 and 16 bytes)
* representing the address in big-endian format, e.g.
* 7F 00 00 01 means IPv4 localhost. For Unix-domain
* sockets, this is the host name of the machine on
* which the Unix-domain display resides (so that an
* .Xauthority file on a shared file system can contain
* authority entries for Unix-domain displays on
* several machines without them clashing).
*
* - str[1] is the display number. I've no idea why
* .Xauthority stores this as a string when it has a
* perfectly good integer format, but there we go.
*
* - str[2] is the authorisation method, encoded as its
* canonical string name (i.e. "MIT-MAGIC-COOKIE-1",
* "XDM-AUTHORIZATION-1" or something we don't
* recognise).
*
* - str[3] is the actual authorisation data, stored in
* binary form.
*/
if (disp->displaynum < 0 || disp->displaynum != atoi(str[1]))
continue; /* not the one */
for (protocol = 1; protocol < lenof(x11_authnames); protocol++)
if (!strcmp(str[2], x11_authnames[protocol]))
break;
if (protocol == lenof(x11_authnames))
continue; /* don't recognise this protocol, look for another */
switch (family) {
case 0:
if (!disp->unixdomain &&
sk_addrtype(disp->addr) == ADDRTYPE_IPV4) {
char buf[4];
sk_addrcopy(disp->addr, buf);
if (len[0] == 4 && !memcmp(str[0], buf, 4))
goto found;
}
break;
case 6:
if (!disp->unixdomain &&
sk_addrtype(disp->addr) == ADDRTYPE_IPV6) {
char buf[16];
sk_addrcopy(disp->addr, buf);
if (len[0] == 16 && !memcmp(str[0], buf, 16))
goto found;
}
break;
case 256:
if (disp->unixdomain && !strcmp(disp->hostname, str[0]))
goto found;
break;
}
}
found:
disp->localauthproto = protocol;
disp->localauthdata = snewn(len[3], unsigned char);
memcpy(disp->localauthdata, str[3], len[3]);
disp->localauthdatalen = len[3];
done:
fclose(authfp);
memset(buf, 0, 65537 * 4);
sfree(buf);
}
static void x11_log(Plug p, int type, SockAddr addr, int port, static void x11_log(Plug p, int type, SockAddr addr, int port,
const char *error_msg, int error_code) const char *error_msg, int error_code)
{ {
@ -240,33 +463,15 @@ int x11_get_screen_number(char *display)
return atoi(display + n + 1); return atoi(display + n + 1);
} }
/* Find the right display, returns an allocated string */
char *x11_display(const char *display) {
char *ret;
if(!display || !*display) {
/* try to find platform-specific local display */
if((ret = platform_get_x_display())==0 || !*ret)
/* plausible default for all platforms */
ret = dupstr(":0");
} else
ret = dupstr(display);
if(ret[0] == ':') {
/* no transport specified, use whatever we think is best */
char *s = dupcat(platform_x11_best_transport, ret, (char *)0);
sfree(ret);
return s;
} else
return ret;
}
/* /*
* Called to set up the raw connection. * Called to set up the raw connection.
* *
* Returns an error message, or NULL on success. * Returns an error message, or NULL on success.
* also, fills the SocketsStructure * also, fills the SocketsStructure
*/ */
const char *x11_init(Socket * s, char *display, void *c, void *auth, extern const char *x11_init(Socket *s, struct X11Display *disp, void *c,
const char *peeraddr, int peerport, const Config *cfg) const char *peeraddr, int peerport,
const Config *cfg)
{ {
static const struct plug_function_table fn_table = { static const struct plug_function_table fn_table = {
x11_log, x11_log,
@ -276,62 +481,23 @@ const char *x11_init(Socket * s, char *display, void *c, void *auth,
NULL NULL
}; };
SockAddr addr;
int port;
const char *err; const char *err;
char *dummy_realhost;
char host[128];
int n, displaynum;
struct X11Private *pr; struct X11Private *pr;
/* default display */
display = x11_display(display);
/*
* Split up display name into host and display-number parts.
*/
n = strcspn(display, ":");
assert(n != 0); /* x11_display() promises this */
if (display[n])
displaynum = atoi(display + n + 1);
else
displaynum = 0; /* sensible default */
if (n > sizeof(host) - 1)
n = sizeof(host) - 1;
strncpy(host, display, n);
host[n] = '\0';
sfree(display);
if(!strcmp(host, "unix") || host[0] == '/') {
/* use AF_UNIX sockets (doesn't make sense on all platforms) */
addr = platform_get_x11_unix_address(display, displaynum,
&dummy_realhost);
port = 0; /* to show we are not confused */
} else {
port = 6000 + displaynum;
/*
* Try to find host.
*/
addr = name_lookup(host, port, &dummy_realhost, cfg, ADDRTYPE_UNSPEC);
if ((err = sk_addr_error(addr)) != NULL) {
sk_addr_free(addr);
return err;
}
}
/* /*
* Open socket. * Open socket.
*/ */
pr = snew(struct X11Private); pr = snew(struct X11Private);
pr->fn = &fn_table; pr->fn = &fn_table;
pr->auth_protocol = NULL; pr->auth_protocol = NULL;
pr->auth = (struct X11Auth *)auth; pr->disp = disp;
pr->verified = 0; pr->verified = 0;
pr->data_read = 0; pr->data_read = 0;
pr->throttled = pr->throttle_override = 0; pr->throttled = pr->throttle_override = 0;
pr->c = c; pr->c = c;
pr->s = *s = new_connection(addr, dummy_realhost, port, pr->s = *s = new_connection(sk_addr_dup(disp->addr),
disp->realhost, disp->port,
0, 1, 0, 0, (Plug) pr, cfg); 0, 1, 0, 0, (Plug) pr, cfg);
if ((err = sk_socket_error(*s)) != NULL) { if ((err = sk_socket_error(*s)) != NULL) {
sfree(pr); sfree(pr);
@ -439,18 +605,18 @@ int x11_send(Socket s, char *data, int len)
return 0; return 0;
/* /*
* If we haven't verified the authentication, do so now. * If we haven't verified the authorisation, do so now.
*/ */
if (!pr->verified) { if (!pr->verified) {
char *err; char *err;
pr->auth_protocol[pr->auth_plen] = '\0'; /* ASCIZ */ pr->auth_protocol[pr->auth_plen] = '\0'; /* ASCIZ */
err = x11_verify(pr->peer_ip, pr->peer_port, err = x11_verify(pr->peer_ip, pr->peer_port,
pr->auth, pr->auth_protocol, pr->disp, pr->auth_protocol,
pr->auth_data, pr->auth_dlen); pr->auth_data, pr->auth_dlen);
/* /*
* If authentication failed, construct and send an error * If authorisation failed, construct and send an error
* packet, then terminate the connection. * packet, then terminate the connection.
*/ */
if (err) { if (err) {
@ -484,27 +650,27 @@ int x11_send(Socket s, char *data, int len)
{ {
char realauthdata[64]; char realauthdata[64];
int realauthlen = 0; int realauthlen = 0;
int authstrlen = strlen(x11_authnames[pr->auth->realproto]); int authstrlen = strlen(x11_authnames[pr->disp->localauthproto]);
int buflen = 0; /* initialise to placate optimiser */ int buflen = 0; /* initialise to placate optimiser */
static const char zeroes[4] = { 0,0,0,0 }; static const char zeroes[4] = { 0,0,0,0 };
void *buf; void *buf;
if (pr->auth->realproto == X11_MIT) { if (pr->disp->localauthproto == X11_MIT) {
assert(pr->auth->reallen <= lenof(realauthdata)); assert(pr->disp->localauthdatalen <= lenof(realauthdata));
realauthlen = pr->auth->reallen; realauthlen = pr->disp->localauthdatalen;
memcpy(realauthdata, pr->auth->realdata, realauthlen); memcpy(realauthdata, pr->disp->localauthdata, realauthlen);
} else if (pr->auth->realproto == X11_XDM && } else if (pr->disp->localauthproto == X11_XDM &&
pr->auth->reallen == 16 && pr->disp->localauthdatalen == 16 &&
((buf = sk_getxdmdata(s, &buflen))!=0)) { ((buf = sk_getxdmdata(s, &buflen))!=0)) {
time_t t; time_t t;
realauthlen = (buflen+12+7) & ~7; realauthlen = (buflen+12+7) & ~7;
assert(realauthlen <= lenof(realauthdata)); assert(realauthlen <= lenof(realauthdata));
memset(realauthdata, 0, realauthlen); memset(realauthdata, 0, realauthlen);
memcpy(realauthdata, pr->auth->realdata, 8); memcpy(realauthdata, pr->disp->localauthdata, 8);
memcpy(realauthdata+8, buf, buflen); memcpy(realauthdata+8, buf, buflen);
t = time(NULL); t = time(NULL);
PUT_32BIT_MSB_FIRST(realauthdata+8+buflen, t); PUT_32BIT_MSB_FIRST(realauthdata+8+buflen, t);
des_encrypt_xdmauth(pr->auth->realdata+9, des_encrypt_xdmauth(pr->disp->localauthdata+9,
(unsigned char *)realauthdata, (unsigned char *)realauthdata,
realauthlen); realauthlen);
sfree(buf); sfree(buf);
@ -517,7 +683,8 @@ int x11_send(Socket s, char *data, int len)
sk_write(s, (char *)pr->firstpkt, 12); sk_write(s, (char *)pr->firstpkt, 12);
if (authstrlen) { if (authstrlen) {
sk_write(s, x11_authnames[pr->auth->realproto], authstrlen); sk_write(s, x11_authnames[pr->disp->localauthproto],
authstrlen);
sk_write(s, zeroes, 3 & (-authstrlen)); sk_write(s, zeroes, 3 & (-authstrlen));
} }
if (realauthlen) { if (realauthlen) {