Mercurial > 510Connectbot
diff src/ch/ethz/ssh2/channel/RemoteX11AcceptThread.java @ 308:42b15aaa7ac7 ganymed
merge
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Wed, 30 Jul 2014 14:21:50 -0700 |
parents | 071eccdff8ea |
children |
line wrap: on
line diff
--- a/src/ch/ethz/ssh2/channel/RemoteX11AcceptThread.java Wed Jul 30 13:38:04 2014 -0700 +++ b/src/ch/ethz/ssh2/channel/RemoteX11AcceptThread.java Wed Jul 30 14:21:50 2014 -0700 @@ -18,229 +18,194 @@ * @author Christian Plattner * @version $Id: RemoteX11AcceptThread.java 119 2014-04-12 20:30:58Z dkocher@sudo.ch $ */ -public class RemoteX11AcceptThread extends Thread -{ - private static final Logger log = Logger.getLogger(RemoteX11AcceptThread.class); - - Channel c; - - String remoteOriginatorAddress; - int remoteOriginatorPort; +public class RemoteX11AcceptThread extends Thread { + private static final Logger log = Logger.getLogger(RemoteX11AcceptThread.class); - Socket s; + Channel c; - public RemoteX11AcceptThread(Channel c, String remoteOriginatorAddress, int remoteOriginatorPort) - { - this.c = c; - this.remoteOriginatorAddress = remoteOriginatorAddress; - this.remoteOriginatorPort = remoteOriginatorPort; - } + String remoteOriginatorAddress; + int remoteOriginatorPort; - @Override - public void run() - { - try - { - /* Send Open Confirmation */ - - c.cm.sendOpenConfirmation(c); - - /* Read startup packet from client */ + Socket s; - OutputStream remote_os = c.getStdinStream(); - InputStream remote_is = c.getStdoutStream(); - - /* The following code is based on the protocol description given in: - * Scheifler/Gettys, - * X Windows System: Core and Extension Protocols: - * X Version 11, Releases 6 and 6.1 ISBN 1-55558-148-X - * (from the ETH library - after being here for almost ten - * years one of the few books I borrowed... sad but true =) - */ + public RemoteX11AcceptThread(Channel c, String remoteOriginatorAddress, int remoteOriginatorPort) { + this.c = c; + this.remoteOriginatorAddress = remoteOriginatorAddress; + this.remoteOriginatorPort = remoteOriginatorPort; + } - /* - * Client startup: - * - * 1 0X42 MSB first/0x6c lSB first - byteorder - * 1 - unused - * 2 card16 - protocol-major-version - * 2 card16 - protocol-minor-version - * 2 n - lenght of authorization-protocol-name - * 2 d - lenght of authorization-protocol-data - * 2 - unused - * string8 - authorization-protocol-name - * p - unused, p=pad(n) - * string8 - authorization-protocol-data - * q - unused, q=pad(d) - * - * pad(X) = (4 - (X mod 4)) mod 4 - * - * Server response: - * - * 1 (0 failed, 2 authenticate, 1 success) - * ... - * - */ - - /* Later on we will simply forward the first 6 header bytes to the "real" X11 server */ - - byte[] header = new byte[6]; - - if (remote_is.read(header) != 6) - throw new IOException("Unexpected EOF on X11 startup!"); - - if ((header[0] != 0x42) && (header[0] != 0x6c)) // 0x42 MSB first, 0x6C LSB first - throw new IOException("Unknown endian format in X11 message!"); + @Override + public void run() { + try { + /* Send Open Confirmation */ + c.cm.sendOpenConfirmation(c); + /* Read startup packet from client */ + OutputStream remote_os = c.getStdinStream(); + InputStream remote_is = c.getStdoutStream(); + /* The following code is based on the protocol description given in: + * Scheifler/Gettys, + * X Windows System: Core and Extension Protocols: + * X Version 11, Releases 6 and 6.1 ISBN 1-55558-148-X + * (from the ETH library - after being here for almost ten + * years one of the few books I borrowed... sad but true =) + */ + /* + * Client startup: + * + * 1 0X42 MSB first/0x6c lSB first - byteorder + * 1 - unused + * 2 card16 - protocol-major-version + * 2 card16 - protocol-minor-version + * 2 n - lenght of authorization-protocol-name + * 2 d - lenght of authorization-protocol-data + * 2 - unused + * string8 - authorization-protocol-name + * p - unused, p=pad(n) + * string8 - authorization-protocol-data + * q - unused, q=pad(d) + * + * pad(X) = (4 - (X mod 4)) mod 4 + * + * Server response: + * + * 1 (0 failed, 2 authenticate, 1 success) + * ... + * + */ + /* Later on we will simply forward the first 6 header bytes to the "real" X11 server */ + byte[] header = new byte[6]; - /* Yes, I came up with this myself - shall I file an application for a patent? =) */ - - int idxMSB = (header[0] == 0x42) ? 0 : 1; + if (remote_is.read(header) != 6) + throw new IOException("Unexpected EOF on X11 startup!"); - /* Read authorization data header */ - - byte[] auth_buff = new byte[6]; + if ((header[0] != 0x42) && (header[0] != 0x6c)) // 0x42 MSB first, 0x6C LSB first + throw new IOException("Unknown endian format in X11 message!"); - if (remote_is.read(auth_buff) != 6) - throw new IOException("Unexpected EOF on X11 startup!"); + /* Yes, I came up with this myself - shall I file an application for a patent? =) */ + int idxMSB = (header[0] == 0x42) ? 0 : 1; + /* Read authorization data header */ + byte[] auth_buff = new byte[6]; - int authProtocolNameLength = ((auth_buff[idxMSB] & 0xff) << 8) | (auth_buff[1 - idxMSB] & 0xff); - int authProtocolDataLength = ((auth_buff[2 + idxMSB] & 0xff) << 8) | (auth_buff[3 - idxMSB] & 0xff); + if (remote_is.read(auth_buff) != 6) + throw new IOException("Unexpected EOF on X11 startup!"); - if ((authProtocolNameLength > 256) || (authProtocolDataLength > 256)) - throw new IOException("Buggy X11 authorization data"); + int authProtocolNameLength = ((auth_buff[idxMSB] & 0xff) << 8) | (auth_buff[1 - idxMSB] & 0xff); + int authProtocolDataLength = ((auth_buff[2 + idxMSB] & 0xff) << 8) | (auth_buff[3 - idxMSB] & 0xff); - int authProtocolNamePadding = ((4 - (authProtocolNameLength % 4)) % 4); - int authProtocolDataPadding = ((4 - (authProtocolDataLength % 4)) % 4); + if ((authProtocolNameLength > 256) || (authProtocolDataLength > 256)) + throw new IOException("Buggy X11 authorization data"); - byte[] authProtocolName = new byte[authProtocolNameLength]; - byte[] authProtocolData = new byte[authProtocolDataLength]; - - byte[] paddingBuffer = new byte[4]; + int authProtocolNamePadding = ((4 - (authProtocolNameLength % 4)) % 4); + int authProtocolDataPadding = ((4 - (authProtocolDataLength % 4)) % 4); + byte[] authProtocolName = new byte[authProtocolNameLength]; + byte[] authProtocolData = new byte[authProtocolDataLength]; + byte[] paddingBuffer = new byte[4]; - if (remote_is.read(authProtocolName) != authProtocolNameLength) - throw new IOException("Unexpected EOF on X11 startup! (authProtocolName)"); + if (remote_is.read(authProtocolName) != authProtocolNameLength) + throw new IOException("Unexpected EOF on X11 startup! (authProtocolName)"); - if (remote_is.read(paddingBuffer, 0, authProtocolNamePadding) != authProtocolNamePadding) - throw new IOException("Unexpected EOF on X11 startup! (authProtocolNamePadding)"); + if (remote_is.read(paddingBuffer, 0, authProtocolNamePadding) != authProtocolNamePadding) + throw new IOException("Unexpected EOF on X11 startup! (authProtocolNamePadding)"); - if (remote_is.read(authProtocolData) != authProtocolDataLength) - throw new IOException("Unexpected EOF on X11 startup! (authProtocolData)"); + if (remote_is.read(authProtocolData) != authProtocolDataLength) + throw new IOException("Unexpected EOF on X11 startup! (authProtocolData)"); - if (remote_is.read(paddingBuffer, 0, authProtocolDataPadding) != authProtocolDataPadding) - throw new IOException("Unexpected EOF on X11 startup! (authProtocolDataPadding)"); + if (remote_is.read(paddingBuffer, 0, authProtocolDataPadding) != authProtocolDataPadding) + throw new IOException("Unexpected EOF on X11 startup! (authProtocolDataPadding)"); - if ("MIT-MAGIC-COOKIE-1".equals(StringEncoder.GetString(authProtocolName)) == false) - throw new IOException("Unknown X11 authorization protocol!"); - - if (authProtocolDataLength != 16) - throw new IOException("Wrong data length for X11 authorization data!"); + if ("MIT-MAGIC-COOKIE-1".equals(StringEncoder.GetString(authProtocolName)) == false) + throw new IOException("Unknown X11 authorization protocol!"); - StringBuilder tmp = new StringBuilder(32); - for (int i = 0; i < authProtocolData.length; i++) - { - String digit2 = Integer.toHexString(authProtocolData[i] & 0xff); - tmp.append((digit2.length() == 2) ? digit2 : "0" + digit2); - } - String hexEncodedFakeCookie = tmp.toString(); + if (authProtocolDataLength != 16) + throw new IOException("Wrong data length for X11 authorization data!"); + + StringBuilder tmp = new StringBuilder(32); - /* Order is very important here - it may be that a certain x11 forwarding - * gets disabled right in the moment when we check and register our connection - * */ + for (int i = 0; i < authProtocolData.length; i++) { + String digit2 = Integer.toHexString(authProtocolData[i] & 0xff); + tmp.append((digit2.length() == 2) ? digit2 : "0" + digit2); + } - synchronized (c) - { - /* Please read the comment in Channel.java */ - c.hexX11FakeCookie = hexEncodedFakeCookie; - } + String hexEncodedFakeCookie = tmp.toString(); - /* Now check our fake cookie directory to see if we produced this cookie */ - - X11ServerData sd = c.cm.checkX11Cookie(hexEncodedFakeCookie); + /* Order is very important here - it may be that a certain x11 forwarding + * gets disabled right in the moment when we check and register our connection + * */ - if (sd == null) - throw new IOException("Invalid X11 cookie received."); + synchronized (c) { + /* Please read the comment in Channel.java */ + c.hexX11FakeCookie = hexEncodedFakeCookie; + } - /* If the session which corresponds to this cookie is closed then we will - * detect this: the session's close code will close all channels - * with the session's assigned x11 fake cookie. - */ - - s = new Socket(sd.hostname, sd.port); - - OutputStream x11_os = s.getOutputStream(); - InputStream x11_is = s.getInputStream(); + /* Now check our fake cookie directory to see if we produced this cookie */ + X11ServerData sd = c.cm.checkX11Cookie(hexEncodedFakeCookie); - /* Now we are sending the startup packet to the real X11 server */ - - x11_os.write(header); + if (sd == null) + throw new IOException("Invalid X11 cookie received."); - if (sd.x11_magic_cookie == null) - { - byte[] emptyAuthData = new byte[6]; - /* empty auth data, hopefully you are connecting to localhost =) */ - x11_os.write(emptyAuthData); - } - else - { - if (sd.x11_magic_cookie.length != 16) - throw new IOException("The real X11 cookie has an invalid length!"); + /* If the session which corresponds to this cookie is closed then we will + * detect this: the session's close code will close all channels + * with the session's assigned x11 fake cookie. + */ + s = new Socket(sd.hostname, sd.port); + OutputStream x11_os = s.getOutputStream(); + InputStream x11_is = s.getInputStream(); + /* Now we are sending the startup packet to the real X11 server */ + x11_os.write(header); - /* send X11 cookie specified by client */ - x11_os.write(auth_buff); - x11_os.write(authProtocolName); /* re-use */ - x11_os.write(paddingBuffer, 0, authProtocolNamePadding); - x11_os.write(sd.x11_magic_cookie); - x11_os.write(paddingBuffer, 0, authProtocolDataPadding); - } - - x11_os.flush(); + if (sd.x11_magic_cookie == null) { + byte[] emptyAuthData = new byte[6]; + /* empty auth data, hopefully you are connecting to localhost =) */ + x11_os.write(emptyAuthData); + } + else { + if (sd.x11_magic_cookie.length != 16) + throw new IOException("The real X11 cookie has an invalid length!"); - /* Start forwarding traffic */ - - StreamForwarder r2l = new StreamForwarder(c, null, null, remote_is, x11_os, "RemoteToX11"); - StreamForwarder l2r = new StreamForwarder(c, null, null, x11_is, remote_os, "X11ToRemote"); + /* send X11 cookie specified by client */ + x11_os.write(auth_buff); + x11_os.write(authProtocolName); /* re-use */ + x11_os.write(paddingBuffer, 0, authProtocolNamePadding); + x11_os.write(sd.x11_magic_cookie); + x11_os.write(paddingBuffer, 0, authProtocolDataPadding); + } - /* No need to start two threads, one can be executed in the current thread */ - - r2l.setDaemon(true); - r2l.start(); - l2r.run(); + x11_os.flush(); + /* Start forwarding traffic */ + StreamForwarder r2l = new StreamForwarder(c, null, null, remote_is, x11_os, "RemoteToX11"); + StreamForwarder l2r = new StreamForwarder(c, null, null, x11_is, remote_os, "X11ToRemote"); + /* No need to start two threads, one can be executed in the current thread */ + r2l.setDaemon(true); + r2l.start(); + l2r.run(); - while (r2l.isAlive()) - { - try - { - r2l.join(); - } - catch (InterruptedException ignored) - { - } - } + while (r2l.isAlive()) { + try { + r2l.join(); + } + catch (InterruptedException ignored) { + } + } - /* If the channel is already closed, then this is a no-op */ + /* If the channel is already closed, then this is a no-op */ + c.cm.closeChannel(c, "EOF on both X11 streams reached.", true); + s.close(); + } + catch (IOException e) { + log.warning("IOException in X11 proxy code: " + e.getMessage()); - c.cm.closeChannel(c, "EOF on both X11 streams reached.", true); - s.close(); - } - catch (IOException e) - { - log.warning("IOException in X11 proxy code: " + e.getMessage()); + try { + c.cm.closeChannel(c, e, true); + } + catch (IOException ignored) { + } - try - { - c.cm.closeChannel(c, e, true); - } - catch (IOException ignored) - { - } - try - { - if (s != null) - s.close(); - } - catch (IOException ignored) - { - } - } - } + try { + if (s != null) + s.close(); + } + catch (IOException ignored) { + } + } + } }