KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > ch > ethz > ssh2 > channel > RemoteX11AcceptThread


1
2 package ch.ethz.ssh2.channel;
3
4 import java.io.IOException JavaDoc;
5 import java.io.InputStream JavaDoc;
6 import java.io.OutputStream JavaDoc;
7 import java.net.Socket JavaDoc;
8
9 import ch.ethz.ssh2.log.Logger;
10
11 /**
12  * RemoteX11AcceptThread.
13  *
14  * @author Christian Plattner, plattner@inf.ethz.ch
15  * @version $Id: RemoteX11AcceptThread.java,v 1.5 2006/02/14 15:17:37 cplattne Exp $
16  */

17 public class RemoteX11AcceptThread extends Thread JavaDoc
18 {
19     private static final Logger log = Logger.getLogger(RemoteX11AcceptThread.class);
20
21     Channel c;
22
23     String JavaDoc remoteOriginatorAddress;
24     int remoteOriginatorPort;
25
26     Socket JavaDoc s;
27
28     public RemoteX11AcceptThread(Channel c, String JavaDoc remoteOriginatorAddress, int remoteOriginatorPort)
29     {
30         this.c = c;
31         this.remoteOriginatorAddress = remoteOriginatorAddress;
32         this.remoteOriginatorPort = remoteOriginatorPort;
33     }
34
35     public void run()
36     {
37         try
38         {
39             /* Send Open Confirmation */
40
41             c.cm.sendOpenConfirmation(c);
42
43             /* Read startup packet from client */
44
45             OutputStream JavaDoc remote_os = c.getStdinStream();
46             InputStream JavaDoc remote_is = c.getStdoutStream();
47
48             /* The following code is based on the protocol description given in:
49              * Scheifler/Gettys,
50              * X Windows System: Core and Extension Protocols:
51              * X Version 11, Releases 6 and 6.1 ISBN 1-55558-148-X
52              * (from the ETH library - after being here for almost ten
53              * years one of the few books I borrowed... sad but true =)
54              */

55
56             /*
57              * Client startup:
58              *
59              * 1 0X42 MSB first/0x6c lSB first - byteorder
60              * 1 - unused
61              * 2 card16 - protocol-major-version
62              * 2 card16 - protocol-minor-version
63              * 2 n - lenght of authorization-protocol-name
64              * 2 d - lenght of authorization-protocol-data
65              * 2 - unused
66              * string8 - authorization-protocol-name
67              * p - unused, p=pad(n)
68              * string8 - authorization-protocol-data
69              * q - unused, q=pad(d)
70              *
71              * pad(X) = (4 - (X mod 4)) mod 4
72              *
73              * Server response:
74              *
75              * 1 (0 failed, 2 authenticate, 1 success)
76              * ...
77              *
78              */

79
80             /* Later on we will simply forward the first 6 header bytes to the "real" X11 server */
81
82             byte[] header = new byte[6];
83
84             if (remote_is.read(header) != 6)
85                 throw new IOException JavaDoc("Unexpected EOF on X11 startup!");
86
87             if ((header[0] != 0x42) && (header[0] != 0x6c)) // 0x42 MSB first, 0x6C LSB first
88
throw new IOException JavaDoc("Unknown endian format in X11 message!");
89
90             /* Yes, I came up with this myself - shall I file an application for a patent? =) */
91             
92             int idxMSB = (header[0] == 0x42) ? 0 : 1;
93
94             /* Read authorization data header */
95
96             byte[] auth_buff = new byte[6];
97
98             if (remote_is.read(auth_buff) != 6)
99                 throw new IOException JavaDoc("Unexpected EOF on X11 startup!");
100
101             int authProtocolNameLength = ((auth_buff[idxMSB] & 0xff) << 8) | (auth_buff[1 - idxMSB] & 0xff);
102             int authProtocolDataLength = ((auth_buff[2 + idxMSB] & 0xff) << 8) | (auth_buff[3 - idxMSB] & 0xff);
103
104             if ((authProtocolNameLength > 256) || (authProtocolDataLength > 256))
105                 throw new IOException JavaDoc("Buggy X11 authorization data");
106
107             int authProtocolNamePadding = ((4 - (authProtocolNameLength % 4)) % 4);
108             int authProtocolDataPadding = ((4 - (authProtocolDataLength % 4)) % 4);
109
110             byte[] authProtocolName = new byte[authProtocolNameLength];
111             byte[] authProtocolData = new byte[authProtocolDataLength];
112
113             byte[] paddingBuffer = new byte[4];
114
115             if (remote_is.read(authProtocolName) != authProtocolNameLength)
116                 throw new IOException JavaDoc("Unexpected EOF on X11 startup! (authProtocolName)");
117
118             if (remote_is.read(paddingBuffer, 0, authProtocolNamePadding) != authProtocolNamePadding)
119                 throw new IOException JavaDoc("Unexpected EOF on X11 startup! (authProtocolNamePadding)");
120
121             if (remote_is.read(authProtocolData) != authProtocolDataLength)
122                 throw new IOException JavaDoc("Unexpected EOF on X11 startup! (authProtocolData)");
123
124             if (remote_is.read(paddingBuffer, 0, authProtocolDataPadding) != authProtocolDataPadding)
125                 throw new IOException JavaDoc("Unexpected EOF on X11 startup! (authProtocolDataPadding)");
126
127             if ("MIT-MAGIC-COOKIE-1".equals(new String JavaDoc(authProtocolName)) == false)
128                 throw new IOException JavaDoc("Unknown X11 authorization protocol!");
129
130             if (authProtocolDataLength != 16)
131                 throw new IOException JavaDoc("Wrong data length for X11 authorization data!");
132
133             StringBuffer JavaDoc tmp = new StringBuffer JavaDoc(32);
134             for (int i = 0; i < authProtocolData.length; i++)
135             {
136                 String JavaDoc digit2 = Integer.toHexString(authProtocolData[i] & 0xff);
137                 tmp.append((digit2.length() == 2) ? digit2 : "0" + digit2);
138             }
139             String JavaDoc hexEncodedFakeCookie = tmp.toString();
140
141             /* Order is very important here - it may be that a certain x11 forwarding
142              * gets disabled right in the moment when we check and register our connection
143              * */

144
145             synchronized (c)
146             {
147                 /* Please read the comment in Channel.java */
148                 c.hexX11FakeCookie = hexEncodedFakeCookie;
149             }
150
151             /* Now check our fake cookie directory to see if we produced this cookie */
152
153             X11ServerData sd = c.cm.checkX11Cookie(hexEncodedFakeCookie);
154
155             if (sd == null)
156                 throw new IOException JavaDoc("Invalid X11 cookie received.");
157
158             /* If the session which corresponds to this cookie is closed then we will
159              * detect this: the session's close code will close all channels
160              * with the session's assigned x11 fake cookie.
161              */

162
163             s = new Socket JavaDoc(sd.hostname, sd.port);
164
165             OutputStream JavaDoc x11_os = s.getOutputStream();
166             InputStream JavaDoc x11_is = s.getInputStream();
167
168             /* Now we are sending the startup packet to the real X11 server */
169
170             x11_os.write(header);
171
172             if (sd.x11_magic_cookie == null)
173             {
174                 byte[] emptyAuthData = new byte[6];
175                 /* empty auth data, hopefully you are connecting to localhost =) */
176                 x11_os.write(emptyAuthData);
177             }
178             else
179             {
180                 if (sd.x11_magic_cookie.length != 16)
181                     throw new IOException JavaDoc("The real X11 cookie has an invalid length!");
182
183                 /* send X11 cookie specified by client */
184                 x11_os.write(auth_buff);
185                 x11_os.write(authProtocolName); /* re-use */
186                 x11_os.write(paddingBuffer, 0, authProtocolNamePadding);
187                 x11_os.write(sd.x11_magic_cookie);
188                 x11_os.write(paddingBuffer, 0, authProtocolDataPadding);
189             }
190
191             x11_os.flush();
192
193             /* Start forwarding traffic */
194
195             StreamForwarder r2l = new StreamForwarder(c, null, null, remote_is, x11_os, "RemoteToX11");
196             StreamForwarder l2r = new StreamForwarder(c, null, null, x11_is, remote_os, "X11ToRemote");
197
198             /* No need to start two threads, one can be executed in the current thread */
199
200             r2l.setDaemon(true);
201             r2l.start();
202             l2r.run();
203
204             while (r2l.isAlive())
205             {
206                 try
207                 {
208                     r2l.join();
209                 }
210                 catch (InterruptedException JavaDoc e)
211                 {
212                 }
213             }
214
215             /* If the channel is already closed, then this is a no-op */
216
217             c.cm.closeChannel(c, "EOF on both X11 streams reached.", true);
218             s.close();
219         }
220         catch (IOException JavaDoc e)
221         {
222             log.log(50, "IOException in X11 proxy code: " + e.getMessage());
223
224             try
225             {
226                 c.cm.closeChannel(c, "IOException in X11 proxy code (" + e.getMessage() + ")", true);
227             }
228             catch (IOException JavaDoc e1)
229             {
230             }
231             try
232             {
233                 if (s != null)
234                     s.close();
235             }
236             catch (IOException JavaDoc e1)
237             {
238             }
239         }
240     }
241 }
242
Popular Tags