bf742c5f5f4f5d33f4f7879d3d103e621dee9c44
[controller.git] / third-party / ganymed / src / main / java / ch / ethz / ssh2 / Connection.java
1 /*
2  * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
3  * Please refer to the LICENSE.txt for licensing details.
4  */
5
6 package ch.ethz.ssh2;
7
8 import java.io.CharArrayWriter;
9 import java.io.File;
10 import java.io.FileReader;
11 import java.io.IOException;
12 import java.net.InetSocketAddress;
13 import java.net.SocketTimeoutException;
14 import java.security.SecureRandom;
15 import java.util.List;
16 import java.util.Vector;
17
18 import ch.ethz.ssh2.auth.AuthenticationManager;
19 import ch.ethz.ssh2.channel.ChannelManager;
20 import ch.ethz.ssh2.crypto.CryptoWishList;
21 import ch.ethz.ssh2.crypto.cipher.BlockCipherFactory;
22 import ch.ethz.ssh2.crypto.digest.MAC;
23 import ch.ethz.ssh2.packets.PacketIgnore;
24 import ch.ethz.ssh2.transport.KexManager;
25 import ch.ethz.ssh2.transport.TransportManager;
26 import ch.ethz.ssh2.util.TimeoutService;
27 import ch.ethz.ssh2.util.TimeoutService.TimeoutToken;
28
29 /**
30  * A <code>Connection</code> is used to establish an encrypted TCP/IP
31  * connection to a SSH-2 server.
32  * <p>
33  * Typically, one
34  * <ol>
35  * <li>creates a {@link #Connection(String) Connection} object.</li>
36  * <li>calls the {@link #connect() connect()} method.</li>
37  * <li>calls some of the authentication methods (e.g., {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()}).</li>
38  * <li>calls one or several times the {@link #openSession() openSession()} method.</li>
39  * <li>finally, one must close the connection and release resources with the {@link #close() close()} method.</li>
40  * </ol>
41  *
42  * @author Christian Plattner
43  * @version $Id: Connection.java 69 2013-08-09 06:39:56Z dkocher@sudo.ch $
44  */
45
46 public class Connection
47 {
48     /**
49      * The identifier presented to the SSH-2 server. This is the same
50      * as the "softwareversion" defined in RFC 4253.
51      * <p/>
52      * <b>NOTE: As per the RFC, the "softwareversion" string MUST consist of printable
53      * US-ASCII characters, with the exception of whitespace characters and the minus sign (-).</b>
54      */
55     private String softwareversion = String.format("Ganymed_%s", Version.getSpecification());
56
57         /* Will be used to generate all random data needed for the current connection.
58          * Note: SecureRandom.nextBytes() is thread safe.
59          */
60
61     private SecureRandom generator;
62
63     /**
64      * Unless you know what you are doing, you will never need this.
65      *
66      * @return The list of supported cipher algorithms by this implementation.
67      */
68     public static synchronized String[] getAvailableCiphers()
69     {
70         return BlockCipherFactory.getDefaultCipherList();
71     }
72
73     /**
74      * Unless you know what you are doing, you will never need this.
75      *
76      * @return The list of supported MAC algorthims by this implementation.
77      */
78     public static synchronized String[] getAvailableMACs()
79     {
80         return MAC.getMacList();
81     }
82
83     /**
84      * Unless you know what you are doing, you will never need this.
85      *
86      * @return The list of supported server host key algorthims by this implementation.
87      */
88     public static synchronized String[] getAvailableServerHostKeyAlgorithms()
89     {
90         return KexManager.getDefaultServerHostkeyAlgorithmList();
91     }
92
93     private AuthenticationManager am;
94
95     private boolean authenticated = false;
96     private ChannelManager cm;
97
98     private CryptoWishList cryptoWishList = new CryptoWishList();
99
100     private DHGexParameters dhgexpara = new DHGexParameters();
101
102     private final String hostname;
103
104     private final int port;
105
106     private TransportManager tm;
107
108     private boolean tcpNoDelay = false;
109
110     private ProxyData proxyData = null;
111
112     private List<ConnectionMonitor> connectionMonitors = new Vector<ConnectionMonitor>();
113
114     /**
115      * Prepares a fresh <code>Connection</code> object which can then be used
116      * to establish a connection to the specified SSH-2 server.
117      * <p>
118      * Same as {@link #Connection(String, int) Connection(hostname, 22)}.
119      *
120      * @param hostname the hostname of the SSH-2 server.
121      */
122     public Connection(String hostname)
123     {
124         this(hostname, 22);
125     }
126
127     /**
128      * Prepares a fresh <code>Connection</code> object which can then be used
129      * to establish a connection to the specified SSH-2 server.
130      *
131      * @param hostname
132      *            the host where we later want to connect to.
133      * @param port
134      *            port on the server, normally 22.
135      */
136     public Connection(String hostname, int port)
137     {
138         this.hostname = hostname;
139         this.port = port;
140     }
141
142     /**
143      * Prepares a fresh <code>Connection</code> object which can then be used
144      * to establish a connection to the specified SSH-2 server.
145      *
146      * @param hostname
147      *            the host where we later want to connect to.
148      * @param port
149      *            port on the server, normally 22.
150      * @param softwareversion
151      *                  Allows you to set a custom "softwareversion" string as defined in RFC 4253.
152      *                  <b>NOTE: As per the RFC, the "softwareversion" string MUST consist of printable
153      *          US-ASCII characters, with the exception of whitespace characters and the minus sign (-).</b>
154      */
155     public Connection(String hostname, int port, String softwareversion)
156     {
157         this.hostname = hostname;
158         this.port = port;
159         this.softwareversion = softwareversion;
160     }
161
162     /**
163      * After a successful connect, one has to authenticate oneself. This method
164      * is based on DSA (it uses DSA to sign a challenge sent by the server).
165      * <p>
166      * If the authentication phase is complete, <code>true</code> will be
167      * returned. If the server does not accept the request (or if further
168      * authentication steps are needed), <code>false</code> is returned and
169      * one can retry either by using this or any other authentication method
170      * (use the <code>getRemainingAuthMethods</code> method to get a list of
171      * the remaining possible methods).
172      *
173      * @param user
174      *            A <code>String</code> holding the username.
175      * @param pem
176      *            A <code>String</code> containing the DSA private key of the
177      *            user in OpenSSH key format (PEM, you can't miss the
178      *            "-----BEGIN DSA PRIVATE KEY-----" tag). The string may contain
179      *            linefeeds.
180      * @param password
181      *            If the PEM string is 3DES encrypted ("DES-EDE3-CBC"), then you
182      *            must specify the password. Otherwise, this argument will be
183      *            ignored and can be set to <code>null</code>.
184      *
185      * @return whether the connection is now authenticated.
186      * @throws IOException
187      *
188      * @deprecated You should use one of the {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()}
189      *                methods, this method is just a wrapper for it and will
190      *            disappear in future builds.
191      *
192      */
193     public synchronized boolean authenticateWithDSA(String user, String pem, String password) throws IOException
194     {
195         if (tm == null)
196             throw new IllegalStateException("Connection is not established!");
197
198         if (authenticated)
199             throw new IllegalStateException("Connection is already authenticated!");
200
201         if (am == null)
202             am = new AuthenticationManager(tm);
203
204         if (cm == null)
205             cm = new ChannelManager(tm);
206
207         if (user == null)
208             throw new IllegalArgumentException("user argument is null");
209
210         if (pem == null)
211             throw new IllegalArgumentException("pem argument is null");
212
213         authenticated = am.authenticatePublicKey(user, pem.toCharArray(), password, getOrCreateSecureRND());
214
215         return authenticated;
216     }
217
218     /**
219      * A wrapper that calls {@link #authenticateWithKeyboardInteractive(String, String[], InteractiveCallback)
220      * authenticateWithKeyboardInteractivewith} a <code>null</code> submethod list.
221      *
222      * @param user
223      *            A <code>String</code> holding the username.
224      * @param cb
225      *            An <code>InteractiveCallback</code> which will be used to
226      *            determine the responses to the questions asked by the server.
227      * @return whether the connection is now authenticated.
228      * @throws IOException
229      */
230     public synchronized boolean authenticateWithKeyboardInteractive(String user, InteractiveCallback cb)
231             throws IOException
232     {
233         return authenticateWithKeyboardInteractive(user, null, cb);
234     }
235
236     /**
237      * After a successful connect, one has to authenticate oneself. This method
238      * is based on "keyboard-interactive", specified in
239      * draft-ietf-secsh-auth-kbdinteract-XX. Basically, you have to define a
240      * callback object which will be feeded with challenges generated by the
241      * server. Answers are then sent back to the server. It is possible that the
242      * callback will be called several times during the invocation of this
243      * method (e.g., if the server replies to the callback's answer(s) with
244      * another challenge...)
245      * <p>
246      * If the authentication phase is complete, <code>true</code> will be
247      * returned. If the server does not accept the request (or if further
248      * authentication steps are needed), <code>false</code> is returned and
249      * one can retry either by using this or any other authentication method
250      * (use the <code>getRemainingAuthMethods</code> method to get a list of
251      * the remaining possible methods).
252      * <p>
253      * Note: some SSH servers advertise "keyboard-interactive", however, any
254      * interactive request will be denied (without having sent any challenge to
255      * the client).
256      *
257      * @param user
258      *            A <code>String</code> holding the username.
259      * @param submethods
260      *            An array of submethod names, see
261      *            draft-ietf-secsh-auth-kbdinteract-XX. May be <code>null</code>
262      *            to indicate an empty list.
263      * @param cb
264      *            An <code>InteractiveCallback</code> which will be used to
265      *            determine the responses to the questions asked by the server.
266      *
267      * @return whether the connection is now authenticated.
268      * @throws IOException
269      */
270     public synchronized boolean authenticateWithKeyboardInteractive(String user, String[] submethods,
271                                                                     InteractiveCallback cb) throws IOException
272     {
273         if (cb == null)
274             throw new IllegalArgumentException("Callback may not ne NULL!");
275
276         if (tm == null)
277             throw new IllegalStateException("Connection is not established!");
278
279         if (authenticated)
280             throw new IllegalStateException("Connection is already authenticated!");
281
282         if (am == null)
283             am = new AuthenticationManager(tm);
284
285         if (cm == null)
286             cm = new ChannelManager(tm);
287
288         if (user == null)
289             throw new IllegalArgumentException("user argument is null");
290
291         authenticated = am.authenticateInteractive(user, submethods, cb);
292
293         return authenticated;
294     }
295
296     /**
297      * After a successful connect, one has to authenticate oneself. This method
298      * sends username and password to the server.
299      * <p>
300      * If the authentication phase is complete, <code>true</code> will be
301      * returned. If the server does not accept the request (or if further
302      * authentication steps are needed), <code>false</code> is returned and
303      * one can retry either by using this or any other authentication method
304      * (use the <code>getRemainingAuthMethods</code> method to get a list of
305      * the remaining possible methods).
306      * <p>
307      * Note: if this method fails, then please double-check that it is actually
308      * offered by the server (use {@link #getRemainingAuthMethods(String) getRemainingAuthMethods()}.
309      * <p>
310      * Often, password authentication is disabled, but users are not aware of it.
311      * Many servers only offer "publickey" and "keyboard-interactive". However,
312      * even though "keyboard-interactive" *feels* like password authentication
313      * (e.g., when using the putty or openssh clients) it is *not* the same mechanism.
314      *
315      * @param user
316      * @param password
317      * @return if the connection is now authenticated.
318      * @throws IOException
319      */
320     public synchronized boolean authenticateWithPassword(String user, String password) throws IOException
321     {
322         if (tm == null)
323             throw new IllegalStateException("Connection is not established!");
324
325         if (authenticated)
326             throw new IllegalStateException("Connection is already authenticated!");
327
328         if (am == null)
329             am = new AuthenticationManager(tm);
330
331         if (cm == null)
332             cm = new ChannelManager(tm);
333
334         if (user == null)
335             throw new IllegalArgumentException("user argument is null");
336
337         if (password == null)
338             throw new IllegalArgumentException("password argument is null");
339
340         authenticated = am.authenticatePassword(user, password);
341
342         return authenticated;
343     }
344
345     /**
346      * After a successful connect, one has to authenticate oneself.
347      * This method can be used to explicitly use the special "none"
348      * authentication method (where only a username has to be specified).
349      * <p>
350      * Note 1: The "none" method may always be tried by clients, however as by
351      * the specs, the server will not explicitly announce it. In other words,
352      * the "none" token will never show up in the list returned by
353      * {@link #getRemainingAuthMethods(String)}.
354      * <p>
355      * Note 2: no matter which one of the authenticateWithXXX() methods
356      * you call, the library will always issue exactly one initial "none"
357      * authentication request to retrieve the initially allowed list of
358      * authentication methods by the server. Please read RFC 4252 for the
359      * details.
360      * <p>
361      * If the authentication phase is complete, <code>true</code> will be
362      * returned. If further authentication steps are needed, <code>false</code>
363      * is returned and one can retry by any other authentication method
364      * (use the <code>getRemainingAuthMethods</code> method to get a list of
365      * the remaining possible methods).
366      *
367      * @param user
368      * @return if the connection is now authenticated.
369      * @throws IOException
370      */
371     public synchronized boolean authenticateWithNone(String user) throws IOException
372     {
373         if (tm == null)
374             throw new IllegalStateException("Connection is not established!");
375
376         if (authenticated)
377             throw new IllegalStateException("Connection is already authenticated!");
378
379         if (am == null)
380             am = new AuthenticationManager(tm);
381
382         if (cm == null)
383             cm = new ChannelManager(tm);
384
385         if (user == null)
386             throw new IllegalArgumentException("user argument is null");
387
388                 /* Trigger the sending of the PacketUserauthRequestNone packet */
389                 /* (if not already done)                                       */
390
391         authenticated = am.authenticateNone(user);
392
393         return authenticated;
394     }
395
396     /**
397      * After a successful connect, one has to authenticate oneself.
398      * The authentication method "publickey" works by signing a challenge
399      * sent by the server. The signature is either DSA or RSA based - it
400      * just depends on the type of private key you specify, either a DSA
401      * or RSA private key in PEM format. And yes, this is may seem to be a
402      * little confusing, the method is called "publickey" in the SSH-2 protocol
403      * specification, however since we need to generate a signature, you
404      * actually have to supply a private key =).
405      * <p>
406      * The private key contained in the PEM file may also be encrypted ("Proc-Type: 4,ENCRYPTED").
407      * The library supports DES-CBC and DES-EDE3-CBC encryption, as well
408      * as the more exotic PEM encrpytions AES-128-CBC, AES-192-CBC and AES-256-CBC.
409      * <p>
410      * If the authentication phase is complete, <code>true</code> will be
411      * returned. If the server does not accept the request (or if further
412      * authentication steps are needed), <code>false</code> is returned and
413      * one can retry either by using this or any other authentication method
414      * (use the <code>getRemainingAuthMethods</code> method to get a list of
415      * the remaining possible methods).
416      * <p>
417      * NOTE PUTTY USERS: Event though your key file may start with "-----BEGIN..."
418      * it is not in the expected format. You have to convert it to the OpenSSH
419      * key format by using the "puttygen" tool (can be downloaded from the Putty
420      * website). Simply load your key and then use the "Conversions/Export OpenSSH key"
421      * functionality to get a proper PEM file.
422      *
423      * @param user
424      *            A <code>String</code> holding the username.
425      * @param pemPrivateKey
426      *            A <code>char[]</code> containing a DSA or RSA private key of the
427      *            user in OpenSSH key format (PEM, you can't miss the
428      *            "-----BEGIN DSA PRIVATE KEY-----" or "-----BEGIN RSA PRIVATE KEY-----"
429      *            tag). The char array may contain linebreaks/linefeeds.
430      * @param password
431      *            If the PEM structure is encrypted ("Proc-Type: 4,ENCRYPTED") then
432      *            you must specify a password. Otherwise, this argument will be ignored
433      *            and can be set to <code>null</code>.
434      *
435      * @return whether the connection is now authenticated.
436      * @throws IOException
437      */
438     public synchronized boolean authenticateWithPublicKey(String user, char[] pemPrivateKey, String password)
439             throws IOException
440     {
441         if (tm == null)
442             throw new IllegalStateException("Connection is not established!");
443
444         if (authenticated)
445             throw new IllegalStateException("Connection is already authenticated!");
446
447         if (am == null)
448             am = new AuthenticationManager(tm);
449
450         if (cm == null)
451             cm = new ChannelManager(tm);
452
453         if (user == null)
454             throw new IllegalArgumentException("user argument is null");
455
456         if (pemPrivateKey == null)
457             throw new IllegalArgumentException("pemPrivateKey argument is null");
458
459         authenticated = am.authenticatePublicKey(user, pemPrivateKey, password, getOrCreateSecureRND());
460
461         return authenticated;
462     }
463
464     /**
465      * A convenience wrapper function which reads in a private key (PEM format, either DSA or RSA)
466      * and then calls <code>authenticateWithPublicKey(String, char[], String)</code>.
467      * <p>
468      * NOTE PUTTY USERS: Event though your key file may start with "-----BEGIN..."
469      * it is not in the expected format. You have to convert it to the OpenSSH
470      * key format by using the "puttygen" tool (can be downloaded from the Putty
471      * website). Simply load your key and then use the "Conversions/Export OpenSSH key"
472      * functionality to get a proper PEM file.
473      *
474      * @param user
475      *            A <code>String</code> holding the username.
476      * @param pemFile
477      *            A <code>File</code> object pointing to a file containing a DSA or RSA
478      *            private key of the user in OpenSSH key format (PEM, you can't miss the
479      *            "-----BEGIN DSA PRIVATE KEY-----" or "-----BEGIN RSA PRIVATE KEY-----"
480      *            tag).
481      * @param password
482      *            If the PEM file is encrypted then you must specify the password.
483      *            Otherwise, this argument will be ignored and can be set to <code>null</code>.
484      *
485      * @return whether the connection is now authenticated.
486      * @throws IOException
487      */
488     public synchronized boolean authenticateWithPublicKey(String user, File pemFile, String password)
489             throws IOException
490     {
491         if (pemFile == null)
492             throw new IllegalArgumentException("pemFile argument is null");
493
494         char[] buff = new char[256];
495
496         CharArrayWriter cw = new CharArrayWriter();
497
498         FileReader fr = new FileReader(pemFile);
499
500         while (true)
501         {
502             int len = fr.read(buff);
503             if (len < 0)
504                 break;
505             cw.write(buff, 0, len);
506         }
507
508         fr.close();
509
510         return authenticateWithPublicKey(user, cw.toCharArray(), password);
511     }
512
513     /**
514      * Add a {@link ConnectionMonitor} to this connection. Can be invoked at any time,
515      * but it is best to add connection monitors before invoking
516      * <code>connect()</code> to avoid glitches (e.g., you add a connection monitor after
517      * a successful connect(), but the connection has died in the mean time. Then,
518      * your connection monitor won't be notified.)
519      * <p>
520      * You can add as many monitors as you like. If a monitor has already been added, then
521      * this method does nothing.
522      *
523      * @see ConnectionMonitor
524      *
525      * @param cmon An object implementing the {@link ConnectionMonitor} interface.
526      */
527     public synchronized void addConnectionMonitor(ConnectionMonitor cmon)
528     {
529         if (cmon == null)
530             throw new IllegalArgumentException("cmon argument is null");
531
532         if (!connectionMonitors.contains(cmon))
533         {
534             connectionMonitors.add(cmon);
535
536             if (tm != null)
537                 tm.setConnectionMonitors(connectionMonitors);
538         }
539     }
540
541     /**
542      * Remove a {@link ConnectionMonitor} from this connection.
543      *
544      * @param cmon
545      * @return whether the monitor could be removed
546      */
547     public synchronized boolean removeConnectionMonitor(ConnectionMonitor cmon)
548     {
549         if (cmon == null)
550             throw new IllegalArgumentException("cmon argument is null");
551
552         boolean existed = connectionMonitors.remove(cmon);
553
554         if (tm != null)
555             tm.setConnectionMonitors(connectionMonitors);
556
557         return existed;
558     }
559
560     /**
561      * Close the connection to the SSH-2 server. All assigned sessions will be
562      * closed, too. Can be called at any time. Don't forget to call this once
563      * you don't need a connection anymore - otherwise the receiver thread may
564      * run forever.
565      */
566     public synchronized void close()
567     {
568         Throwable t = new Throwable("Closed due to user request.");
569         close(t, false);
570     }
571
572     public synchronized void close(Throwable t, boolean hard)
573     {
574         if (cm != null)
575             cm.closeAllChannels();
576
577         if (tm != null)
578         {
579             tm.close(t, hard == false);
580             tm = null;
581         }
582         am = null;
583         cm = null;
584         authenticated = false;
585     }
586
587     /**
588      * Same as {@link #connect(ServerHostKeyVerifier, int, int) connect(null, 0, 0)}.
589      *
590      * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method.
591      * @throws IOException
592      */
593     public synchronized ConnectionInfo connect() throws IOException
594     {
595         return connect(null, 0, 0);
596     }
597
598     /**
599      * Same as {@link #connect(ServerHostKeyVerifier, int, int) connect(verifier, 0, 0)}.
600      *
601      * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method.
602      * @throws IOException
603      */
604     public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier) throws IOException
605     {
606         return connect(verifier, 0, 0);
607     }
608
609     /**
610      * Connect to the SSH-2 server and, as soon as the server has presented its
611      * host key, use the {@link ServerHostKeyVerifier#verifyServerHostKey(String,
612      * int, String, byte[]) ServerHostKeyVerifier.verifyServerHostKey()}
613      * method of the <code>verifier</code> to ask for permission to proceed.
614      * If <code>verifier</code> is <code>null</code>, then any host key will be
615      * accepted - this is NOT recommended, since it makes man-in-the-middle attackes
616      * VERY easy (somebody could put a proxy SSH server between you and the real server).
617      * <p>
618      * Note: The verifier will be called before doing any crypto calculations
619      * (i.e., diffie-hellman). Therefore, if you don't like the presented host key then
620      * no CPU cycles are wasted (and the evil server has less information about us).
621      * <p>
622      * However, it is still possible that the server presented a fake host key: the server
623      * cheated (typically a sign for a man-in-the-middle attack) and is not able to generate
624      * a signature that matches its host key. Don't worry, the library will detect such
625      * a scenario later when checking the signature (the signature cannot be checked before
626      * having completed the diffie-hellman exchange).
627      * <p>
628      * Note 2: The  {@link ServerHostKeyVerifier#verifyServerHostKey(String,
629      * int, String, byte[]) ServerHostKeyVerifier.verifyServerHostKey()} method
630      * will *NOT* be called from the current thread, the call is being made from a
631      * background thread (there is a background dispatcher thread for every
632      * established connection).
633      * <p>
634      * Note 3: This method will block as long as the key exchange of the underlying connection
635      * has not been completed (and you have not specified any timeouts).
636      * <p>
637      * Note 4: If you want to re-use a connection object that was successfully connected,
638      * then you must call the {@link #close()} method before invoking <code>connect()</code> again.
639      *
640      * @param verifier
641      *            An object that implements the
642      *            {@link ServerHostKeyVerifier} interface. Pass <code>null</code>
643      *            to accept any server host key - NOT recommended.
644      *
645      * @param connectTimeout
646      *            Connect the underlying TCP socket to the server with the given timeout
647      *            value (non-negative, in milliseconds). Zero means no timeout. If a proxy is being
648      *            used (see {@link #setProxyData(ProxyData)}), then this timeout is used for the
649      *            connection establishment to the proxy.
650      *
651      * @param kexTimeout
652      *            Timeout for complete connection establishment (non-negative,
653      *            in milliseconds). Zero means no timeout. The timeout counts from the
654      *            moment you invoke the connect() method and is cancelled as soon as the
655      *            first key-exchange round has finished. It is possible that
656      *            the timeout event will be fired during the invocation of the
657      *            <code>verifier</code> callback, but it will only have an effect after
658      *            the <code>verifier</code> returns.
659      *
660      * @return A {@link ConnectionInfo} object containing the details of
661      *            the established connection.
662      *
663      * @throws IOException
664      *            If any problem occurs, e.g., the server's host key is not
665      *            accepted by the <code>verifier</code> or there is problem during
666      *            the initial crypto setup (e.g., the signature sent by the server is wrong).
667      *            <p>
668      *            In case of a timeout (either connectTimeout or kexTimeout)
669      *            a SocketTimeoutException is thrown.
670      *            <p>
671      *            An exception may also be thrown if the connection was already successfully
672      *            connected (no matter if the connection broke in the mean time) and you invoke
673      *            <code>connect()</code> again without having called {@link #close()} first.
674      *            <p>
675      *            If a HTTP proxy is being used and the proxy refuses the connection,
676      *            then a {@link HTTPProxyException} may be thrown, which
677      *            contains the details returned by the proxy. If the proxy is buggy and does
678      *            not return a proper HTTP response, then a normal IOException is thrown instead.
679      */
680     public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier, int connectTimeout, int kexTimeout)
681             throws IOException
682     {
683         final class TimeoutState
684         {
685             boolean isCancelled = false;
686             boolean timeoutSocketClosed = false;
687         }
688
689         if (tm != null)
690             throw new IOException("Connection to " + hostname + " is already in connected state!");
691
692         if (connectTimeout < 0)
693             throw new IllegalArgumentException("connectTimeout must be non-negative!");
694
695         if (kexTimeout < 0)
696             throw new IllegalArgumentException("kexTimeout must be non-negative!");
697
698         final TimeoutState state = new TimeoutState();
699
700         tm = new TransportManager();
701         tm.setSoTimeout(connectTimeout);
702         tm.setConnectionMonitors(connectionMonitors);
703
704                 /* Make sure that the runnable below will observe the new value of "tm"
705                  * and "state" (the runnable will be executed in a different thread, which
706                  * may be already running, that is why we need a memory barrier here).
707                  * See also the comment in Channel.java if you
708                  * are interested in the details.
709                  * 
710                  * OKOK, this is paranoid since adding the runnable to the todo list
711                  * of the TimeoutService will ensure that all writes have been flushed
712                  * before the Runnable reads anything
713                  * (there is a synchronized block in TimeoutService.addTimeoutHandler).
714                  */
715
716         synchronized (tm)
717         {
718                         /* We could actually synchronize on anything. */
719         }
720
721         try
722         {
723             TimeoutToken token = null;
724
725             if (kexTimeout > 0)
726             {
727                 final Runnable timeoutHandler = new Runnable()
728                 {
729                     public void run()
730                     {
731                         synchronized (state)
732                         {
733                             if (state.isCancelled)
734                                 return;
735                             state.timeoutSocketClosed = true;
736                             tm.close(new SocketTimeoutException("The connect timeout expired"), false);
737                         }
738                     }
739                 };
740
741                 long timeoutHorizont = System.currentTimeMillis() + kexTimeout;
742
743                 token = TimeoutService.addTimeoutHandler(timeoutHorizont, timeoutHandler);
744             }
745
746             try
747             {
748                 tm.clientInit(hostname, port, softwareversion, cryptoWishList, verifier, dhgexpara, connectTimeout,
749                         getOrCreateSecureRND(), proxyData);
750             }
751             catch (SocketTimeoutException se)
752             {
753                 throw (SocketTimeoutException) new SocketTimeoutException(
754                         "The connect() operation on the socket timed out.").initCause(se);
755             }
756
757             tm.setTcpNoDelay(tcpNoDelay);
758
759                         /* Wait until first KEX has finished */
760
761             ConnectionInfo ci = tm.getConnectionInfo(1);
762
763                         /* Now try to cancel the timeout, if needed */
764
765             if (token != null)
766             {
767                 TimeoutService.cancelTimeoutHandler(token);
768
769                                 /* Were we too late? */
770
771                 synchronized (state)
772                 {
773                     if (state.timeoutSocketClosed)
774                         throw new IOException("This exception will be replaced by the one below =)");
775                                         /* Just in case the "cancelTimeoutHandler" invocation came just a little bit
776                                          * too late but the handler did not enter the semaphore yet - we can
777                                          * still stop it.
778                                          */
779                     state.isCancelled = true;
780                 }
781             }
782
783             return ci;
784         }
785         catch (SocketTimeoutException ste)
786         {
787             throw ste;
788         }
789         catch (IOException e1)
790         {
791                         /* This will also invoke any registered connection monitors */
792             close(new Throwable("There was a problem during connect."), false);
793
794             synchronized (state)
795             {
796                                 /* Show a clean exception, not something like "the socket is closed!?!" */
797                 if (state.timeoutSocketClosed)
798                     throw new SocketTimeoutException("The kexTimeout (" + kexTimeout + " ms) expired.");
799             }
800
801                         /* Do not wrap a HTTPProxyException */
802             if (e1 instanceof HTTPProxyException)
803                 throw e1;
804
805             throw (IOException) new IOException("There was a problem while connecting to " + hostname + ":" + port)
806                     .initCause(e1);
807         }
808     }
809
810     /**
811      * Creates a new {@link LocalPortForwarder}.
812      * A <code>LocalPortForwarder</code> forwards TCP/IP connections that arrive at a local
813      * port via the secure tunnel to another host (which may or may not be
814      * identical to the remote SSH-2 server).
815      * <p>
816      * This method must only be called after one has passed successfully the authentication step.
817      * There is no limit on the number of concurrent forwardings.
818      *
819      * @param local_port the local port the LocalPortForwarder shall bind to.
820      * @param host_to_connect target address (IP or hostname)
821      * @param port_to_connect target port
822      * @return A {@link LocalPortForwarder} object.
823      * @throws IOException
824      */
825     public synchronized LocalPortForwarder createLocalPortForwarder(int local_port, String host_to_connect,
826                                                                     int port_to_connect) throws IOException
827     {
828         if (tm == null)
829             throw new IllegalStateException("Cannot forward ports, you need to establish a connection first.");
830
831         if (!authenticated)
832             throw new IllegalStateException("Cannot forward ports, connection is not authenticated.");
833
834         return new LocalPortForwarder(cm, local_port, host_to_connect, port_to_connect);
835     }
836
837     /**
838      * Creates a new {@link LocalPortForwarder}.
839      * A <code>LocalPortForwarder</code> forwards TCP/IP connections that arrive at a local
840      * port via the secure tunnel to another host (which may or may not be
841      * identical to the remote SSH-2 server).
842      * <p>
843      * This method must only be called after one has passed successfully the authentication step.
844      * There is no limit on the number of concurrent forwardings.
845      *
846      * @param addr specifies the InetSocketAddress where the local socket shall be bound to.
847      * @param host_to_connect target address (IP or hostname)
848      * @param port_to_connect target port
849      * @return A {@link LocalPortForwarder} object.
850      * @throws IOException
851      */
852     public synchronized LocalPortForwarder createLocalPortForwarder(InetSocketAddress addr, String host_to_connect,
853                                                                     int port_to_connect) throws IOException
854     {
855         if (tm == null)
856             throw new IllegalStateException("Cannot forward ports, you need to establish a connection first.");
857
858         if (!authenticated)
859             throw new IllegalStateException("Cannot forward ports, connection is not authenticated.");
860
861         return new LocalPortForwarder(cm, addr, host_to_connect, port_to_connect);
862     }
863
864     /**
865      * Creates a new {@link LocalStreamForwarder}.
866      * A <code>LocalStreamForwarder</code> manages an Input/Outputstream pair
867      * that is being forwarded via the secure tunnel into a TCP/IP connection to another host
868      * (which may or may not be identical to the remote SSH-2 server).
869      *
870      * @param host_to_connect
871      * @param port_to_connect
872      * @return A {@link LocalStreamForwarder} object.
873      * @throws IOException
874      */
875     public synchronized LocalStreamForwarder createLocalStreamForwarder(String host_to_connect, int port_to_connect)
876             throws IOException
877     {
878         if (tm == null)
879             throw new IllegalStateException("Cannot forward, you need to establish a connection first.");
880
881         if (!authenticated)
882             throw new IllegalStateException("Cannot forward, connection is not authenticated.");
883
884         return new LocalStreamForwarder(cm, host_to_connect, port_to_connect);
885     }
886
887     /**
888      * Create a very basic {@link SCPClient} that can be used to copy
889      * files from/to the SSH-2 server.
890      * <p>
891      * Works only after one has passed successfully the authentication step.
892      * There is no limit on the number of concurrent SCP clients.
893      * <p>
894      * Note: This factory method will probably disappear in the future.
895      *
896      * @return A {@link SCPClient} object.
897      * @throws IOException
898      */
899     public synchronized SCPClient createSCPClient() throws IOException
900     {
901         if (tm == null)
902             throw new IllegalStateException("Cannot create SCP client, you need to establish a connection first.");
903
904         if (!authenticated)
905             throw new IllegalStateException("Cannot create SCP client, connection is not authenticated.");
906
907         return new SCPClient(this);
908     }
909
910     /**
911      * Force an asynchronous key re-exchange (the call does not block). The
912      * latest values set for MAC, Cipher and DH group exchange parameters will
913      * be used. If a key exchange is currently in progress, then this method has
914      * the only effect that the so far specified parameters will be used for the
915      * next (server driven) key exchange.
916      * <p>
917      * Note: This implementation will never start a key exchange (other than the initial one)
918      * unless you or the SSH-2 server ask for it.
919      *
920      * @throws IOException
921      *             In case of any failure behind the scenes.
922      */
923     public synchronized void forceKeyExchange() throws IOException
924     {
925         if (tm == null)
926             throw new IllegalStateException("You need to establish a connection first.");
927
928         tm.forceKeyExchange(cryptoWishList, dhgexpara, null, null);
929     }
930
931     /**
932      * Returns the hostname that was passed to the constructor.
933      *
934      * @return the hostname
935      */
936     public synchronized String getHostname()
937     {
938         return hostname;
939     }
940
941     /**
942      * Returns the port that was passed to the constructor.
943      *
944      * @return the TCP port
945      */
946     public synchronized int getPort()
947     {
948         return port;
949     }
950
951     /**
952      * Returns a {@link ConnectionInfo} object containing the details of
953      * the connection. Can be called as soon as the connection has been
954      * established (successfully connected).
955      *
956      * @return A {@link ConnectionInfo} object.
957      * @throws IOException
958      *             In case of any failure behind the scenes.
959      */
960     public synchronized ConnectionInfo getConnectionInfo() throws IOException
961     {
962         if (tm == null)
963             throw new IllegalStateException(
964                     "Cannot get details of connection, you need to establish a connection first.");
965         return tm.getConnectionInfo(1);
966     }
967
968     /**
969      * After a successful connect, one has to authenticate oneself. This method
970      * can be used to tell which authentication methods are supported by the
971      * server at a certain stage of the authentication process (for the given
972      * username).
973      * <p>
974      * Note 1: the username will only be used if no authentication step was done
975      * so far (it will be used to ask the server for a list of possible
976      * authentication methods by sending the initial "none" request). Otherwise,
977      * this method ignores the user name and returns a cached method list
978      * (which is based on the information contained in the last negative server response).
979      * <p>
980      * Note 2: the server may return method names that are not supported by this
981      * implementation.
982      * <p>
983      * After a successful authentication, this method must not be called
984      * anymore.
985      *
986      * @param user
987      *            A <code>String</code> holding the username.
988      *
989      * @return a (possibly emtpy) array holding authentication method names.
990      * @throws IOException
991      */
992     public synchronized String[] getRemainingAuthMethods(String user) throws IOException
993     {
994         if (user == null)
995             throw new IllegalArgumentException("user argument may not be NULL!");
996
997         if (tm == null)
998             throw new IllegalStateException("Connection is not established!");
999
1000         if (authenticated)
1001             throw new IllegalStateException("Connection is already authenticated!");
1002
1003         if (am == null)
1004             am = new AuthenticationManager(tm);
1005
1006         if (cm == null)
1007             cm = new ChannelManager(tm);
1008
1009         return am.getRemainingMethods(user);
1010     }
1011
1012     /**
1013      * Determines if the authentication phase is complete. Can be called at any
1014      * time.
1015      *
1016      * @return <code>true</code> if no further authentication steps are
1017      *         needed.
1018      */
1019     public synchronized boolean isAuthenticationComplete()
1020     {
1021         return authenticated;
1022     }
1023
1024     /**
1025      * Returns true if there was at least one failed authentication request and
1026      * the last failed authentication request was marked with "partial success"
1027      * by the server. This is only needed in the rare case of SSH-2 server setups
1028      * that cannot be satisfied with a single successful authentication request
1029      * (i.e., multiple authentication steps are needed.)
1030      * <p>
1031      * If you are interested in the details, then have a look at RFC4252.
1032      *
1033      * @return if the there was a failed authentication step and the last one
1034      *         was marked as a "partial success".
1035      */
1036     public synchronized boolean isAuthenticationPartialSuccess()
1037     {
1038         if (am == null)
1039             return false;
1040
1041         return am.getPartialSuccess();
1042     }
1043
1044     /**
1045      * Checks if a specified authentication method is available. This method is
1046      * actually just a wrapper for {@link #getRemainingAuthMethods(String)
1047      * getRemainingAuthMethods()}.
1048      *
1049      * @param user
1050      *            A <code>String</code> holding the username.
1051      * @param method
1052      *            An authentication method name (e.g., "publickey", "password",
1053      *            "keyboard-interactive") as specified by the SSH-2 standard.
1054      * @return if the specified authentication method is currently available.
1055      * @throws IOException
1056      */
1057     public synchronized boolean isAuthMethodAvailable(String user, String method) throws IOException
1058     {
1059         if (method == null)
1060             throw new IllegalArgumentException("method argument may not be NULL!");
1061
1062         String methods[] = getRemainingAuthMethods(user);
1063
1064         for (int i = 0; i < methods.length; i++)
1065         {
1066             if (methods[i].compareTo(method) == 0)
1067                 return true;
1068         }
1069
1070         return false;
1071     }
1072
1073     private SecureRandom getOrCreateSecureRND()
1074     {
1075         if (generator == null)
1076             generator = new SecureRandom();
1077
1078         return generator;
1079     }
1080
1081     /**
1082      * Open a new {@link Session} on this connection. Works only after one has passed
1083      * successfully the authentication step. There is no limit on the number of
1084      * concurrent sessions.
1085      *
1086      * @return A {@link Session} object.
1087      * @throws IOException
1088      */
1089     public synchronized Session openSession() throws IOException
1090     {
1091         if (tm == null)
1092             throw new IllegalStateException("Cannot open session, you need to establish a connection first.");
1093
1094         if (!authenticated)
1095             throw new IllegalStateException("Cannot open session, connection is not authenticated.");
1096
1097         return new Session(cm, getOrCreateSecureRND());
1098     }
1099
1100     /**
1101      * Send an SSH_MSG_IGNORE packet. This method will generate a random data attribute
1102      * (length between 0 (invlusive) and 16 (exclusive) bytes, contents are random bytes).
1103      * <p>
1104      * This method must only be called once the connection is established.
1105      *
1106      * @throws IOException
1107      */
1108     public synchronized void sendIgnorePacket() throws IOException
1109     {
1110         SecureRandom rnd = getOrCreateSecureRND();
1111
1112         byte[] data = new byte[rnd.nextInt(16)];
1113         rnd.nextBytes(data);
1114
1115         sendIgnorePacket(data);
1116     }
1117
1118     /**
1119      * Send an SSH_MSG_IGNORE packet with the given data attribute.
1120      * <p>
1121      * This method must only be called once the connection is established.
1122      *
1123      * @throws IOException
1124      */
1125     public synchronized void sendIgnorePacket(byte[] data) throws IOException
1126     {
1127         if (data == null)
1128             throw new IllegalArgumentException("data argument must not be null.");
1129
1130         if (tm == null)
1131             throw new IllegalStateException(
1132                     "Cannot send SSH_MSG_IGNORE packet, you need to establish a connection first.");
1133
1134         PacketIgnore pi = new PacketIgnore();
1135         pi.setData(data);
1136
1137         tm.sendMessage(pi.getPayload());
1138     }
1139
1140     /**
1141      * Removes duplicates from a String array, keeps only first occurence
1142      * of each element. Does not destroy order of elements; can handle nulls.
1143      * Uses a very efficient O(N^2) algorithm =)
1144      *
1145      * @param list a String array.
1146      * @return a cleaned String array.
1147      */
1148     private String[] removeDuplicates(String[] list)
1149     {
1150         if ((list == null) || (list.length < 2))
1151             return list;
1152
1153         String[] list2 = new String[list.length];
1154
1155         int count = 0;
1156
1157         for (int i = 0; i < list.length; i++)
1158         {
1159             boolean duplicate = false;
1160
1161             String element = list[i];
1162
1163             for (int j = 0; j < count; j++)
1164             {
1165                 if (((element == null) && (list2[j] == null)) || ((element != null) && (element.equals(list2[j]))))
1166                 {
1167                     duplicate = true;
1168                     break;
1169                 }
1170             }
1171
1172             if (duplicate)
1173                 continue;
1174
1175             list2[count++] = list[i];
1176         }
1177
1178         if (count == list2.length)
1179             return list2;
1180
1181         String[] tmp = new String[count];
1182         System.arraycopy(list2, 0, tmp, 0, count);
1183
1184         return tmp;
1185     }
1186
1187     /**
1188      * Unless you know what you are doing, you will never need this.
1189      *
1190      * @param ciphers
1191      */
1192     public synchronized void setClient2ServerCiphers(String[] ciphers)
1193     {
1194         if ((ciphers == null) || (ciphers.length == 0))
1195             throw new IllegalArgumentException();
1196         ciphers = removeDuplicates(ciphers);
1197         BlockCipherFactory.checkCipherList(ciphers);
1198         cryptoWishList.c2s_enc_algos = ciphers;
1199     }
1200
1201     /**
1202      * Unless you know what you are doing, you will never need this.
1203      *
1204      * @param macs
1205      */
1206     public synchronized void setClient2ServerMACs(String[] macs)
1207     {
1208         if ((macs == null) || (macs.length == 0))
1209             throw new IllegalArgumentException();
1210         macs = removeDuplicates(macs);
1211         MAC.checkMacList(macs);
1212         cryptoWishList.c2s_mac_algos = macs;
1213     }
1214
1215     /**
1216      * Sets the parameters for the diffie-hellman group exchange. Unless you
1217      * know what you are doing, you will never need this. Default values are
1218      * defined in the {@link DHGexParameters} class.
1219      *
1220      * @param dgp {@link DHGexParameters}, non null.
1221      *
1222      */
1223     public synchronized void setDHGexParameters(DHGexParameters dgp)
1224     {
1225         if (dgp == null)
1226             throw new IllegalArgumentException();
1227
1228         dhgexpara = dgp;
1229     }
1230
1231     /**
1232      * Unless you know what you are doing, you will never need this.
1233      *
1234      * @param ciphers
1235      */
1236     public synchronized void setServer2ClientCiphers(String[] ciphers)
1237     {
1238         if ((ciphers == null) || (ciphers.length == 0))
1239             throw new IllegalArgumentException();
1240         ciphers = removeDuplicates(ciphers);
1241         BlockCipherFactory.checkCipherList(ciphers);
1242         cryptoWishList.s2c_enc_algos = ciphers;
1243     }
1244
1245     /**
1246      * Unless you know what you are doing, you will never need this.
1247      *
1248      * @param macs
1249      */
1250     public synchronized void setServer2ClientMACs(String[] macs)
1251     {
1252         if ((macs == null) || (macs.length == 0))
1253             throw new IllegalArgumentException();
1254
1255         macs = removeDuplicates(macs);
1256         MAC.checkMacList(macs);
1257         cryptoWishList.s2c_mac_algos = macs;
1258     }
1259
1260     /**
1261      * Define the set of allowed server host key algorithms to be used for
1262      * the following key exchange operations.
1263      * <p>
1264      * Unless you know what you are doing, you will never need this.
1265      *
1266      * @param algos An array of allowed server host key algorithms.
1267      *  SSH-2 defines <code>ssh-dss</code> and <code>ssh-rsa</code>.
1268      *  The entries of the array must be ordered after preference, i.e.,
1269      *  the entry at index 0 is the most preferred one. You must specify
1270      *  at least one entry.
1271      */
1272     public synchronized void setServerHostKeyAlgorithms(String[] algos)
1273     {
1274         if ((algos == null) || (algos.length == 0))
1275             throw new IllegalArgumentException();
1276
1277         algos = removeDuplicates(algos);
1278         KexManager.checkServerHostkeyAlgorithmsList(algos);
1279         cryptoWishList.serverHostKeyAlgorithms = algos;
1280     }
1281
1282     /**
1283      * Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm) on the underlying socket.
1284      * <p>
1285      * Can be called at any time. If the connection has not yet been established
1286      * then the passed value will be stored and set after the socket has been set up.
1287      * The default value that will be used is <code>false</code>.
1288      *
1289      * @param enable the argument passed to the <code>Socket.setTCPNoDelay()</code> method.
1290      * @throws IOException
1291      */
1292     public synchronized void setTCPNoDelay(boolean enable) throws IOException
1293     {
1294         tcpNoDelay = enable;
1295
1296         if (tm != null)
1297             tm.setTcpNoDelay(enable);
1298     }
1299
1300     /**
1301      * Used to tell the library that the connection shall be established through a proxy server.
1302      * It only makes sense to call this method before calling the {@link #connect() connect()}
1303      * method.
1304      * <p>
1305      * At the moment, only HTTP proxies are supported.
1306      * <p>
1307      * Note: This method can be called any number of times. The {@link #connect() connect()}
1308      * method will use the value set in the last preceding invocation of this method.
1309      *
1310      * @see HTTPProxyData
1311      *
1312      * @param proxyData Connection information about the proxy. If <code>null</code>, then
1313      *                  no proxy will be used (non surprisingly, this is also the default).
1314      */
1315     public synchronized void setProxyData(ProxyData proxyData)
1316     {
1317         this.proxyData = proxyData;
1318     }
1319
1320     /**
1321      * Request a remote port forwarding.
1322      * If successful, then forwarded connections will be redirected to the given target address.
1323      * You can cancle a requested remote port forwarding by calling
1324      * {@link #cancelRemotePortForwarding(int) cancelRemotePortForwarding()}.
1325      * <p>
1326      * A call of this method will block until the peer either agreed or disagreed to your request-
1327      * <p>
1328      * Note 1: this method typically fails if you
1329      * <ul>
1330      * <li>pass a port number for which the used remote user has not enough permissions (i.e., port
1331      * &lt; 1024)</li>
1332      * <li>or pass a port number that is already in use on the remote server</li>
1333      * <li>or if remote port forwarding is disabled on the server.</li>
1334      * </ul>
1335      * <p>
1336      * Note 2: (from the openssh man page): By default, the listening socket on the server will be
1337      * bound to the loopback interface only. This may be overriden by specifying a bind address.
1338      * Specifying a remote bind address will only succeed if the server's <b>GatewayPorts</b> option
1339      * is enabled (see sshd_config(5)).
1340      *
1341      * @param bindAddress address to bind to on the server:
1342      *                    <ul>
1343      *                    <li>"" means that connections are to be accepted on all protocol families
1344      *                    supported by the SSH implementation</li>
1345      *                    <li>"0.0.0.0" means to listen on all IPv4 addresses</li>
1346      *                    <li>"::" means to listen on all IPv6 addresses</li>
1347      *                    <li>"localhost" means to listen on all protocol families supported by the SSH
1348      *                    implementation on loopback addresses only, [RFC3330] and RFC3513]</li>
1349      *                    <li>"127.0.0.1" and "::1" indicate listening on the loopback interfaces for
1350      *                    IPv4 and IPv6 respectively</li>
1351      *                    </ul>
1352      * @param bindPort port number to bind on the server (must be &gt; 0)
1353      * @param targetAddress the target address (IP or hostname)
1354      * @param targetPort the target port
1355      * @throws IOException
1356      */
1357     public synchronized void requestRemotePortForwarding(String bindAddress, int bindPort, String targetAddress,
1358                                                          int targetPort) throws IOException
1359     {
1360         if (tm == null)
1361             throw new IllegalStateException("You need to establish a connection first.");
1362
1363         if (!authenticated)
1364             throw new IllegalStateException("The connection is not authenticated.");
1365
1366         if ((bindAddress == null) || (targetAddress == null) || (bindPort <= 0) || (targetPort <= 0))
1367             throw new IllegalArgumentException();
1368
1369         cm.requestGlobalForward(bindAddress, bindPort, targetAddress, targetPort);
1370     }
1371
1372     /**
1373      * Cancel an earlier requested remote port forwarding.
1374      * Currently active forwardings will not be affected (e.g., disrupted).
1375      * Note that further connection forwarding requests may be received until
1376      * this method has returned.
1377      *
1378      * @param bindPort the allocated port number on the server
1379      * @throws IOException if the remote side refuses the cancel request or another low
1380      *         level error occurs (e.g., the underlying connection is closed)
1381      */
1382     public synchronized void cancelRemotePortForwarding(int bindPort) throws IOException
1383     {
1384         if (tm == null)
1385             throw new IllegalStateException("You need to establish a connection first.");
1386
1387         if (!authenticated)
1388             throw new IllegalStateException("The connection is not authenticated.");
1389
1390         cm.requestCancelGlobalForward(bindPort);
1391     }
1392
1393     /**
1394      * Provide your own instance of SecureRandom. Can be used, e.g., if you
1395      * want to seed the used SecureRandom generator manually.
1396      * <p>
1397      * The SecureRandom instance is used during key exchanges, public key authentication,
1398      * x11 cookie generation and the like.
1399      *
1400      * @param rnd a SecureRandom instance
1401      */
1402     public synchronized void setSecureRandom(SecureRandom rnd)
1403     {
1404         if (rnd == null)
1405             throw new IllegalArgumentException();
1406
1407         this.generator = rnd;
1408     }
1409 }