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