mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 09:27:59 +00:00
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.) [originally from svn r2536]
This commit is contained in:
parent
2e8b94c8d4
commit
86977efa81
4
Recipe
4
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
|
||||
|
@ -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"
|
||||
|
4
misc.c
4
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;
|
||||
|
||||
|
2
misc.h
2
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);
|
||||
|
@ -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);
|
||||
|
4
proxy.c
4
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;
|
||||
|
||||
|
10
putty.h
10
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
|
||||
|
2
ssh.c
2
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");
|
||||
|
1
ssh.h
1
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);
|
||||
|
106
unix/ux_x11.c
Normal file
106
unix/ux_x11.c
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* ux_x11.c: fetch local auth data for X forwarding.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#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);
|
||||
}
|
@ -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;
|
||||
|
||||
|
14
winmisc.c
Normal file
14
winmisc.c
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* winmisc.c: miscellaneous Windows-specific things.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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. */
|
||||
}
|
8
winnet.c
8
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;
|
||||
|
||||
|
90
x11fwd.c
90
x11fwd.c
@ -1,5 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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))
|
||||
|
||||
struct X11Auth {
|
||||
unsigned char data[64];
|
||||
int len;
|
||||
const char *const x11_authnames[] = {
|
||||
"", "MIT-MAGIC-COOKIE-1"
|
||||
};
|
||||
|
||||
struct X11Auth {
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user