From e0e7dff87dc3f482da6ab00317664474b0f82995 Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 10 Jan 2003 18:33:35 +0000 Subject: [PATCH] Introduce framework for authenticating with the local X server. Windows and Mac backends have acquired auth-finding functions which do nothing; Unix backend has acquired one which actually works, so Plink can now do X forwarding believably. (This checkin stretches into some unlikely parts of the code because there have been one or two knock-on effects involving `const'. Bah.) git-svn-id: svn://svn.tartarus.org/sgt/putty@2536 cda61777-01e9-0310-a592-d414129be87e --- Recipe | 4 +-- mac/mac.c | 8 ++++- misc.c | 4 +-- misc.h | 2 +- network.h | 4 +-- proxy.c | 4 +-- putty.h | 10 ++++++ ssh.c | 2 ++ ssh.h | 1 + unix/ux_x11.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ unix/uxnet.c | 8 ++--- winmisc.c | 14 ++++++++ winnet.c | 8 ++--- x11fwd.c | 88 ++++++++++++++++++++++++++++++++++++++---------- 14 files changed, 228 insertions(+), 35 deletions(-) create mode 100644 unix/ux_x11.c create mode 100644 winmisc.c diff --git a/Recipe b/Recipe index e3443c0d..2416af29 100644 --- a/Recipe +++ b/Recipe @@ -109,7 +109,7 @@ SFTP = sftp int64 logging # Miscellaneous objects appearing in all the network utilities (not # Pageant or PuTTYgen). WINMISC = misc version winstore settings tree234 winnet proxy cmdline - + windefs + + windefs winmisc UXMISC = misc version uxstore settings tree234 uxnet proxy cmdline MACMISC = misc version macstore settings tree234 mtcpnet proxy @@ -145,7 +145,7 @@ puttygen : [G] puttygen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version pterm : [X] pterm terminal wcwidth uxucs uxmisc tree234 misc ldisc ldiscucs + logging uxprint settings pty be_none uxstore signal CHARSET -plink : [U] uxplink uxcons NONSSH UXSSH be_all logging UXMISC signal +plink : [U] uxplink uxcons NONSSH UXSSH be_all logging UXMISC signal ux_x11 PuTTY : [M] terminal wcwidth ldiscucs logging be_all mac macdlg + macterm macucs mac_res.rsrc testback NONSSH MACSSH MACMISC CHARSET diff --git a/mac/mac.c b/mac/mac.c index a0ec60b2..fe46f3f8 100644 --- a/mac/mac.c +++ b/mac/mac.c @@ -1,4 +1,4 @@ -/* $Id: mac.c,v 1.22 2003/01/09 22:39:47 ben Exp $ */ +/* $Id: mac.c,v 1.23 2003/01/10 18:33:35 simon Exp $ */ /* * Copyright (c) 1999 Ben Harris * All rights reserved. @@ -740,6 +740,12 @@ int platform_default_i(char *name, int def) return def; } +void platform_get_x11_auth(char *display, int *proto, + unsigned char *data, int *datalen) +{ + /* SGT: I have no idea whether Mac X servers need anything here. */ +} + /* * Local Variables: * c-file-style: "simon" diff --git a/misc.c b/misc.c index 496d30e3..e4c6d4ac 100644 --- a/misc.c +++ b/misc.c @@ -174,9 +174,9 @@ int bufchain_size(bufchain *ch) return ch->buffersize; } -void bufchain_add(bufchain *ch, void *data, int len) +void bufchain_add(bufchain *ch, const void *data, int len) { - char *buf = (char *)data; + const char *buf = (const char *)data; ch->buffersize += len; diff --git a/misc.h b/misc.h index 21540a3b..456cda06 100644 --- a/misc.h +++ b/misc.h @@ -28,7 +28,7 @@ typedef struct bufchain_tag { void bufchain_init(bufchain *ch); void bufchain_clear(bufchain *ch); int bufchain_size(bufchain *ch); -void bufchain_add(bufchain *ch, void *data, int len); +void bufchain_add(bufchain *ch, const void *data, int len); void bufchain_prefix(bufchain *ch, void **data, int *len); void bufchain_consume(bufchain *ch, int len); void bufchain_fetch(bufchain *ch, void *data, int len); diff --git a/network.h b/network.h index e9ad518d..673831fb 100644 --- a/network.h +++ b/network.h @@ -24,8 +24,8 @@ struct socket_function_table { /* if p is NULL, it doesn't change the plug */ /* but it does return the one it's using */ void (*close) (Socket s); - int (*write) (Socket s, char *data, int len); - int (*write_oob) (Socket s, char *data, int len); + int (*write) (Socket s, const char *data, int len); + int (*write_oob) (Socket s, const char *data, int len); void (*flush) (Socket s); void (*set_private_ptr) (Socket s, void *ptr); void *(*get_private_ptr) (Socket s); diff --git a/proxy.c b/proxy.c index ce310012..a4847b9a 100644 --- a/proxy.c +++ b/proxy.c @@ -91,7 +91,7 @@ static void sk_proxy_close (Socket s) sfree(ps); } -static int sk_proxy_write (Socket s, char *data, int len) +static int sk_proxy_write (Socket s, const char *data, int len) { Proxy_Socket ps = (Proxy_Socket) s; @@ -102,7 +102,7 @@ static int sk_proxy_write (Socket s, char *data, int len) return sk_write(ps->sub_socket, data, len); } -static int sk_proxy_write_oob (Socket s, char *data, int len) +static int sk_proxy_write_oob (Socket s, const char *data, int len) { Proxy_Socket ps = (Proxy_Socket) s; diff --git a/putty.h b/putty.h index c4e6d987..6f32be3b 100644 --- a/putty.h +++ b/putty.h @@ -691,4 +691,14 @@ extern int cmdline_tooltype; void cmdline_error(char *, ...); +/* + * X11 auth mechanisms we know about. + */ +enum { + X11_NO_AUTH, + X11_MIT, /* MIT-MAGIC-COOKIE-1 */ + X11_NAUTHS +}; +extern const char *const x11_authnames[]; /* declared in x11fwd.c */ + #endif diff --git a/ssh.c b/ssh.c index eac31128..c0f06efa 100644 --- a/ssh.c +++ b/ssh.c @@ -3019,6 +3019,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) logevent("Requesting X11 forwarding"); ssh->x11auth = x11_invent_auth(proto, sizeof(proto), data, sizeof(data)); + x11_get_real_auth(ssh->x11auth, cfg.x11_display); if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) { send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING, PKT_STR, proto, PKT_STR, data, @@ -5068,6 +5069,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) logevent("Requesting X11 forwarding"); ssh->x11auth = x11_invent_auth(proto, sizeof(proto), data, sizeof(data)); + x11_get_real_auth(ssh->x11auth, cfg.x11_display); ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid); ssh2_pkt_addstring(ssh, "x11-req"); diff --git a/ssh.h b/ssh.h index 659a5431..0a38e949 100644 --- a/ssh.h +++ b/ssh.h @@ -273,6 +273,7 @@ extern void *x11_invent_auth(char *, int, char *, int); extern void x11_unthrottle(Socket s); 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); Bignum copybn(Bignum b); Bignum bn_power_2(int n); diff --git a/unix/ux_x11.c b/unix/ux_x11.c new file mode 100644 index 00000000..7753c854 --- /dev/null +++ b/unix/ux_x11.c @@ -0,0 +1,106 @@ +/* + * ux_x11.c: fetch local auth data for X forwarding. + */ + +#include +#include +#include "putty.h" + +void platform_get_x11_auth(char *display, int *protocol, + unsigned char *data, int *datalen) +{ + FILE *fp; + char *command; + int maxsize = *datalen; + char *localbuf; + + command = dupprintf("xauth list %s 2>/dev/null", display); + fp = popen(command, "r"); + sfree(command); + + if (!fp) + return; /* assume no auth */ + + localbuf = smalloc(maxsize); + + 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, proto; + 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. */ + } + pclose(fp); + sfree(localbuf); +} diff --git a/unix/uxnet.c b/unix/uxnet.c index 26f32be3..722ab474 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -298,8 +298,8 @@ static void sk_tcp_flush(Socket s) } static void sk_tcp_close(Socket s); -static int sk_tcp_write(Socket s, char *data, int len); -static int sk_tcp_write_oob(Socket s, char *data, int len); +static int sk_tcp_write(Socket s, const char *data, int len); +static int sk_tcp_write_oob(Socket s, const char *data, int len); static void sk_tcp_set_private_ptr(Socket s, void *ptr); static void *sk_tcp_get_private_ptr(Socket s); static void sk_tcp_set_frozen(Socket s, int is_frozen); @@ -726,7 +726,7 @@ void try_send(Actual_Socket s) } } -static int sk_tcp_write(Socket sock, char *buf, int len) +static int sk_tcp_write(Socket sock, const char *buf, int len) { Actual_Socket s = (Actual_Socket) sock; @@ -744,7 +744,7 @@ static int sk_tcp_write(Socket sock, char *buf, int len) return bufchain_size(&s->output_data); } -static int sk_tcp_write_oob(Socket sock, char *buf, int len) +static int sk_tcp_write_oob(Socket sock, const char *buf, int len) { Actual_Socket s = (Actual_Socket) sock; diff --git a/winmisc.c b/winmisc.c new file mode 100644 index 00000000..a4f666eb --- /dev/null +++ b/winmisc.c @@ -0,0 +1,14 @@ +/* + * winmisc.c: miscellaneous Windows-specific things. + */ + +#include +#include +#include +#include "putty.h" + +void platform_get_x11_auth(char *display, int *proto, + unsigned char *data, int *datalen) +{ + /* We don't support this at all under Windows. */ +} diff --git a/winnet.c b/winnet.c index 4bebe6d7..f2e84548 100644 --- a/winnet.c +++ b/winnet.c @@ -460,8 +460,8 @@ static void sk_tcp_flush(Socket s) } static void sk_tcp_close(Socket s); -static int sk_tcp_write(Socket s, char *data, int len); -static int sk_tcp_write_oob(Socket s, char *data, int len); +static int sk_tcp_write(Socket s, const char *data, int len); +static int sk_tcp_write_oob(Socket s, const char *data, int len); static void sk_tcp_set_private_ptr(Socket s, void *ptr); static void *sk_tcp_get_private_ptr(Socket s); static void sk_tcp_set_frozen(Socket s, int is_frozen); @@ -924,7 +924,7 @@ void try_send(Actual_Socket s) } } -static int sk_tcp_write(Socket sock, char *buf, int len) +static int sk_tcp_write(Socket sock, const char *buf, int len) { Actual_Socket s = (Actual_Socket) sock; @@ -942,7 +942,7 @@ static int sk_tcp_write(Socket sock, char *buf, int len) return bufchain_size(&s->output_data); } -static int sk_tcp_write_oob(Socket sock, char *buf, int len) +static int sk_tcp_write_oob(Socket sock, const char *buf, int len) { Actual_Socket s = (Actual_Socket) sock; diff --git a/x11fwd.c b/x11fwd.c index 80e0eb57..184a3302 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -1,5 +1,6 @@ #include #include +#include #include "putty.h" #include "ssh.h" @@ -50,11 +51,19 @@ #define PUT_16BIT(endian, cp, val) \ (endian=='B' ? PUT_16BIT_MSB_FIRST(cp, val) : PUT_16BIT_LSB_FIRST(cp, val)) +const char *const x11_authnames[] = { + "", "MIT-MAGIC-COOKIE-1" +}; + struct X11Auth { - unsigned char data[64]; - int len; + unsigned char fakedata[64], realdata[64]; + int fakeproto, realproto; + int fakelen, reallen; }; +extern void platform_get_x11_auth(char *display, int *proto, + unsigned char *data, int *datalen); + struct X11Private { const struct plug_function_table *fn; /* the above variable absolutely *must* be the first in this structure */ @@ -76,30 +85,51 @@ void *x11_invent_auth(char *proto, int protomaxlen, char ourdata[64]; int i; + auth->fakeproto = X11_MIT; + /* MIT-MAGIC-COOKIE-1. Cookie size is 128 bits (16 bytes). */ - auth->len = 16; + auth->fakelen = 16; for (i = 0; i < 16; i++) - auth->data[i] = random_byte(); + auth->fakedata[i] = random_byte(); /* Now format for the recipient. */ - strncpy(proto, "MIT-MAGIC-COOKIE-1", protomaxlen); + strncpy(proto, x11_authnames[auth->fakeproto], protomaxlen); ourdata[0] = '\0'; - for (i = 0; i < auth->len; i++) - sprintf(ourdata + strlen(ourdata), "%02x", auth->data[i]); + for (i = 0; i < auth->fakelen; i++) + sprintf(ourdata + strlen(ourdata), "%02x", auth->fakedata[i]); strncpy(data, ourdata, datamaxlen); return auth; } +/* + * Fetch the real auth data for a given display string, and store + * it in an X11Auth structure. Returns NULL on success, or an error + * string. + */ +void x11_get_real_auth(void *authv, char *display) +{ + struct X11Auth *auth = (struct X11Auth *)authv; + + 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); +} + static int x11_verify(struct X11Auth *auth, char *proto, unsigned char *data, int dlen) { - if (strcmp(proto, "MIT-MAGIC-COOKIE-1") != 0) + if (strcmp(proto, x11_authnames[auth->fakeproto]) != 0) return 0; /* wrong protocol attempted */ - if (dlen != auth->len) - return 0; /* cookie was wrong length */ - if (memcmp(auth->data, data, dlen) != 0) - return 0; /* cookie was wrong cookie! */ + if (auth->fakeproto == X11_MIT) { + if (dlen != auth->fakelen) + return 0; /* cookie was wrong length */ + if (memcmp(auth->fakedata, data, dlen) != 0) + return 0; /* cookie was wrong cookie! */ + } + /* implement other protocols here if ever required */ return 1; } @@ -344,12 +374,36 @@ int x11_send(Socket s, char *data, int len) /* * Now we know we're going to accept the connection. Strip - * the auth data. (TODO: if we ever work out how, we should - * replace some real auth data in here.) + * the fake auth data, and optionally put real auth data in + * instead. */ - PUT_16BIT(pr->firstpkt[0], pr->firstpkt + 6, 0); /* auth proto */ - PUT_16BIT(pr->firstpkt[0], pr->firstpkt + 8, 0); /* auth data */ - sk_write(s, (char *)pr->firstpkt, 12); + { + char realauthdata[64]; + int realauthlen = 0; + int authstrlen = strlen(x11_authnames[pr->auth->realproto]); + static const char zeroes[4] = { 0,0,0,0 }; + + if (pr->auth->realproto == X11_MIT) { + assert(pr->auth->reallen <= lenof(realauthdata)); + realauthlen = pr->auth->reallen; + memcpy(realauthdata, pr->auth->realdata, realauthlen); + } + /* implement other auth methods here if required */ + + PUT_16BIT(pr->firstpkt[0], pr->firstpkt + 6, authstrlen); + PUT_16BIT(pr->firstpkt[0], pr->firstpkt + 8, realauthlen); + + sk_write(s, (char *)pr->firstpkt, 12); + + if (authstrlen) { + sk_write(s, x11_authnames[pr->auth->realproto], authstrlen); + sk_write(s, zeroes, 3 & (-authstrlen)); + } + if (realauthlen) { + sk_write(s, realauthdata, realauthlen); + sk_write(s, zeroes, 3 & (-realauthlen)); + } + } pr->verified = 1; } -- 2.11.0