Mercurial > 510Connectbot
annotate src/ch/ethz/ssh2/channel/RemoteX11AcceptThread.java @ 396:1f625669d89d
Added tag stable-1.9.0.6 for changeset 74d527fe7f5f
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Fri, 19 Sep 2014 15:27:51 -0700 |
parents | 071eccdff8ea |
children |
rev | line source |
---|---|
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
1 /* |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
2 * Copyright (c) 2006-2011 Christian Plattner. All rights reserved. |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
3 * Please refer to the LICENSE.txt for licensing details. |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
4 */ |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
5 package ch.ethz.ssh2.channel; |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
6 |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
7 import java.io.IOException; |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
8 import java.io.InputStream; |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
9 import java.io.OutputStream; |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
10 import java.net.Socket; |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
11 |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
12 import ch.ethz.ssh2.log.Logger; |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
13 import ch.ethz.ssh2.util.StringEncoder; |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
14 |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
15 /** |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
16 * RemoteX11AcceptThread. |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
17 * |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
18 * @author Christian Plattner |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
19 * @version $Id: RemoteX11AcceptThread.java 119 2014-04-12 20:30:58Z dkocher@sudo.ch $ |
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
20 */ |
307 | 21 public class RemoteX11AcceptThread extends Thread { |
22 private static final Logger log = Logger.getLogger(RemoteX11AcceptThread.class); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
23 |
307 | 24 Channel c; |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
25 |
307 | 26 String remoteOriginatorAddress; |
27 int remoteOriginatorPort; | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
28 |
307 | 29 Socket s; |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
30 |
307 | 31 public RemoteX11AcceptThread(Channel c, String remoteOriginatorAddress, int remoteOriginatorPort) { |
32 this.c = c; | |
33 this.remoteOriginatorAddress = remoteOriginatorAddress; | |
34 this.remoteOriginatorPort = remoteOriginatorPort; | |
35 } | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
36 |
307 | 37 @Override |
38 public void run() { | |
39 try { | |
40 /* Send Open Confirmation */ | |
41 c.cm.sendOpenConfirmation(c); | |
42 /* Read startup packet from client */ | |
43 OutputStream remote_os = c.getStdinStream(); | |
44 InputStream remote_is = c.getStdoutStream(); | |
45 /* The following code is based on the protocol description given in: | |
46 * Scheifler/Gettys, | |
47 * X Windows System: Core and Extension Protocols: | |
48 * X Version 11, Releases 6 and 6.1 ISBN 1-55558-148-X | |
49 * (from the ETH library - after being here for almost ten | |
50 * years one of the few books I borrowed... sad but true =) | |
51 */ | |
52 /* | |
53 * Client startup: | |
54 * | |
55 * 1 0X42 MSB first/0x6c lSB first - byteorder | |
56 * 1 - unused | |
57 * 2 card16 - protocol-major-version | |
58 * 2 card16 - protocol-minor-version | |
59 * 2 n - lenght of authorization-protocol-name | |
60 * 2 d - lenght of authorization-protocol-data | |
61 * 2 - unused | |
62 * string8 - authorization-protocol-name | |
63 * p - unused, p=pad(n) | |
64 * string8 - authorization-protocol-data | |
65 * q - unused, q=pad(d) | |
66 * | |
67 * pad(X) = (4 - (X mod 4)) mod 4 | |
68 * | |
69 * Server response: | |
70 * | |
71 * 1 (0 failed, 2 authenticate, 1 success) | |
72 * ... | |
73 * | |
74 */ | |
75 /* Later on we will simply forward the first 6 header bytes to the "real" X11 server */ | |
76 byte[] header = new byte[6]; | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
77 |
307 | 78 if (remote_is.read(header) != 6) |
79 throw new IOException("Unexpected EOF on X11 startup!"); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
80 |
307 | 81 if ((header[0] != 0x42) && (header[0] != 0x6c)) // 0x42 MSB first, 0x6C LSB first |
82 throw new IOException("Unknown endian format in X11 message!"); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
83 |
307 | 84 /* Yes, I came up with this myself - shall I file an application for a patent? =) */ |
85 int idxMSB = (header[0] == 0x42) ? 0 : 1; | |
86 /* Read authorization data header */ | |
87 byte[] auth_buff = new byte[6]; | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
88 |
307 | 89 if (remote_is.read(auth_buff) != 6) |
90 throw new IOException("Unexpected EOF on X11 startup!"); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
91 |
307 | 92 int authProtocolNameLength = ((auth_buff[idxMSB] & 0xff) << 8) | (auth_buff[1 - idxMSB] & 0xff); |
93 int authProtocolDataLength = ((auth_buff[2 + idxMSB] & 0xff) << 8) | (auth_buff[3 - idxMSB] & 0xff); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
94 |
307 | 95 if ((authProtocolNameLength > 256) || (authProtocolDataLength > 256)) |
96 throw new IOException("Buggy X11 authorization data"); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
97 |
307 | 98 int authProtocolNamePadding = ((4 - (authProtocolNameLength % 4)) % 4); |
99 int authProtocolDataPadding = ((4 - (authProtocolDataLength % 4)) % 4); | |
100 byte[] authProtocolName = new byte[authProtocolNameLength]; | |
101 byte[] authProtocolData = new byte[authProtocolDataLength]; | |
102 byte[] paddingBuffer = new byte[4]; | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
103 |
307 | 104 if (remote_is.read(authProtocolName) != authProtocolNameLength) |
105 throw new IOException("Unexpected EOF on X11 startup! (authProtocolName)"); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
106 |
307 | 107 if (remote_is.read(paddingBuffer, 0, authProtocolNamePadding) != authProtocolNamePadding) |
108 throw new IOException("Unexpected EOF on X11 startup! (authProtocolNamePadding)"); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
109 |
307 | 110 if (remote_is.read(authProtocolData) != authProtocolDataLength) |
111 throw new IOException("Unexpected EOF on X11 startup! (authProtocolData)"); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
112 |
307 | 113 if (remote_is.read(paddingBuffer, 0, authProtocolDataPadding) != authProtocolDataPadding) |
114 throw new IOException("Unexpected EOF on X11 startup! (authProtocolDataPadding)"); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
115 |
307 | 116 if ("MIT-MAGIC-COOKIE-1".equals(StringEncoder.GetString(authProtocolName)) == false) |
117 throw new IOException("Unknown X11 authorization protocol!"); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
118 |
307 | 119 if (authProtocolDataLength != 16) |
120 throw new IOException("Wrong data length for X11 authorization data!"); | |
121 | |
122 StringBuilder tmp = new StringBuilder(32); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
123 |
307 | 124 for (int i = 0; i < authProtocolData.length; i++) { |
125 String digit2 = Integer.toHexString(authProtocolData[i] & 0xff); | |
126 tmp.append((digit2.length() == 2) ? digit2 : "0" + digit2); | |
127 } | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
128 |
307 | 129 String hexEncodedFakeCookie = tmp.toString(); |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
130 |
307 | 131 /* Order is very important here - it may be that a certain x11 forwarding |
132 * gets disabled right in the moment when we check and register our connection | |
133 * */ | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
134 |
307 | 135 synchronized (c) { |
136 /* Please read the comment in Channel.java */ | |
137 c.hexX11FakeCookie = hexEncodedFakeCookie; | |
138 } | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
139 |
307 | 140 /* Now check our fake cookie directory to see if we produced this cookie */ |
141 X11ServerData sd = c.cm.checkX11Cookie(hexEncodedFakeCookie); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
142 |
307 | 143 if (sd == null) |
144 throw new IOException("Invalid X11 cookie received."); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
145 |
307 | 146 /* If the session which corresponds to this cookie is closed then we will |
147 * detect this: the session's close code will close all channels | |
148 * with the session's assigned x11 fake cookie. | |
149 */ | |
150 s = new Socket(sd.hostname, sd.port); | |
151 OutputStream x11_os = s.getOutputStream(); | |
152 InputStream x11_is = s.getInputStream(); | |
153 /* Now we are sending the startup packet to the real X11 server */ | |
154 x11_os.write(header); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
155 |
307 | 156 if (sd.x11_magic_cookie == null) { |
157 byte[] emptyAuthData = new byte[6]; | |
158 /* empty auth data, hopefully you are connecting to localhost =) */ | |
159 x11_os.write(emptyAuthData); | |
160 } | |
161 else { | |
162 if (sd.x11_magic_cookie.length != 16) | |
163 throw new IOException("The real X11 cookie has an invalid length!"); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
164 |
307 | 165 /* send X11 cookie specified by client */ |
166 x11_os.write(auth_buff); | |
167 x11_os.write(authProtocolName); /* re-use */ | |
168 x11_os.write(paddingBuffer, 0, authProtocolNamePadding); | |
169 x11_os.write(sd.x11_magic_cookie); | |
170 x11_os.write(paddingBuffer, 0, authProtocolDataPadding); | |
171 } | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
172 |
307 | 173 x11_os.flush(); |
174 /* Start forwarding traffic */ | |
175 StreamForwarder r2l = new StreamForwarder(c, null, null, remote_is, x11_os, "RemoteToX11"); | |
176 StreamForwarder l2r = new StreamForwarder(c, null, null, x11_is, remote_os, "X11ToRemote"); | |
177 /* No need to start two threads, one can be executed in the current thread */ | |
178 r2l.setDaemon(true); | |
179 r2l.start(); | |
180 l2r.run(); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
181 |
307 | 182 while (r2l.isAlive()) { |
183 try { | |
184 r2l.join(); | |
185 } | |
186 catch (InterruptedException ignored) { | |
187 } | |
188 } | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
189 |
307 | 190 /* If the channel is already closed, then this is a no-op */ |
191 c.cm.closeChannel(c, "EOF on both X11 streams reached.", true); | |
192 s.close(); | |
193 } | |
194 catch (IOException e) { | |
195 log.warning("IOException in X11 proxy code: " + e.getMessage()); | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
196 |
307 | 197 try { |
198 c.cm.closeChannel(c, e, true); | |
199 } | |
200 catch (IOException ignored) { | |
201 } | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
202 |
307 | 203 try { |
204 if (s != null) | |
205 s.close(); | |
206 } | |
207 catch (IOException ignored) { | |
208 } | |
209 } | |
210 } | |
273
91a31873c42a
start conversion from trilead to ganymed
Carl Byington <carl@five-ten-sg.com>
parents:
diff
changeset
|
211 } |