Source Code Cross Referenced for Connection.java in  » Net » Ganymed-SSH-2 » ch » ethz » ssh2 » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Net » Ganymed SSH 2 » ch.ethz.ssh2 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package ch.ethz.ssh2;
0002:
0003:        import java.io.CharArrayWriter;
0004:        import java.io.File;
0005:        import java.io.FileReader;
0006:        import java.io.IOException;
0007:        import java.net.SocketTimeoutException;
0008:        import java.security.SecureRandom;
0009:        import java.util.Vector;
0010:
0011:        import ch.ethz.ssh2.auth.AuthenticationManager;
0012:        import ch.ethz.ssh2.channel.ChannelManager;
0013:        import ch.ethz.ssh2.crypto.CryptoWishList;
0014:        import ch.ethz.ssh2.crypto.cipher.BlockCipherFactory;
0015:        import ch.ethz.ssh2.crypto.digest.MAC;
0016:        import ch.ethz.ssh2.transport.KexManager;
0017:        import ch.ethz.ssh2.transport.TransportManager;
0018:        import ch.ethz.ssh2.util.TimeoutService;
0019:        import ch.ethz.ssh2.util.TimeoutService.TimeoutToken;
0020:
0021:        /**
0022:         * A <code>Connection</code> is used to establish an encrypted TCP/IP
0023:         * connection to a SSH-2 server.
0024:         * <p>
0025:         * Typically, one
0026:         * <ol>
0027:         * <li>creates a {@link #Connection(String) Connection} object.</li>
0028:         * <li>calls the {@link #connect() connect()} method.</li>
0029:         * <li>calls some of the authentication methods (e.g., {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()}).</li>
0030:         * <li>calls one or several times the {@link #openSession() openSession()} method.</li>
0031:         * <li>finally, one must close the connection and release resources with the {@link #close() close()} method.</li>
0032:         * </ol>
0033:         * 
0034:         * @author Christian Plattner, plattner@inf.ethz.ch
0035:         * @version $Id: Connection.java,v 1.28 2006/09/12 15:35:26 cplattne Exp $
0036:         */
0037:
0038:        public class Connection {
0039:            /**
0040:             * The identifier presented to the SSH-2 server.
0041:             */
0042:            public final static String identification = "Ganymed Build_210";
0043:
0044:            /* Will be used to generate all random data needed for the current connection.
0045:             * Note: SecureRandom.nextBytes() is thread safe.
0046:             */
0047:
0048:            private SecureRandom generator;
0049:
0050:            /**
0051:             * Unless you know what you are doing, you will never need this.
0052:             * 
0053:             * @return The list of supported cipher algorithms by this implementation.
0054:             */
0055:            public static synchronized String[] getAvailableCiphers() {
0056:                return BlockCipherFactory.getDefaultCipherList();
0057:            }
0058:
0059:            /**
0060:             * Unless you know what you are doing, you will never need this.
0061:             * 
0062:             * @return The list of supported MAC algorthims by this implementation.
0063:             */
0064:            public static synchronized String[] getAvailableMACs() {
0065:                return MAC.getMacList();
0066:            }
0067:
0068:            /**
0069:             * Unless you know what you are doing, you will never need this.
0070:             * 
0071:             * @return The list of supported server host key algorthims by this implementation.
0072:             */
0073:            public static synchronized String[] getAvailableServerHostKeyAlgorithms() {
0074:                return KexManager.getDefaultServerHostkeyAlgorithmList();
0075:            }
0076:
0077:            private AuthenticationManager am;
0078:
0079:            private boolean authenticated = false;
0080:            private ChannelManager cm;
0081:
0082:            private CryptoWishList cryptoWishList = new CryptoWishList();
0083:
0084:            private DHGexParameters dhgexpara = new DHGexParameters();
0085:
0086:            private final String hostname;
0087:
0088:            private final int port;
0089:
0090:            private TransportManager tm;
0091:
0092:            private boolean tcpNoDelay = false;
0093:
0094:            private ProxyData proxyData = null;
0095:
0096:            private Vector connectionMonitors = new Vector();
0097:
0098:            /**
0099:             * Prepares a fresh <code>Connection</code> object which can then be used
0100:             * to establish a connection to the specified SSH-2 server.
0101:             * <p>
0102:             * Same as {@link #Connection(String, int) Connection(hostname, 22)}. 
0103:             * 
0104:             * @param hostname the hostname of the SSH-2 server.
0105:             */
0106:            public Connection(String hostname) {
0107:                this (hostname, 22);
0108:            }
0109:
0110:            /**
0111:             * Prepares a fresh <code>Connection</code> object which can then be used
0112:             * to establish a connection to the specified SSH-2 server.
0113:             * 
0114:             * @param hostname
0115:             *            the host where we later want to connect to.
0116:             * @param port
0117:             *            port on the server, normally 22.
0118:             */
0119:            public Connection(String hostname, int port) {
0120:                this .hostname = hostname;
0121:                this .port = port;
0122:            }
0123:
0124:            /**
0125:             * After a successful connect, one has to authenticate oneself. This method
0126:             * is based on DSA (it uses DSA to sign a challenge sent by the server).
0127:             * <p>
0128:             * If the authentication phase is complete, <code>true</code> will be
0129:             * returned. If the server does not accept the request (or if further
0130:             * authentication steps are needed), <code>false</code> is returned and
0131:             * one can retry either by using this or any other authentication method
0132:             * (use the <code>getRemainingAuthMethods</code> method to get a list of
0133:             * the remaining possible methods).
0134:             * 
0135:             * @param user
0136:             *            A <code>String</code> holding the username.
0137:             * @param pem
0138:             *            A <code>String</code> containing the DSA private key of the
0139:             *            user in OpenSSH key format (PEM, you can't miss the
0140:             *            "-----BEGIN DSA PRIVATE KEY-----" tag). The string may contain
0141:             *            linefeeds.
0142:             * @param password
0143:             *            If the PEM string is 3DES encrypted ("DES-EDE3-CBC"), then you
0144:             *            must specify the password. Otherwise, this argument will be
0145:             *            ignored and can be set to <code>null</code>.
0146:             * 
0147:             * @return whether the connection is now authenticated.
0148:             * @throws IOException
0149:             * 
0150:             * @deprecated You should use one of the {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()}
0151:             * 		      methods, this method is just a wrapper for it and will
0152:             *            disappear in future builds.
0153:             * 
0154:             */
0155:            public synchronized boolean authenticateWithDSA(String user,
0156:                    String pem, String password) throws IOException {
0157:                if (tm == null)
0158:                    throw new IllegalStateException(
0159:                            "Connection is not established!");
0160:
0161:                if (authenticated)
0162:                    throw new IllegalStateException(
0163:                            "Connection is already authenticated!");
0164:
0165:                if (am == null)
0166:                    am = new AuthenticationManager(tm);
0167:
0168:                if (cm == null)
0169:                    cm = new ChannelManager(tm);
0170:
0171:                if (user == null)
0172:                    throw new IllegalArgumentException("user argument is null");
0173:
0174:                if (pem == null)
0175:                    throw new IllegalArgumentException("pem argument is null");
0176:
0177:                authenticated = am.authenticatePublicKey(user, pem
0178:                        .toCharArray(), password, getOrCreateSecureRND());
0179:
0180:                return authenticated;
0181:            }
0182:
0183:            /**
0184:             * A wrapper that calls {@link #authenticateWithKeyboardInteractive(String, String[], InteractiveCallback)
0185:             * authenticateWithKeyboardInteractivewith} a <code>null</code> submethod list.
0186:             * 
0187:             * @param user
0188:             *            A <code>String</code> holding the username.
0189:             * @param cb
0190:             *            An <code>InteractiveCallback</code> which will be used to
0191:             *            determine the responses to the questions asked by the server.
0192:             * @return whether the connection is now authenticated.
0193:             * @throws IOException
0194:             */
0195:            public synchronized boolean authenticateWithKeyboardInteractive(
0196:                    String user, InteractiveCallback cb) throws IOException {
0197:                return authenticateWithKeyboardInteractive(user, null, cb);
0198:            }
0199:
0200:            /**
0201:             * After a successful connect, one has to authenticate oneself. This method
0202:             * is based on "keyboard-interactive", specified in
0203:             * draft-ietf-secsh-auth-kbdinteract-XX. Basically, you have to define a
0204:             * callback object which will be feeded with challenges generated by the
0205:             * server. Answers are then sent back to the server. It is possible that the
0206:             * callback will be called several times during the invocation of this
0207:             * method (e.g., if the server replies to the callback's answer(s) with
0208:             * another challenge...)
0209:             * <p>
0210:             * If the authentication phase is complete, <code>true</code> will be
0211:             * returned. If the server does not accept the request (or if further
0212:             * authentication steps are needed), <code>false</code> is returned and
0213:             * one can retry either by using this or any other authentication method
0214:             * (use the <code>getRemainingAuthMethods</code> method to get a list of
0215:             * the remaining possible methods).
0216:             * <p>
0217:             * Note: some SSH servers advertise "keyboard-interactive", however, any
0218:             * interactive request will be denied (without having sent any challenge to
0219:             * the client).
0220:             * 
0221:             * @param user
0222:             *            A <code>String</code> holding the username.
0223:             * @param submethods
0224:             *            An array of submethod names, see
0225:             *            draft-ietf-secsh-auth-kbdinteract-XX. May be <code>null</code>
0226:             *            to indicate an empty list.
0227:             * @param cb
0228:             *            An <code>InteractiveCallback</code> which will be used to
0229:             *            determine the responses to the questions asked by the server.
0230:             * 
0231:             * @return whether the connection is now authenticated.
0232:             * @throws IOException
0233:             */
0234:            public synchronized boolean authenticateWithKeyboardInteractive(
0235:                    String user, String[] submethods, InteractiveCallback cb)
0236:                    throws IOException {
0237:                if (cb == null)
0238:                    throw new IllegalArgumentException(
0239:                            "Callback may not ne NULL!");
0240:
0241:                if (tm == null)
0242:                    throw new IllegalStateException(
0243:                            "Connection is not established!");
0244:
0245:                if (authenticated)
0246:                    throw new IllegalStateException(
0247:                            "Connection is already authenticated!");
0248:
0249:                if (am == null)
0250:                    am = new AuthenticationManager(tm);
0251:
0252:                if (cm == null)
0253:                    cm = new ChannelManager(tm);
0254:
0255:                if (user == null)
0256:                    throw new IllegalArgumentException("user argument is null");
0257:
0258:                authenticated = am
0259:                        .authenticateInteractive(user, submethods, cb);
0260:
0261:                return authenticated;
0262:            }
0263:
0264:            /**
0265:             * After a successfull connect, one has to authenticate oneself. This method
0266:             * sends username and password to the server.
0267:             * <p>
0268:             * If the authentication phase is complete, <code>true</code> will be
0269:             * returned. If the server does not accept the request (or if further
0270:             * authentication steps are needed), <code>false</code> is returned and
0271:             * one can retry either by using this or any other authentication method
0272:             * (use the <code>getRemainingAuthMethods</code> method to get a list of
0273:             * the remaining possible methods).
0274:             * <p>
0275:             * Note: if this method fails, then please double-check that it is actually
0276:             * offered by the server (use {@link #getRemainingAuthMethods(String) getRemainingAuthMethods()}.
0277:             * <p>
0278:             * Often, password authentication is disabled, but users are not aware of it.
0279:             * Many servers only offer "publickey" and "keyboard-interactive". However,
0280:             * even though "keyboard-interactive" *feels* like password authentication
0281:             * (e.g., when using the putty or openssh clients) it is *not* the same mechanism.
0282:             * 
0283:             * @param user
0284:             * @param password
0285:             * @return if the connection is now authenticated.
0286:             * @throws IOException
0287:             */
0288:            public synchronized boolean authenticateWithPassword(String user,
0289:                    String password) throws IOException {
0290:                if (tm == null)
0291:                    throw new IllegalStateException(
0292:                            "Connection is not established!");
0293:
0294:                if (authenticated)
0295:                    throw new IllegalStateException(
0296:                            "Connection is already authenticated!");
0297:
0298:                if (am == null)
0299:                    am = new AuthenticationManager(tm);
0300:
0301:                if (cm == null)
0302:                    cm = new ChannelManager(tm);
0303:
0304:                if (user == null)
0305:                    throw new IllegalArgumentException("user argument is null");
0306:
0307:                if (password == null)
0308:                    throw new IllegalArgumentException(
0309:                            "password argument is null");
0310:
0311:                authenticated = am.authenticatePassword(user, password);
0312:
0313:                return authenticated;
0314:            }
0315:
0316:            /**
0317:             * After a successful connect, one has to authenticate oneself.
0318:             * The authentication method "publickey" works by signing a challenge
0319:             * sent by the server. The signature is either DSA or RSA based - it
0320:             * just depends on the type of private key you specify, either a DSA
0321:             * or RSA private key in PEM format. And yes, this is may seem to be a
0322:             * little confusing, the method is called "publickey" in the SSH-2 protocol
0323:             * specification, however since we need to generate a signature, you
0324:             * actually have to supply a private key =).
0325:             * <p>
0326:             * The private key contained in the PEM file may also be encrypted ("Proc-Type: 4,ENCRYPTED").
0327:             * The library supports DES-CBC and DES-EDE3-CBC encryption, as well
0328:             * as the more exotic PEM encrpytions AES-128-CBC, AES-192-CBC and AES-256-CBC.
0329:             * <p>
0330:             * If the authentication phase is complete, <code>true</code> will be
0331:             * returned. If the server does not accept the request (or if further
0332:             * authentication steps are needed), <code>false</code> is returned and
0333:             * one can retry either by using this or any other authentication method
0334:             * (use the <code>getRemainingAuthMethods</code> method to get a list of
0335:             * the remaining possible methods).
0336:             * <p>
0337:             * NOTE PUTTY USERS: Event though your key file may start with "-----BEGIN..."
0338:             * it is not in the expected format. You have to convert it to the OpenSSH
0339:             * key format by using the "puttygen" tool (can be downloaded from the Putty
0340:             * website). Simply load your key and then use the "Conversions/Export OpenSSH key"
0341:             * functionality to get a proper PEM file.
0342:             * 
0343:             * @param user
0344:             *            A <code>String</code> holding the username.
0345:             * @param pemPrivateKey
0346:             *            A <code>char[]</code> containing a DSA or RSA private key of the
0347:             *            user in OpenSSH key format (PEM, you can't miss the
0348:             *            "-----BEGIN DSA PRIVATE KEY-----" or "-----BEGIN RSA PRIVATE KEY-----"
0349:             *            tag). The char array may contain linebreaks/linefeeds.
0350:             * @param password
0351:             *            If the PEM structure is encrypted ("Proc-Type: 4,ENCRYPTED") then
0352:             *            you must specify a password. Otherwise, this argument will be ignored
0353:             *            and can be set to <code>null</code>.
0354:             * 
0355:             * @return whether the connection is now authenticated.
0356:             * @throws IOException
0357:             */
0358:            public synchronized boolean authenticateWithPublicKey(String user,
0359:                    char[] pemPrivateKey, String password) throws IOException {
0360:                if (tm == null)
0361:                    throw new IllegalStateException(
0362:                            "Connection is not established!");
0363:
0364:                if (authenticated)
0365:                    throw new IllegalStateException(
0366:                            "Connection is already authenticated!");
0367:
0368:                if (am == null)
0369:                    am = new AuthenticationManager(tm);
0370:
0371:                if (cm == null)
0372:                    cm = new ChannelManager(tm);
0373:
0374:                if (user == null)
0375:                    throw new IllegalArgumentException("user argument is null");
0376:
0377:                if (pemPrivateKey == null)
0378:                    throw new IllegalArgumentException(
0379:                            "pemPrivateKey argument is null");
0380:
0381:                authenticated = am.authenticatePublicKey(user, pemPrivateKey,
0382:                        password, getOrCreateSecureRND());
0383:
0384:                return authenticated;
0385:            }
0386:
0387:            /**
0388:             * A convenience wrapper function which reads in a private key (PEM format, either DSA or RSA)
0389:             * and then calls <code>authenticateWithPublicKey(String, char[], String)</code>.
0390:             * <p>
0391:             * NOTE PUTTY USERS: Event though your key file may start with "-----BEGIN..."
0392:             * it is not in the expected format. You have to convert it to the OpenSSH
0393:             * key format by using the "puttygen" tool (can be downloaded from the Putty
0394:             * website). Simply load your key and then use the "Conversions/Export OpenSSH key"
0395:             * functionality to get a proper PEM file.
0396:             * 
0397:             * @param user
0398:             *            A <code>String</code> holding the username.
0399:             * @param pemFile
0400:             *            A <code>File</code> object pointing to a file containing a DSA or RSA
0401:             *            private key of the user in OpenSSH key format (PEM, you can't miss the
0402:             *            "-----BEGIN DSA PRIVATE KEY-----" or "-----BEGIN RSA PRIVATE KEY-----"
0403:             *            tag).
0404:             * @param password
0405:             *            If the PEM file is encrypted then you must specify the password.
0406:             *            Otherwise, this argument will be ignored and can be set to <code>null</code>.
0407:             * 
0408:             * @return whether the connection is now authenticated.
0409:             * @throws IOException
0410:             */
0411:            public synchronized boolean authenticateWithPublicKey(String user,
0412:                    File pemFile, String password) throws IOException {
0413:                if (pemFile == null)
0414:                    throw new IllegalArgumentException(
0415:                            "pemFile argument is null");
0416:
0417:                char[] buff = new char[256];
0418:
0419:                CharArrayWriter cw = new CharArrayWriter();
0420:
0421:                FileReader fr = new FileReader(pemFile);
0422:
0423:                while (true) {
0424:                    int len = fr.read(buff);
0425:                    if (len < 0)
0426:                        break;
0427:                    cw.write(buff, 0, len);
0428:                }
0429:
0430:                fr.close();
0431:
0432:                return authenticateWithPublicKey(user, cw.toCharArray(),
0433:                        password);
0434:            }
0435:
0436:            /**
0437:             * Add a {@link ConnectionMonitor} to this connection. Can be invoked at any time,
0438:             * but it is best to add connection monitors before invoking
0439:             * <code>connect()</code> to avoid glitches (e.g., you add a connection monitor after
0440:             * a successful connect(), but the connection has died in the mean time. Then,
0441:             * your connection monitor won't be notified.) 
0442:             * <p>
0443:             * You can add as many monitors as you like.
0444:             * 
0445:             * @see ConnectionMonitor
0446:             * 
0447:             * @param cmon An object implementing the <code>ConnectionMonitor</code> interface.
0448:             */
0449:            public synchronized void addConnectionMonitor(ConnectionMonitor cmon) {
0450:                if (cmon == null)
0451:                    throw new IllegalArgumentException("cmon argument is null");
0452:
0453:                connectionMonitors.addElement(cmon);
0454:
0455:                if (tm != null)
0456:                    tm.setConnectionMonitors(connectionMonitors);
0457:            }
0458:
0459:            /**
0460:             * Close the connection to the SSH-2 server. All assigned sessions will be
0461:             * closed, too. Can be called at any time. Don't forget to call this once
0462:             * you don't need a connection anymore - otherwise the receiver thread may
0463:             * run forever.
0464:             */
0465:            public synchronized void close() {
0466:                Throwable t = new Throwable("Closed due to user request.");
0467:                close(t, false);
0468:            }
0469:
0470:            private void close(Throwable t, boolean hard) {
0471:                if (cm != null)
0472:                    cm.closeAllChannels();
0473:
0474:                if (tm != null) {
0475:                    tm.close(t, hard == false);
0476:                    tm = null;
0477:                }
0478:                am = null;
0479:                cm = null;
0480:                authenticated = false;
0481:            }
0482:
0483:            /**
0484:             * Same as {@link #connect(ServerHostKeyVerifier, int, int) connect(null, 0, 0)}.
0485:             * 
0486:             * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method.
0487:             * @throws IOException
0488:             */
0489:            public synchronized ConnectionInfo connect() throws IOException {
0490:                return connect(null, 0, 0);
0491:            }
0492:
0493:            /**
0494:             * Same as {@link #connect(ServerHostKeyVerifier, int, int) connect(verifier, 0, 0)}.
0495:             * 
0496:             * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method.
0497:             * @throws IOException
0498:             */
0499:            public synchronized ConnectionInfo connect(
0500:                    ServerHostKeyVerifier verifier) throws IOException {
0501:                return connect(verifier, 0, 0);
0502:            }
0503:
0504:            /**
0505:             * Connect to the SSH-2 server and, as soon as the server has presented its
0506:             * host key, use the {@link ServerHostKeyVerifier#verifyServerHostKey(String,
0507:             * int, String, byte[]) ServerHostKeyVerifier.verifyServerHostKey()}
0508:             * method of the <code>verifier</code> to ask for permission to proceed.
0509:             * If <code>verifier</code> is <code>null</code>, then any host key will be
0510:             * accepted - this is NOT recommended, since it makes man-in-the-middle attackes
0511:             * VERY easy (somebody could put a proxy SSH server between you and the real server).
0512:             * <p>
0513:             * Note: The verifier will be called before doing any crypto calculations
0514:             * (i.e., diffie-hellman). Therefore, if you don't like the presented host key then
0515:             * no CPU cycles are wasted (and the evil server has less information about us).
0516:             * <p>
0517:             * However, it is still possible that the server presented a fake host key: the server
0518:             * cheated (typically a sign for a man-in-the-middle attack) and is not able to generate
0519:             * a signature that matches its host key. Don't worry, the library will detect such
0520:             * a scenario later when checking the signature (the signature cannot be checked before
0521:             * having completed the diffie-hellman exchange).
0522:             * <p>
0523:             * Note 2: The  {@link ServerHostKeyVerifier#verifyServerHostKey(String,
0524:             * int, String, byte[]) ServerHostKeyVerifier.verifyServerHostKey()} method
0525:             * will *NOT* be called from the current thread, the call is being made from a
0526:             * background thread (there is a background dispatcher thread for every
0527:             * established connection). 
0528:             * <p>
0529:             * Note 3: This method will block as long as the key exchange of the underlying connection
0530:             * has not been completed (and you have not specified any timeouts).
0531:             * <p>
0532:             * Note 4: If you want to re-use a connection object that was successfully connected,
0533:             * then you must call the {@link #close()} method before invoking <code>connect()</code> again.
0534:             * 
0535:             * @param verifier
0536:             *            An object that implements the
0537:             *            {@link ServerHostKeyVerifier} interface. Pass <code>null</code>
0538:             *            to accept any server host key - NOT recommended.
0539:             *            
0540:             * @param connectTimeout
0541:             *            Connect the underlying TCP socket to the server with the given timeout
0542:             *            value (non-negative, in milliseconds). Zero means no timeout. If a proxy is being
0543:             *            used (see {@link #setProxyData(ProxyData)}), then this timeout is used for the
0544:             *            connection establishment to the proxy.
0545:             * 
0546:             * @param kexTimeout
0547:             *            Timeout for complete connection establishment (non-negative,
0548:             *            in milliseconds). Zero means no timeout. The timeout counts from the
0549:             *            moment you invoke the connect() method and is cancelled as soon as the
0550:             *            first key-exchange round has finished. It is possible that
0551:             *            the timeout event will be fired during the invocation of the
0552:             *            <code>verifier</code> callback, but it will only have an effect after
0553:             *            the <code>verifier</code> returns.
0554:             *            
0555:             * @return A {@link ConnectionInfo} object containing the details of
0556:             *            the established connection.
0557:             *         
0558:             * @throws IOException
0559:             *            If any problem occurs, e.g., the server's host key is not
0560:             *            accepted by the <code>verifier</code> or there is problem during
0561:             *            the initial crypto setup (e.g., the signature sent by the server is wrong).
0562:             *            <p>
0563:             *            In case of a timeout (either connectTimeout or kexTimeout)
0564:             *            a SocketTimeoutException is thrown.
0565:             *            <p>
0566:             *            An exception may also be thrown if the connection was already successfully
0567:             *            connected (no matter if the connection broke in the mean time) and you invoke
0568:             *            <code>connect()</code> again without having called {@link #close()} first.
0569:             *            <p>
0570:             *            If a HTTP proxy is being used and the proxy refuses the connection,
0571:             *            then a {@link HTTPProxyException} may be thrown, which
0572:             *            contains the details returned by the proxy. If the proxy is buggy and does
0573:             *            not return a proper HTTP response, then a normal IOException is thrown instead.        
0574:             */
0575:            public synchronized ConnectionInfo connect(
0576:                    ServerHostKeyVerifier verifier, int connectTimeout,
0577:                    int kexTimeout) throws IOException {
0578:                final class TimeoutState {
0579:                    boolean isCancelled = false;
0580:                    boolean timeoutSocketClosed = false;
0581:                }
0582:
0583:                if (tm != null)
0584:                    throw new IOException("Connection to " + hostname
0585:                            + " is already in connected state!");
0586:
0587:                if (connectTimeout < 0)
0588:                    throw new IllegalArgumentException(
0589:                            "connectTimeout must be non-negative!");
0590:
0591:                if (kexTimeout < 0)
0592:                    throw new IllegalArgumentException(
0593:                            "kexTimeout must be non-negative!");
0594:
0595:                final TimeoutState state = new TimeoutState();
0596:
0597:                tm = new TransportManager(hostname, port);
0598:
0599:                tm.setConnectionMonitors(connectionMonitors);
0600:
0601:                /* Make sure that the runnable below will observe the new value of "tm"
0602:                 * and "state" (the runnable will be executed in a different thread, which
0603:                 * may be already running, that is why we need a memory barrier here).
0604:                 * See also the comment in Channel.java if you
0605:                 * are interested in the details.
0606:                 * 
0607:                 * OKOK, this is paranoid since adding the runnable to the todo list
0608:                 * of the TimeoutService will ensure that all writes have been flushed
0609:                 * before the Runnable reads anything
0610:                 * (there is a synchronized block in TimeoutService.addTimeoutHandler).
0611:                 */
0612:
0613:                synchronized (tm) {
0614:                    /* We could actually synchronize on anything. */
0615:                }
0616:
0617:                try {
0618:                    TimeoutToken token = null;
0619:
0620:                    if (kexTimeout > 0) {
0621:                        final Runnable timeoutHandler = new Runnable() {
0622:                            public void run() {
0623:                                synchronized (state) {
0624:                                    if (state.isCancelled)
0625:                                        return;
0626:                                    state.timeoutSocketClosed = true;
0627:                                    tm.close(new SocketTimeoutException(
0628:                                            "The connect timeout expired"),
0629:                                            false);
0630:                                }
0631:                            }
0632:                        };
0633:
0634:                        long timeoutHorizont = System.currentTimeMillis()
0635:                                + kexTimeout;
0636:
0637:                        token = TimeoutService.addTimeoutHandler(
0638:                                timeoutHorizont, timeoutHandler);
0639:                    }
0640:
0641:                    try {
0642:                        tm.initialize(cryptoWishList, verifier, dhgexpara,
0643:                                connectTimeout, getOrCreateSecureRND(),
0644:                                proxyData);
0645:                    } catch (SocketTimeoutException se) {
0646:                        throw (SocketTimeoutException) new SocketTimeoutException(
0647:                                "The connect() operation on the socket timed out.")
0648:                                .initCause(se);
0649:                    }
0650:
0651:                    tm.setTcpNoDelay(tcpNoDelay);
0652:
0653:                    /* Wait until first KEX has finished */
0654:
0655:                    ConnectionInfo ci = tm.getConnectionInfo(1);
0656:
0657:                    /* Now try to cancel the timeout, if needed */
0658:
0659:                    if (token != null) {
0660:                        TimeoutService.cancelTimeoutHandler(token);
0661:
0662:                        /* Were we too late? */
0663:
0664:                        synchronized (state) {
0665:                            if (state.timeoutSocketClosed)
0666:                                throw new IOException(
0667:                                        "This exception will be replaced by the one below =)");
0668:                            /* Just in case the "cancelTimeoutHandler" invocation came just a little bit
0669:                             * too late but the handler did not enter the semaphore yet - we can
0670:                             * still stop it.
0671:                             */
0672:                            state.isCancelled = true;
0673:                        }
0674:                    }
0675:
0676:                    return ci;
0677:                } catch (SocketTimeoutException ste) {
0678:                    throw ste;
0679:                } catch (IOException e1) {
0680:                    /* This will also invoke any registered connection monitors */
0681:                    close(new Throwable("There was a problem during connect."),
0682:                            false);
0683:
0684:                    synchronized (state) {
0685:                        /* Show a clean exception, not something like "the socket is closed!?!" */
0686:                        if (state.timeoutSocketClosed)
0687:                            throw new SocketTimeoutException("The kexTimeout ("
0688:                                    + kexTimeout + " ms) expired.");
0689:                    }
0690:
0691:                    /* Do not wrap a HTTPProxyException */
0692:                    if (e1 instanceof  HTTPProxyException)
0693:                        throw e1;
0694:
0695:                    throw (IOException) new IOException(
0696:                            "There was a problem while connecting to "
0697:                                    + hostname + ":" + port).initCause(e1);
0698:                }
0699:            }
0700:
0701:            /**
0702:             * Creates a new {@link LocalPortForwarder}.
0703:             * A <code>LocalPortForwarder</code> forwards TCP/IP connections that arrive at a local
0704:             * port via the secure tunnel to another host (which may or may not be
0705:             * identical to the remote SSH-2 server).
0706:             * <p>
0707:             * This method must only be called after one has passed successfully the authentication step.
0708:             * There is no limit on the number of concurrent forwardings.
0709:             * 
0710:             * @param local_port the local port the LocalPortForwarder shall bind to.
0711:             * @param host_to_connect target address (IP or hostname)
0712:             * @param port_to_connect target port
0713:             * @return A {@link LocalPortForwarder} object.
0714:             * @throws IOException
0715:             */
0716:            public synchronized LocalPortForwarder createLocalPortForwarder(
0717:                    int local_port, String host_to_connect, int port_to_connect)
0718:                    throws IOException {
0719:                if (tm == null)
0720:                    throw new IllegalStateException(
0721:                            "Cannot forward ports, you need to establish a connection first.");
0722:
0723:                if (!authenticated)
0724:                    throw new IllegalStateException(
0725:                            "Cannot forward ports, connection is not authenticated.");
0726:
0727:                return new LocalPortForwarder(cm, local_port, host_to_connect,
0728:                        port_to_connect);
0729:            }
0730:
0731:            /**
0732:             * Creates a new {@link LocalStreamForwarder}.
0733:             * A <code>LocalStreamForwarder</code> manages an Input/Outputstream pair
0734:             * that is being forwarded via the secure tunnel into a TCP/IP connection to another host
0735:             * (which may or may not be identical to the remote SSH-2 server).
0736:             * 
0737:             * @param host_to_connect
0738:             * @param port_to_connect
0739:             * @return A {@link LocalStreamForwarder} object.
0740:             * @throws IOException
0741:             */
0742:            public synchronized LocalStreamForwarder createLocalStreamForwarder(
0743:                    String host_to_connect, int port_to_connect)
0744:                    throws IOException {
0745:                if (tm == null)
0746:                    throw new IllegalStateException(
0747:                            "Cannot forward, you need to establish a connection first.");
0748:
0749:                if (!authenticated)
0750:                    throw new IllegalStateException(
0751:                            "Cannot forward, connection is not authenticated.");
0752:
0753:                return new LocalStreamForwarder(cm, host_to_connect,
0754:                        port_to_connect);
0755:            }
0756:
0757:            /**
0758:             * Create a very basic {@link SCPClient} that can be used to copy
0759:             * files from/to the SSH-2 server.
0760:             * <p>
0761:             * Works only after one has passed successfully the authentication step.
0762:             * There is no limit on the number of concurrent SCP clients.
0763:             * <p>
0764:             * Note: This factory method will probably disappear in the future.
0765:             * 
0766:             * @return A {@link SCPClient} object.
0767:             * @throws IOException
0768:             */
0769:            public synchronized SCPClient createSCPClient() throws IOException {
0770:                if (tm == null)
0771:                    throw new IllegalStateException(
0772:                            "Cannot create SCP client, you need to establish a connection first.");
0773:
0774:                if (!authenticated)
0775:                    throw new IllegalStateException(
0776:                            "Cannot create SCP client, connection is not authenticated.");
0777:
0778:                return new SCPClient(this );
0779:            }
0780:
0781:            /**
0782:             * Force an asynchronous key re-exchange (the call does not block). The
0783:             * latest values set for MAC, Cipher and DH group exchange parameters will
0784:             * be used. If a key exchange is currently in progress, then this method has
0785:             * the only effect that the so far specified parameters will be used for the
0786:             * next (server driven) key exchange.
0787:             * <p>
0788:             * Note: This implementation will never start a key exchange (other than the initial one)
0789:             * unless you or the SSH-2 server ask for it.
0790:             * 
0791:             * @throws IOException
0792:             *             In case of any failure behind the scenes.
0793:             */
0794:            public synchronized void forceKeyExchange() throws IOException {
0795:                if (tm == null)
0796:                    throw new IllegalStateException(
0797:                            "You need to establish a connection first.");
0798:
0799:                tm.forceKeyExchange(cryptoWishList, dhgexpara);
0800:            }
0801:
0802:            /**
0803:             * Returns the hostname that was passed to the constructor.
0804:             * 
0805:             * @return the hostname
0806:             */
0807:            public synchronized String getHostname() {
0808:                return hostname;
0809:            }
0810:
0811:            /**
0812:             * Returns the port that was passed to the constructor.
0813:             * 
0814:             * @return the TCP port
0815:             */
0816:            public synchronized int getPort() {
0817:                return port;
0818:            }
0819:
0820:            /**
0821:             * Returns a {@link ConnectionInfo} object containing the details of
0822:             * the connection. Can be called as soon as the connection has been
0823:             * established (successfully connected).
0824:             * 
0825:             * @return A {@link ConnectionInfo} object.
0826:             * @throws IOException
0827:             *             In case of any failure behind the scenes.
0828:             */
0829:            public synchronized ConnectionInfo getConnectionInfo()
0830:                    throws IOException {
0831:                if (tm == null)
0832:                    throw new IllegalStateException(
0833:                            "Cannot get details of connection, you need to establish a connection first.");
0834:                return tm.getConnectionInfo(1);
0835:            }
0836:
0837:            /**
0838:             * After a successful connect, one has to authenticate oneself. This method
0839:             * can be used to tell which authentication methods are supported by the
0840:             * server at a certain stage of the authentication process (for the given
0841:             * username).
0842:             * <p>
0843:             * Note 1: the username will only be used if no authentication step was done
0844:             * so far (it will be used to ask the server for a list of possible
0845:             * authentication methods). Otherwise, this method ignores the user name and
0846:             * returns a cached method list (which is based on the information contained
0847:             * in the last negative server response).
0848:             * <p>
0849:             * Note 2: the server may return method names that are not supported by this
0850:             * implementation.
0851:             * <p>
0852:             * After a successful authentication, this method must not be called
0853:             * anymore.
0854:             * 
0855:             * @param user
0856:             *            A <code>String</code> holding the username.
0857:             * 
0858:             * @return a (possibly emtpy) array holding authentication method names.
0859:             * @throws IOException
0860:             */
0861:            public synchronized String[] getRemainingAuthMethods(String user)
0862:                    throws IOException {
0863:                if (user == null)
0864:                    throw new IllegalArgumentException(
0865:                            "user argument may not be NULL!");
0866:
0867:                if (tm == null)
0868:                    throw new IllegalStateException(
0869:                            "Connection is not established!");
0870:
0871:                if (authenticated)
0872:                    throw new IllegalStateException(
0873:                            "Connection is already authenticated!");
0874:
0875:                if (am == null)
0876:                    am = new AuthenticationManager(tm);
0877:
0878:                if (cm == null)
0879:                    cm = new ChannelManager(tm);
0880:
0881:                return am.getRemainingMethods(user);
0882:            }
0883:
0884:            /**
0885:             * Determines if the authentication phase is complete. Can be called at any
0886:             * time.
0887:             * 
0888:             * @return <code>true</code> if no further authentication steps are
0889:             *         needed.
0890:             */
0891:            public synchronized boolean isAuthenticationComplete() {
0892:                return authenticated;
0893:            }
0894:
0895:            /**
0896:             * Returns true if there was at least one failed authentication request and
0897:             * the last failed authentication request was marked with "partial success"
0898:             * by the server. This is only needed in the rare case of SSH-2 server setups
0899:             * that cannot be satisfied with a single successful authentication request
0900:             * (i.e., multiple authentication steps are needed.)
0901:             * <p>
0902:             * If you are interested in the details, then have a look at
0903:             * draft-ietf-secsh-userauth-XX.txt.
0904:             * 
0905:             * @return if the there was a failed authentication step and the last one
0906:             *         was marked as a "partial success".
0907:             */
0908:            public synchronized boolean isAuthenticationPartialSuccess() {
0909:                if (am == null)
0910:                    return false;
0911:
0912:                return am.getPartialSuccess();
0913:            }
0914:
0915:            /**
0916:             * Checks if a specified authentication method is available. This method is
0917:             * actually just a wrapper for {@link #getRemainingAuthMethods(String)
0918:             * getRemainingAuthMethods()}.
0919:             * 
0920:             * @param user
0921:             *            A <code>String</code> holding the username.
0922:             * @param method
0923:             *            An authentication method name (e.g., "publickey", "password",
0924:             *            "keyboard-interactive") as specified by the SSH-2 standard.
0925:             * @return if the specified authentication method is currently available.
0926:             * @throws IOException
0927:             */
0928:            public synchronized boolean isAuthMethodAvailable(String user,
0929:                    String method) throws IOException {
0930:                if (method == null)
0931:                    throw new IllegalArgumentException(
0932:                            "method argument may not be NULL!");
0933:
0934:                String methods[] = getRemainingAuthMethods(user);
0935:
0936:                for (int i = 0; i < methods.length; i++) {
0937:                    if (methods[i].compareTo(method) == 0)
0938:                        return true;
0939:                }
0940:
0941:                return false;
0942:            }
0943:
0944:            private final SecureRandom getOrCreateSecureRND() {
0945:                if (generator == null)
0946:                    generator = new SecureRandom();
0947:
0948:                return generator;
0949:            }
0950:
0951:            /**
0952:             * Open a new {@link Session} on this connection. Works only after one has passed
0953:             * successfully the authentication step. There is no limit on the number of
0954:             * concurrent sessions.
0955:             * 
0956:             * @return A {@link Session} object.
0957:             * @throws IOException
0958:             */
0959:            public synchronized Session openSession() throws IOException {
0960:                if (tm == null)
0961:                    throw new IllegalStateException(
0962:                            "Cannot open session, you need to establish a connection first.");
0963:
0964:                if (!authenticated)
0965:                    throw new IllegalStateException(
0966:                            "Cannot open session, connection is not authenticated.");
0967:
0968:                return new Session(cm, getOrCreateSecureRND());
0969:            }
0970:
0971:            /**
0972:             * Removes duplicates from a String array, keeps only first occurence
0973:             * of each element. Does not destroy order of elements; can handle nulls.
0974:             * Uses a very efficient O(N^2) algorithm =)
0975:             * 
0976:             * @param list a String array.
0977:             * @return a cleaned String array.
0978:             */
0979:            private String[] removeDuplicates(String[] list) {
0980:                if ((list == null) || (list.length < 2))
0981:                    return list;
0982:
0983:                String[] list2 = new String[list.length];
0984:
0985:                int count = 0;
0986:
0987:                for (int i = 0; i < list.length; i++) {
0988:                    boolean duplicate = false;
0989:
0990:                    String element = list[i];
0991:
0992:                    for (int j = 0; j < count; j++) {
0993:                        if (((element == null) && (list2[j] == null))
0994:                                || ((element != null) && (element
0995:                                        .equals(list2[j])))) {
0996:                            duplicate = true;
0997:                            break;
0998:                        }
0999:                    }
1000:
1001:                    if (duplicate)
1002:                        continue;
1003:
1004:                    list2[count++] = list[i];
1005:                }
1006:
1007:                if (count == list2.length)
1008:                    return list2;
1009:
1010:                String[] tmp = new String[count];
1011:                System.arraycopy(list2, 0, tmp, 0, count);
1012:
1013:                return tmp;
1014:            }
1015:
1016:            /**
1017:             * Unless you know what you are doing, you will never need this.
1018:             * 
1019:             * @param ciphers
1020:             */
1021:            public synchronized void setClient2ServerCiphers(String[] ciphers) {
1022:                if ((ciphers == null) || (ciphers.length == 0))
1023:                    throw new IllegalArgumentException();
1024:                ciphers = removeDuplicates(ciphers);
1025:                BlockCipherFactory.checkCipherList(ciphers);
1026:                cryptoWishList.c2s_enc_algos = ciphers;
1027:            }
1028:
1029:            /**
1030:             * Unless you know what you are doing, you will never need this.
1031:             * 
1032:             * @param macs
1033:             */
1034:            public synchronized void setClient2ServerMACs(String[] macs) {
1035:                if ((macs == null) || (macs.length == 0))
1036:                    throw new IllegalArgumentException();
1037:                macs = removeDuplicates(macs);
1038:                MAC.checkMacList(macs);
1039:                cryptoWishList.c2s_mac_algos = macs;
1040:            }
1041:
1042:            /**
1043:             * Sets the parameters for the diffie-hellman group exchange. Unless you
1044:             * know what you are doing, you will never need this. Default values are
1045:             * defined in the {@link DHGexParameters} class.
1046:             * 
1047:             * @param dgp {@link DHGexParameters}, non null.
1048:             * 
1049:             */
1050:            public synchronized void setDHGexParameters(DHGexParameters dgp) {
1051:                if (dgp == null)
1052:                    throw new IllegalArgumentException();
1053:
1054:                dhgexpara = dgp;
1055:            }
1056:
1057:            /**
1058:             * Unless you know what you are doing, you will never need this.
1059:             * 
1060:             * @param ciphers
1061:             */
1062:            public synchronized void setServer2ClientCiphers(String[] ciphers) {
1063:                if ((ciphers == null) || (ciphers.length == 0))
1064:                    throw new IllegalArgumentException();
1065:                ciphers = removeDuplicates(ciphers);
1066:                BlockCipherFactory.checkCipherList(ciphers);
1067:                cryptoWishList.s2c_enc_algos = ciphers;
1068:            }
1069:
1070:            /**
1071:             * Unless you know what you are doing, you will never need this.
1072:             * 
1073:             * @param macs
1074:             */
1075:            public synchronized void setServer2ClientMACs(String[] macs) {
1076:                if ((macs == null) || (macs.length == 0))
1077:                    throw new IllegalArgumentException();
1078:
1079:                macs = removeDuplicates(macs);
1080:                MAC.checkMacList(macs);
1081:                cryptoWishList.s2c_mac_algos = macs;
1082:            }
1083:
1084:            /**
1085:             * Define the set of allowed server host key algorithms to be used for
1086:             * the following key exchange operations.
1087:             * <p>
1088:             * Unless you know what you are doing, you will never need this.
1089:             * 
1090:             * @param algos An array of allowed server host key algorithms.
1091:             * 	SSH-2 defines <code>ssh-dss</code> and <code>ssh-rsa</code>.
1092:             * 	The entries of the array must be ordered after preference, i.e.,
1093:             *  the entry at index 0 is the most preferred one. You must specify
1094:             *  at least one entry.
1095:             */
1096:            public synchronized void setServerHostKeyAlgorithms(String[] algos) {
1097:                if ((algos == null) || (algos.length == 0))
1098:                    throw new IllegalArgumentException();
1099:
1100:                algos = removeDuplicates(algos);
1101:                KexManager.checkServerHostkeyAlgorithmsList(algos);
1102:                cryptoWishList.serverHostKeyAlgorithms = algos;
1103:            }
1104:
1105:            /**
1106:             * Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm) on the underlying socket.
1107:             * <p>
1108:             * Can be called at any time. If the connection has not yet been established
1109:             * then the passed value will be stored and set after the socket has been set up.
1110:             * The default value that will be used is <code>false</code>.
1111:             * 
1112:             * @param enable the argument passed to the <code>Socket.setTCPNoDelay()</code> method.
1113:             * @throws IOException
1114:             */
1115:            public synchronized void setTCPNoDelay(boolean enable)
1116:                    throws IOException {
1117:                tcpNoDelay = enable;
1118:
1119:                if (tm != null)
1120:                    tm.setTcpNoDelay(enable);
1121:            }
1122:
1123:            /**
1124:             * Used to tell the library that the connection shall be established through a proxy server.
1125:             * It only makes sense to call this method before calling the {@link #connect() connect()}
1126:             * method.
1127:             * <p>
1128:             * At the moment, only HTTP proxies are supported.
1129:             * <p>
1130:             * Note: This method can be called any number of times. The {@link #connect() connect()}
1131:             * method will use the value set in the last preceding invocation of this method.
1132:             * 
1133:             * @see HTTPProxyData
1134:             * 
1135:             * @param proxyData Connection information about the proxy. If <code>null</code>, then
1136:             *                  no proxy will be used (non surprisingly, this is also the default).
1137:             */
1138:            public synchronized void setProxyData(ProxyData proxyData) {
1139:                this .proxyData = proxyData;
1140:            }
1141:
1142:            /**
1143:             * Request a remote port forwarding.
1144:             * If successful, then forwarded connections will be redirected to the given target address.
1145:             * You can cancle a requested remote port forwarding by calling
1146:             * {@link #cancelRemotePortForwarding(int) cancelRemotePortForwarding()}.
1147:             * <p>
1148:             * A call of this method will block until the peer either agreed or disagreed to your request-
1149:             * <p>
1150:             * Note 1: this method typically fails if you
1151:             * <ul>
1152:             * <li>pass a port number for which the used remote user has not enough permissions (i.e., port
1153:             * &lt; 1024)</li>
1154:             * <li>or pass a port number that is already in use on the remote server</li>
1155:             * <li>or if remote port forwarding is disabled on the server.</li>
1156:             * </ul>
1157:             * <p>
1158:             * Note 2: (from the openssh man page): By default, the listening socket on the server will be
1159:             * bound to the loopback interface only. This may be overriden by specifying a bind address.
1160:             * Specifying a remote bind address will only succeed if the server's <b>GatewayPorts</b> option
1161:             * is enabled (see sshd_config(5)).
1162:             * 
1163:             * @param bindAddress address to bind to on the server:
1164:             *                    <ul>
1165:             *                    <li>"" means that connections are to be accepted on all protocol families
1166:             *                    supported by the SSH implementation</li>
1167:             *                    <li>"0.0.0.0" means to listen on all IPv4 addresses</li>
1168:             *                    <li>"::" means to listen on all IPv6 addresses</li>
1169:             *                    <li>"localhost" means to listen on all protocol families supported by the SSH
1170:             *                    implementation on loopback addresses only, [RFC3330] and RFC3513]</li>
1171:             *                    <li>"127.0.0.1" and "::1" indicate listening on the loopback interfaces for
1172:             *                    IPv4 and IPv6 respectively</li>
1173:             *                    </ul>
1174:             * @param bindPort port number to bind on the server (must be &gt; 0)
1175:             * @param targetAddress the target address (IP or hostname)
1176:             * @param targetPort the target port
1177:             * @throws IOException
1178:             */
1179:            public synchronized void requestRemotePortForwarding(
1180:                    String bindAddress, int bindPort, String targetAddress,
1181:                    int targetPort) throws IOException {
1182:                if (tm == null)
1183:                    throw new IllegalStateException(
1184:                            "You need to establish a connection first.");
1185:
1186:                if (!authenticated)
1187:                    throw new IllegalStateException(
1188:                            "The connection is not authenticated.");
1189:
1190:                if ((bindAddress == null) || (targetAddress == null)
1191:                        || (bindPort <= 0) || (targetPort <= 0))
1192:                    throw new IllegalArgumentException();
1193:
1194:                cm.requestGlobalForward(bindAddress, bindPort, targetAddress,
1195:                        targetPort);
1196:            }
1197:
1198:            /**
1199:             * Cancel an earlier requested remote port forwarding. 
1200:             * Currently active forwardings will not be affected (e.g., disrupted).
1201:             * Note that further connection forwarding requests may be received until
1202:             * this method has returned.
1203:             * 
1204:             * @param bindPort the allocated port number on the server
1205:             * @throws IOException if the remote side refuses the cancel request or another low
1206:             *         level error occurs (e.g., the underlying connection is closed)
1207:             */
1208:            public synchronized void cancelRemotePortForwarding(int bindPort)
1209:                    throws IOException {
1210:                if (tm == null)
1211:                    throw new IllegalStateException(
1212:                            "You need to establish a connection first.");
1213:
1214:                if (!authenticated)
1215:                    throw new IllegalStateException(
1216:                            "The connection is not authenticated.");
1217:
1218:                cm.requestCancelGlobalForward(bindPort);
1219:            }
1220:
1221:            /**
1222:             * Provide your own instance of SecureRandom. Can be used, e.g., if you
1223:             * want to seed the used SecureRandom generator manually.
1224:             * <p>
1225:             * The SecureRandom instance is used during key exchanges, public key authentication,
1226:             * x11 cookie generation and the like.
1227:             * 
1228:             * @param rnd a SecureRandom instance
1229:             */
1230:            public synchronized void setSecureRandom(SecureRandom rnd) {
1231:                if (rnd == null)
1232:                    throw new IllegalArgumentException();
1233:
1234:                this.generator = rnd;
1235:            }
1236:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.