Save This Page
Home » j2ssh-0.2.9-src » com.sshtools.j2ssh » [javadoc | source]
    1   /*
    2    *  SSHTools - Java SSH2 API
    3    *
    4    *  Copyright (C) 2002-2003 Lee David Painter and Contributors.
    5    *
    6    *  Contributions made by:
    7    *
    8    *  Brett Smith
    9    *  Richard Pernavas
   10    *  Erwin Bolwidt
   11    *
   12    *  This program is free software; you can redistribute it and/or
   13    *  modify it under the terms of the GNU General Public License
   14    *  as published by the Free Software Foundation; either version 2
   15    *  of the License, or (at your option) any later version.
   16    *
   17    *  This program is distributed in the hope that it will be useful,
   18    *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   19    *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   20    *  GNU General Public License for more details.
   21    *
   22    *  You should have received a copy of the GNU General Public License
   23    *  along with this program; if not, write to the Free Software
   24    *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   25    */
   26   package com.sshtools.j2ssh;
   27   
   28   import com.sshtools.j2ssh.authentication.AuthenticationProtocolClient;
   29   import com.sshtools.j2ssh.authentication.AuthenticationProtocolState;
   30   import com.sshtools.j2ssh.authentication.PublicKeyAuthenticationClient;
   31   import com.sshtools.j2ssh.authentication.SshAuthenticationClient;
   32   import com.sshtools.j2ssh.configuration.SshConnectionProperties;
   33   import com.sshtools.j2ssh.connection.Channel;
   34   import com.sshtools.j2ssh.connection.ChannelEventAdapter;
   35   import com.sshtools.j2ssh.connection.ChannelEventListener;
   36   import com.sshtools.j2ssh.connection.ChannelFactory;
   37   import com.sshtools.j2ssh.connection.ConnectionProtocol;
   38   import com.sshtools.j2ssh.forwarding.ForwardingClient;
   39   import com.sshtools.j2ssh.net.TransportProvider;
   40   import com.sshtools.j2ssh.net.TransportProviderFactory;
   41   import com.sshtools.j2ssh.session.SessionChannelClient;
   42   import com.sshtools.j2ssh.sftp.SftpSubsystemClient;
   43   import com.sshtools.j2ssh.transport.ConsoleKnownHostsKeyVerification;
   44   import com.sshtools.j2ssh.transport.HostKeyVerification;
   45   import com.sshtools.j2ssh.transport.TransportProtocolClient;
   46   import com.sshtools.j2ssh.transport.TransportProtocolState;
   47   import com.sshtools.j2ssh.transport.publickey.SshPublicKey;
   48   import com.sshtools.j2ssh.util.State;
   49   
   50   import org.apache.commons.logging.Log;
   51   import org.apache.commons.logging.LogFactory;
   52   
   53   import java.io.File;
   54   import java.io.IOException;
   55   
   56   import java.net.UnknownHostException;
   57   
   58   import java.util.Iterator;
   59   import java.util.List;
   60   import java.util.Vector;
   61   
   62   
   63   /**
   64    * <p>
   65    * Implements an SSH client with methods to connect to a remote server and
   66    * perform all necersary SSH functions such as SCP, SFTP, executing commands,
   67    * starting the users shell and perform port forwarding.
   68    * </p>
   69    *
   70    * <p>
   71    * There are several steps to perform prior to performing the desired task.
   72    * This involves the making the initial connection, authenticating the user
   73    * and creating a session to execute a command, shell or subsystem and/or
   74    * configuring the port forwarding manager.
   75    * </p>
   76    *
   77    * <p>
   78    * To create a connection use the following code:<br>
   79    * <blockquote><pre>
   80    * // Create a instance and connect SshClient
   81    * ssh = new SshClient();
   82    * ssh.connect("hostname");
   83    * </pre></blockquote>
   84    * Once this code has executed and returned
   85    * the connection is ready for authentication:<br>
   86    * <blockquote><pre>
   87    * PasswordAuthenticationClient pwd = new PasswordAuthenticationClient();
   88    * pwd.setUsername("foo");
   89    * pwd.setPassword("xxxxx");
   90    * // Authenticate the user
   91    * int result = ssh.authenticate(pwd);
   92    * if(result==AuthenticationProtocolState.COMPLETED) {
   93    *    // Authentication complete
   94    * }
   95    * </pre></blockquote>
   96    * Once authenticated the user's shell can be started:<br>
   97    * <blockquote><pre>
   98    * // Open a session channel
   99    * SessionChannelClient session =
  100    *                      ssh.openSessionChannel();
  101    *
  102    * // Request a pseudo terminal, if you do not you may not see the prompt
  103    * if(session.requestPseudoTerminal("ansi", 80, 24, 0, 0, "") {
  104    *      // Start the users shell
  105    *      if(session.startShell()) {
  106    *         // Do something with the session output
  107    *         session.getOutputStream().write("echo message\n");
  108    *         ....
  109    *       }
  110    * }
  111    * </pre></blockquote>
  112    * </p>
  113    *
  114    * @author Lee David Painter
  115    * @version $Revision: 1.75 $
  116    *
  117    * @since 0.2.0
  118    */
  119   public class SshClient {
  120       private static Log log = LogFactory.getLog(SshClient.class);
  121   
  122       /**
  123        * The SSH Authentication protocol implementation for this SSH client. The
  124        * SSH Authentication protocol runs over the SSH Transport protocol as a
  125        * transport protocol service.
  126        */
  127       protected AuthenticationProtocolClient authentication;
  128   
  129       /**
  130        * The SSH Connection protocol implementation for this SSH client. The
  131        * connection protocol runs over the SSH Transport protocol as a transport
  132        * protocol service and is started by the authentication protocol after a
  133        * successful authentication.
  134        */
  135       protected ConnectionProtocol connection;
  136   
  137       /** Provides a high level management interface for SSH port forwarding. */
  138       protected ForwardingClient forwarding;
  139   
  140       /** The SSH Transport protocol implementation for this SSH Client. */
  141       protected TransportProtocolClient transport;
  142   
  143       /** The current state of the authentication for the current connection. */
  144       protected int authenticationState = AuthenticationProtocolState.READY;
  145   
  146       /**
  147        * The timeout in milliseconds for the underlying transport provider
  148        * (typically a Socket).
  149        */
  150       protected int socketTimeout = 0;
  151   
  152       /**
  153        * A Transport protocol event handler instance that receives notifications
  154        * of transport layer events such as Socket timeouts and disconnection.
  155        */
  156       protected SshEventAdapter eventHandler = null;
  157   
  158       /** The currently active channels for this SSH Client connection. */
  159       protected Vector activeChannels = new Vector();
  160   
  161       /**
  162        * An channel event listener implemention to maintain the active channel
  163        * list.
  164        */
  165       protected ActiveChannelEventListener activeChannelListener = new ActiveChannelEventListener();
  166   
  167       /**
  168        * Flag indicating whether the forwarding instance is created when the
  169        * connection is made.
  170        */
  171       protected boolean useDefaultForwarding = true;
  172   
  173       /** The currently active Sftp clients */
  174       private Vector activeSftpClients = new Vector();
  175   
  176       /**
  177        * <p>
  178        * Contructs an unitilialized SshClient ready for connecting.
  179        * </p>
  180        */
  181       public SshClient() {
  182       }
  183   
  184       /**
  185        * <p>
  186        * Returns the server's authentication banner.
  187        * </p>
  188        *
  189        * <p>
  190        * In some jurisdictions, sending a warning message before authentication
  191        * may be relevant for getting legal protection.  Many UNIX machines, for
  192        * example, normally display text from `/etc/issue', or use "tcp wrappers"
  193        * or similar software to display a banner before issuing a login prompt.
  194        * </p>
  195        *
  196        * <p>
  197        * The server may or may not send this message. Call this method to
  198        * retrieve the message, specifying a timeout limit to wait for the
  199        * message.
  200        * </p>
  201        *
  202        * @param timeout The number of milliseconds to wait for the banner message
  203        *        before returning
  204        *
  205        * @return The server's banner message
  206        *
  207        * @exception IOException If an IO error occurs reading the message
  208        *
  209        * @since 0.2.0
  210        */
  211       public String getAuthenticationBanner(int timeout)
  212           throws IOException {
  213           if (authentication == null) {
  214               return "";
  215           } else {
  216               return authentication.getBannerMessage(timeout);
  217           }
  218       }
  219   
  220       /**
  221        * <p>
  222        * Returns the list of available authentication methods for a given user.
  223        * </p>
  224        *
  225        * <p>
  226        * A client may request a list of authentication methods that may continue
  227        * by using the "none" authentication method.This method calls the "none"
  228        * method and returns the available authentication methods.
  229        * </p>
  230        *
  231        * @param username The name of the account for which you require the
  232        *        available authentication methods
  233        *
  234        * @return A list of Strings, for example "password", "publickey" &
  235        *         "keyboard-interactive"
  236        *
  237        * @exception IOException If an IO error occurs during the operation
  238        *
  239        * @since 0.2.0
  240        */
  241       public List getAvailableAuthMethods(String username)
  242           throws IOException {
  243           if (authentication != null) {
  244               return authentication.getAvailableAuths(username,
  245                   connection.getServiceName());
  246           } else {
  247               return null;
  248           }
  249       }
  250   
  251       /**
  252        * <p>
  253        * Returns the connection state of the client.
  254        * </p>
  255        *
  256        * @return true if the client is connected, false otherwise
  257        *
  258        * @since 0.2.0
  259        */
  260       public boolean isConnected() {
  261           State state = (transport == null) ? null : transport.getState();
  262           int value = (state == null) ? TransportProtocolState.DISCONNECTED
  263                                       : state.getValue();
  264   
  265           return ((value == TransportProtocolState.CONNECTED) ||
  266           (value == TransportProtocolState.PERFORMING_KEYEXCHANGE));
  267       }
  268   
  269       /**
  270        * <p>
  271        * Evaluate whether the client has successfully authenticated.
  272        * </p>
  273        *
  274        * @return true if the client is authenticated, otherwise false
  275        */
  276       public boolean isAuthenticated() {
  277           return authenticationState == AuthenticationProtocolState.COMPLETE;
  278       }
  279   
  280       /**
  281        * <p>
  282        * Returns the identification string sent by the server during protocol
  283        * negotiation. For example "SSH-2.0-OpenSSH_p3.4".
  284        * </p>
  285        *
  286        * @return The server's identification string.
  287        *
  288        * @since 0.2.0
  289        */
  290       public String getServerId() {
  291           return transport.getRemoteId();
  292       }
  293   
  294       /**
  295        * <p>
  296        * Returns the server's public key supplied during key exchange.
  297        * </p>
  298        *
  299        * @return the server's public key
  300        *
  301        * @since 0.2.0
  302        */
  303       public SshPublicKey getServerHostKey() {
  304           return transport.getServerHostKey();
  305       }
  306   
  307       /**
  308        * <p>
  309        * Returns the transport protocol's connection state.
  310        * </p>
  311        *
  312        * @return The transport protocol's state
  313        *
  314        * @since 0.2.0
  315        */
  316       public TransportProtocolState getConnectionState() {
  317           return transport.getState();
  318       }
  319   
  320       /**
  321        * <p>
  322        * Returns the default port forwarding manager.
  323        * </p>
  324        *
  325        * @return This connection's forwarding client
  326        *
  327        * @since 0.2.0
  328        */
  329       public ForwardingClient getForwardingClient() {
  330           return forwarding;
  331       }
  332   
  333       /**
  334        * <p>
  335        * Return's a rough guess at the server's EOL setting. This is simply
  336        * derived from the identification string and should not be used as a cast
  337        * iron proof on the EOL setting.
  338        * </p>
  339        *
  340        * @return The transport protocol's EOL constant
  341        *
  342        * @since 0.2.0
  343        */
  344       public int getRemoteEOL() {
  345           return transport.getRemoteEOL();
  346       }
  347   
  348       /**
  349        * <p>
  350        * Set the event handler for the underlying transport protocol.
  351        * </p>
  352        * <blockquote>
  353        * <pre>
  354        * ssh.setEventHandler(new TransportProtocolEventHandler() {
  355        *
  356        *   public void onSocketTimeout(TransportProtocol transport) {<br>
  357        *     // Do something to handle the socket timeout<br>
  358        *   }
  359        *
  360        *   public void onDisconnect(TransportProtocol transport) {
  361        *     // Perhaps some clean up?
  362        *   }
  363        * });
  364        * </pre>
  365        * </blockquote>
  366        *
  367        * @param eventHandler The event handler instance to receive transport
  368        *        protocol events
  369        *
  370        * @see com.sshtools.j2ssh.transport.TransportProtocolEventHandler
  371        * @since 0.2.0
  372        */
  373       public void addEventHandler(SshEventAdapter eventHandler) {
  374           // If were connected then add, otherwise store for later connection
  375           if (transport != null) {
  376               transport.addEventHandler(eventHandler);
  377               authentication.addEventListener(eventHandler);
  378           } else {
  379               this.eventHandler = eventHandler;
  380           }
  381       }
  382   
  383       /**
  384        * <p>
  385        * Set's the socket timeout (in milliseconds) for the underlying transport
  386        * provider. This MUST be called prior to connect.
  387        * </p>
  388        * <blockquote>
  389        * SshClient ssh = new SshClient();
  390        * ssh.setSocketTimeout(30000);
  391        * ssh.connect("hostname");
  392        * </blockquote>
  393        *
  394        * @param milliseconds The number of milliseconds without activity before
  395        *        the timeout event occurs
  396        *
  397        * @since 0.2.0
  398        */
  399       public void setSocketTimeout(int milliseconds) {
  400           this.socketTimeout = milliseconds;
  401       }
  402   
  403       /**
  404        * <p>
  405        * Return's a rough guess at the server's EOL setting. This is simply
  406        * derived from the identification string and should not be used as a cast
  407        * iron proof on the EOL setting.
  408        * </p>
  409        *
  410        * @return The EOL string
  411        *
  412        * @since 0.2.0
  413        */
  414       public String getRemoteEOLString() {
  415           return ((transport.getRemoteEOL() == TransportProtocolClient.EOL_CRLF)
  416           ? "\r\n" : "\n");
  417       }
  418   
  419       /**
  420        * Get the connection properties for this connection.
  421        *
  422        * @return
  423        */
  424       public SshConnectionProperties getConnectionProperties() {
  425           return transport.getProperties();
  426       }
  427   
  428       /**
  429        * <p>
  430        * Authenticate the user on the remote host.
  431        * </p>
  432        *
  433        * <p>
  434        * To authenticate the user, create an <code>SshAuthenticationClient</code>
  435        * instance and configure it with the authentication details.
  436        * </p>
  437        * <code> PasswordAuthenticationClient pwd = new
  438        * PasswordAuthenticationClient(); pwd.setUsername("root");
  439        * pwd.setPassword("xxxxxxxxx"); int result = ssh.authenticate(pwd);
  440        * </code>
  441        *
  442        * <p>
  443        * The method returns a result value will one of the public static values
  444        * defined in <code>AuthenticationProtocolState</code>. These are<br>
  445        * <br>
  446        * COMPLETED - The authentication succeeded.<br>
  447        * PARTIAL   - The authentication succeeded but a further authentication
  448        * method is required.<br>
  449        * FAILED    - The authentication failed.<br>
  450        * CANCELLED - The user cancelled authentication (can only be returned
  451        * when the user is prompted for information.<br>
  452        * </p>
  453        *
  454        * @param auth A configured SshAuthenticationClient instance ready for
  455        *        authentication
  456        *
  457        * @return The authentication result
  458        *
  459        * @exception IOException If an IO error occurs during authentication
  460        *
  461        * @since 0.2.0
  462        */
  463       public int authenticate(SshAuthenticationClient auth)
  464           throws IOException {
  465           // Do the authentication
  466           authenticationState = authentication.authenticate(auth, connection);
  467   
  468           if ((authenticationState == AuthenticationProtocolState.COMPLETE) &&
  469                   useDefaultForwarding) {
  470               // Use some method to synchronize forwardings on the ForwardingClient
  471               forwarding.synchronizeConfiguration(transport.getProperties());
  472           }
  473   
  474           return authenticationState;
  475       }
  476   
  477       /**
  478        * <p>
  479        * Determine whether a private/public key pair will be accepted for public
  480        * key authentication.
  481        * </p>
  482        *
  483        * <p>
  484        * When using public key authentication, the signing of data could take
  485        * some time depending upon the available machine resources. By calling
  486        * this method, you can determine whether the server will accept a key for
  487        * authentication by providing the public key. The server will verify the
  488        * key against the user's authorized keys and return true should the
  489        * public key be authorized. The caller can then proceed with the private
  490        * key operation.
  491        * </p>
  492        *
  493        * @param username The username for authentication
  494        * @param key The public key for which authentication will be attempted
  495        *
  496        * @return true if the server will accept the key, otherwise false
  497        *
  498        * @exception IOException If an IO error occurs during the operation
  499        * @throws SshException
  500        *
  501        * @since 0.2.0
  502        */
  503       public boolean acceptsKey(String username, SshPublicKey key)
  504           throws IOException {
  505           if (authenticationState != AuthenticationProtocolState.COMPLETE) {
  506               PublicKeyAuthenticationClient pk = new PublicKeyAuthenticationClient();
  507   
  508               return pk.acceptsKey(authentication, username,
  509                   connection.getServiceName(), key);
  510           } else {
  511               throw new SshException("Authentication has been completed!");
  512           }
  513       }
  514   
  515       /**
  516        * <p>
  517        * Connect the client to the server using default connection properties.
  518        * </p>
  519        *
  520        * <p>
  521        * This call attempts to connect to the hostname specified on the standard
  522        * SSH port of 22 and uses all the default connection properties. This
  523        * call is the equivilent of calling:
  524        * </p>
  525        * <blockquote><pre>
  526        * SshConnectionProperties properties = new
  527        *                           SshConnectionProperties();
  528        * properties.setHostname("hostname");
  529        * ssh.connect(properties);
  530        * </pre></blockquote>
  531        *
  532        * @param hostname The hostname of the server to connect
  533        *
  534        * @exception IOException If an IO error occurs during the connect
  535        *            operation
  536        *
  537        * @see #connect(com.sshtools.j2ssh.configuration.SshConnectionProperties)
  538        * @since 0.2.0
  539        */
  540       public void connect(String hostname) throws IOException {
  541           connect(hostname, 22, new ConsoleKnownHostsKeyVerification());
  542       }
  543   
  544       /**
  545        * <p>
  546        * Connect the client to the server using the default connection
  547        * properties.
  548        * </p>
  549        *
  550        * <p>
  551        * This call attempts to connect to the hostname specified on the standard
  552        * SSH port of 22 and uses all the default connection properties. When
  553        * this method returns the connection has been established, the server's
  554        * identity been verified and the connection is ready for user
  555        * authentication. Host key verification will be performed using the host
  556        * key verification instance provided:
  557        * </p>
  558        * <blockquote><pre>
  559        * // Connect and consult $HOME/.ssh/known_hosts
  560        * ssh.connect("hostname", new ConsoleKnownHostsKeyVerification());
  561        * // Connect and allow any host
  562        * ssh.connect("hostname", new
  563        *                 IgnoreHostKeyVerification());
  564        * </pre></blockquote>
  565        *
  566        * <p>
  567        * You can provide your own host key verification process by implementing
  568        * the <code>HostKeyVerification</code> interface.
  569        * </p>
  570        *
  571        * @param hostname The hostname of the server to connect
  572        * @param hosts The host key verification instance to consult for host key
  573        *        validation
  574        *
  575        * @exception IOException If an IO error occurs during the connect
  576        *            operation
  577        *
  578        * @see #connect(com.sshtools.j2ssh.configuration.SshConnectionProperties,
  579        *      com.sshtools.j2ssh.transport.HostKeyVerification)
  580        * @since 0.2.0
  581        */
  582       public void connect(String hostname, HostKeyVerification hosts)
  583           throws IOException {
  584           connect(hostname, 22, hosts);
  585       }
  586   
  587       /**
  588        * <p>
  589        * Connect the client to the server on a specified port with default
  590        * connection properties.
  591        * </p>
  592        *
  593        * <p>
  594        * This call attempts to connect to the hostname and port specified. This
  595        * call is the equivilent of calling:
  596        * </p>
  597        * <blockquote></pre>
  598        * SshConnectionProperties properties = new
  599        *                               SshConnectionProperties();
  600        * properties.setHostname("hostname");
  601        * properties.setPort(10022);
  602        * ssh.connect(properties);
  603        * </pre></blockquote>
  604        *
  605        * @param hostname The hostname of the server to connect
  606        * @param port The port to connect
  607        *
  608        * @exception IOException If an IO error occurs during the connect
  609        *            operation
  610        *
  611        * @see #connect(com.sshtools.j2ssh.configuration.SshConnectionProperties)
  612        * @since 0.2.0
  613        */
  614       public void connect(String hostname, int port) throws IOException {
  615           connect(hostname, port, new ConsoleKnownHostsKeyVerification());
  616       }
  617   
  618       /**
  619        * <p>
  620        * Connect the client to the server on a specified port with default
  621        * connection properties.
  622        * </p>
  623        *
  624        * <p>
  625        * This call attempts to connect to the hostname and port specified. When
  626        * this method returns the connection has been established, the server's
  627        * identity been verified and the connection is ready for user
  628        * authentication. Host key verification will be performed using the host
  629        * key verification instance provided:
  630        * </p>
  631        * <blockquote><pre>
  632        * // Connect and consult $HOME/.ssh/known_hosts
  633        * ssh.connect("hostname", new ConsoleKnownHostsKeyVerification());
  634        * // Connect and allow any host
  635        * ssh.connect("hostname", new
  636        *                 IgnoreHostKeyVerification());
  637        * </pre></blockquote>
  638        *
  639        * <p>
  640        * You can provide your own host key verification process by implementing
  641        * the <code>HostKeyVerification</code> interface.
  642        * </p>
  643        *
  644        * @param hostname The hostname of the server to connect
  645        * @param port The port to connect
  646        * @param hosts The host key verification instance to consult for host key
  647        *        validation
  648        *
  649        * @exception IOException If an IO error occurs during the connect
  650        *            operation
  651        *
  652        * @see #connect(com.sshtools.j2ssh.configuration.SshConnectionProperties,
  653        *      com.sshtools.j2ssh.transport.HostKeyVerification)
  654        * @since 0.2.0
  655        */
  656       public void connect(String hostname, int port, HostKeyVerification hosts)
  657           throws IOException {
  658           SshConnectionProperties properties = new SshConnectionProperties();
  659           properties.setHost(hostname);
  660           properties.setPort(port);
  661           connect(properties, hosts);
  662       }
  663   
  664       /**
  665        * <p>
  666        * Connect the client to the server with the specified properties.
  667        * </p>
  668        *
  669        * <p>
  670        * This call attempts to connect to using the connection properties
  671        * specified. When this method returns the connection has been
  672        * established, the server's identity been verified and the connection is
  673        * ready for user authentication. To use this method first create a
  674        * properties instance and set the required fields.
  675        * </p>
  676        * <blockquote><pre>
  677        * SshConnectionProperties properties = new
  678        *                         SshConnectionProperties();
  679        * properties.setHostname("hostname");
  680        * properties.setPort(10022);
  681        * properties.setPrefCSEncryption("blowfish-cbc");
  682        * ssh.connect(properties);
  683        * </pre></blockquote>
  684        *
  685        * <p>
  686        * Host key verification will be performed using
  687        * <code>ConsoleKnownHostsKeyVerification</code> and so this call is the
  688        * equivilent of calling:
  689        * </p>
  690        * <blockquote><pre>
  691        * ssh.connect("hostname", new ConsoleKnownHostsKeyVerification());
  692        * </pre></blockquote>
  693        *
  694        * <p>
  695        * If the key is not matched to any keys already in the
  696        * $HOME/.ssh/known_hosts file, the user will be prompted via the console
  697        * to confirm the identity of the remote server. The user will receive the
  698        * following prompt.
  699        * </p>
  700        * <code> The host shell.sourceforge.net is currently unknown to the system
  701        * The host key fingerprint is: 1024: 4c 68 3 d4 5c 58 a6 1d 9d 17 13 24
  702        * 14 48 ba 99 Do you want to allow this host key? [Yes|No|Always]:
  703        * </code>
  704        *
  705        * <p>
  706        * Selecting the "always" option will write the key to the known_hosts
  707        * file.
  708        * </p>
  709        *
  710        * @param properties The connection properties
  711        *
  712        * @exception IOException If an IO error occurs during the connect
  713        *            operation
  714        *
  715        * @since 0.2.0
  716        */
  717       public void connect(SshConnectionProperties properties)
  718           throws IOException {
  719           connect(properties, new ConsoleKnownHostsKeyVerification());
  720       }
  721   
  722       /**
  723        * <p>
  724        * Connect the client to the server with the specified properties.
  725        * </p>
  726        *
  727        * <p>
  728        * This call attempts to connect to using the connection properties
  729        * specified. When this method returns the connection has been
  730        * established, the server's identity been verified and the connection is
  731        * ready for user authentication. To use this method first create a
  732        * properties instance and set the required fields.
  733        * </p>
  734        * <blockquote><pre>
  735        * SshConnectionProperties properties = new
  736        *                             SshConnectionProperties();
  737        * properties.setHostname("hostname");
  738        * properties.setPort(22);             // Defaults to 22
  739        * // Set the prefered client->server encryption
  740        * ssh.setPrefCSEncryption("blowfish-cbc");
  741        * // Set the prefered server->client encrpytion
  742        * ssh.setPrefSCEncrpyion("3des-cbc");
  743        * ssh.connect(properties);
  744        * </pre></blockquote>
  745        *
  746        * <p>
  747        * Host key verification will be performed using the host key verification
  748        * instance provided:<br>
  749        * <blockquote><pre>
  750        * // Connect and consult $HOME/.ssh/known_hosts
  751        * ssh.connect("hostname", new ConsoleKnownHostsKeyVerification());
  752        * // Connect and allow any host
  753        * ssh.connect("hostname", new
  754        *                 IgnoreHostKeyVerification());
  755        * </pre></blockquote>
  756        * You can provide your own host key verification process by implementing the
  757        * <code>HostKeyVerification</code> interface.
  758        * </p>
  759        *
  760        * @param properties The connection properties
  761        * @param hostVerification The host key verification instance to consult
  762        *        for host  key validation
  763        *
  764        * @exception UnknownHostException If the host is unknown
  765        * @exception IOException If an IO error occurs during the connect
  766        *            operation
  767        *
  768        * @since 0.2.0
  769        */
  770       public void connect(SshConnectionProperties properties,
  771           HostKeyVerification hostVerification)
  772           throws UnknownHostException, IOException {
  773           TransportProvider provider = TransportProviderFactory.connectTransportProvider(properties /*, connectTimeout*/,
  774                   socketTimeout);
  775   
  776           // Start the transport protocol
  777           transport = new TransportProtocolClient(hostVerification);
  778           transport.addEventHandler(eventHandler);
  779           transport.startTransportProtocol(provider, properties);
  780   
  781           // Start the authentication protocol
  782           authentication = new AuthenticationProtocolClient();
  783           authentication.addEventListener(eventHandler);
  784           transport.requestService(authentication);
  785           connection = new ConnectionProtocol();
  786   
  787           if (useDefaultForwarding) {
  788               forwarding = new ForwardingClient(connection);
  789           }
  790       }
  791   
  792       /**
  793        * <p>
  794        * Sets the timeout value for the key exchange.
  795        * </p>
  796        *
  797        * <p>
  798        * When this time limit is reached the transport protocol will initiate a
  799        * key re-exchange. The default value is one hour with the minumin timeout
  800        * being 60 seconds.
  801        * </p>
  802        *
  803        * @param seconds The number of seconds beofre key re-exchange
  804        *
  805        * @exception IOException If the timeout value is invalid
  806        *
  807        * @since 0.2.0
  808        */
  809       public void setKexTimeout(long seconds) throws IOException {
  810           transport.setKexTimeout(seconds);
  811       }
  812   
  813       /**
  814        * <p>
  815        * Sets the key exchance transfer limit in kilobytes.
  816        * </p>
  817        *
  818        * <p>
  819        * Once this amount of data has been transfered the transport protocol will
  820        * initiate a key re-exchange. The default value is one gigabyte of data
  821        * with the mimimun value of 10 kilobytes.
  822        * </p>
  823        *
  824        * @param kilobytes The data transfer limit in kilobytes
  825        *
  826        * @exception IOException If the data transfer limit is invalid
  827        */
  828       public void setKexTransferLimit(long kilobytes) throws IOException {
  829           transport.setKexTransferLimit(kilobytes);
  830       }
  831   
  832       /**
  833        * <p>
  834        * Set's the send ignore flag to send random data packets.
  835        * </p>
  836        *
  837        * <p>
  838        * If this flag is set to true, then the transport protocol will send
  839        * additional SSH_MSG_IGNORE packets with random data.
  840        * </p>
  841        *
  842        * @param sendIgnore true if you want to turn on random packet data,
  843        *        otherwise false
  844        *
  845        * @since 0.2.0
  846        */
  847       public void setSendIgnore(boolean sendIgnore) {
  848           transport.setSendIgnore(sendIgnore);
  849       }
  850   
  851       /**
  852        * <p>
  853        * Turn the default forwarding manager on/off.
  854        * </p>
  855        *
  856        * <p>
  857        * If this flag is set to false before connection, the client will not
  858        * create a port forwarding manager. Use this to provide you own
  859        * forwarding implementation.
  860        * </p>
  861        *
  862        * @param useDefaultForwarding Set to false if you not wish to use the
  863        *        default forwarding manager.
  864        *
  865        * @since 0.2.0
  866        */
  867       public void setUseDefaultForwarding(boolean useDefaultForwarding) {
  868           this.useDefaultForwarding = useDefaultForwarding;
  869       }
  870   
  871       /**
  872        * <p>
  873        * Disconnect the client.
  874        * </p>
  875        *
  876        * @since 0.2.0
  877        */
  878       public void disconnect() {
  879           if (connection != null) {
  880               connection.stop();
  881           }
  882   
  883           if (transport != null) {
  884               transport.disconnect("Terminating connection");
  885           }
  886       }
  887   
  888       /**
  889        * <p>
  890        * Returns the number of bytes transmitted to the remote server.
  891        * </p>
  892        *
  893        * @return The number of bytes transmitted
  894        *
  895        * @since 0.2.0
  896        */
  897       public long getOutgoingByteCount() {
  898           return transport.getOutgoingByteCount();
  899       }
  900   
  901       /**
  902        * <p>
  903        * Returns the number of bytes received from the remote server.
  904        * </p>
  905        *
  906        * @return The number of bytes received
  907        *
  908        * @since 0.2.0
  909        */
  910       public long getIncomingByteCount() {
  911           return transport.getIncomingByteCount();
  912       }
  913   
  914       /**
  915        * <p>
  916        * Returns the number of active channels for this client.
  917        * </p>
  918        *
  919        * <p>
  920        * This is the total count of sessions, port forwarding, sftp, scp and
  921        * custom channels currently open.
  922        * </p>
  923        *
  924        * @return The number of active channels
  925        *
  926        * @since 0.2.0
  927        */
  928       public int getActiveChannelCount() {
  929           synchronized (activeChannels) {
  930               return activeChannels.size();
  931           }
  932       }
  933   
  934       /**
  935        * <p>
  936        * Returns the list of active channels.
  937        * </p>
  938        *
  939        * @return The list of active channels
  940        *
  941        * @since 0.2.0
  942        */
  943       public List getActiveChannels() {
  944           synchronized (activeChannels) {
  945               return (List) activeChannels.clone();
  946           }
  947       }
  948   
  949       /**
  950        * <p>
  951        * Returns true if there is an active session channel of the specified
  952        * type.
  953        * </p>
  954        *
  955        * <p>
  956        * When a session is created, it is assigned a default type. For instance,
  957        * when a session is created it as a type of "uninitialized"; however when
  958        * a shell is started on the session, the type is set to "shell". This
  959        * also occurs for commands where the type is set to the command which is
  960        * executed and subsystems where the type is set to the subsystem name.
  961        * This allows each session to be saved in the active session channel's
  962        * list and recalled later. It is also possible to set the session
  963        * channel's type using the setSessionType method of the
  964        * <code>SessionChannelClient</code> class.
  965        * </p>
  966        * <blockquote><pre>
  967        * if(ssh.hasActiveSession("shell")) {
  968        *      SessionChannelClient session =
  969        *           ssh.getActiveSession("shell");
  970        * }
  971        * </pre></blockquote>
  972        *
  973        * @param type The string specifying the channel type
  974        *
  975        * @return true if an active session channel exists, otherwise false
  976        *
  977        * @since 0.2.0
  978        */
  979       public boolean hasActiveSession(String type) {
  980           Iterator it = activeChannels.iterator();
  981           Object obj;
  982   
  983           while (it.hasNext()) {
  984               obj = it.next();
  985   
  986               if (obj instanceof SessionChannelClient) {
  987                   if (((SessionChannelClient) obj).getSessionType().equals(type)) {
  988                       return true;
  989                   }
  990               }
  991           }
  992   
  993           return false;
  994       }
  995   
  996       /**
  997        * <p>
  998        * Returns the active session channel of the given type.
  999        * </p>
 1000        *
 1001        * @param type The type fo session channel
 1002        *
 1003        * @return The session channel instance
 1004        *
 1005        * @exception IOException If the session type does not exist
 1006        *
 1007        * @since 0.2.0
 1008        */
 1009       public SessionChannelClient getActiveSession(String type)
 1010           throws IOException {
 1011           Iterator it = activeChannels.iterator();
 1012           Object obj;
 1013   
 1014           while (it.hasNext()) {
 1015               obj = it.next();
 1016   
 1017               if (obj instanceof SessionChannelClient) {
 1018                   if (((SessionChannelClient) obj).getSessionType().equals(type)) {
 1019                       return (SessionChannelClient) obj;
 1020                   }
 1021               }
 1022           }
 1023   
 1024           throw new IOException("There are no active " + type + " sessions");
 1025       }
 1026   
 1027       /**
 1028        * Determine whether the channel supplied is an active channel
 1029        *
 1030        * @param channel
 1031        *
 1032        * @return
 1033        */
 1034       public boolean isActiveChannel(Channel channel) {
 1035           return activeChannels.contains(channel);
 1036       }
 1037   
 1038       /**
 1039        * <p>
 1040        * Open's a session channel on the remote server.
 1041        * </p>
 1042        *
 1043        * <p>
 1044        * A session channel may be used to start the user's shell, execute a
 1045        * command or start a subsystem such as SFTP.
 1046        * </p>
 1047        *
 1048        * @return An new session channel
 1049        *
 1050        * @exception IOException If authentication has not been completed, the
 1051        *            server refuses to open the channel or a general IO error
 1052        *            occurs
 1053        *
 1054        * @see com.sshtools.j2ssh.session.SessionChannelClient
 1055        * @since 0.2.0
 1056        */
 1057       public SessionChannelClient openSessionChannel() throws IOException {
 1058           return openSessionChannel(null);
 1059       }
 1060   
 1061       /**
 1062        *
 1063        * <p>
 1064        * Open's a session channel on the remote server.
 1065        * </p>
 1066        *
 1067        * <p>
 1068        * A session channel may be used to start the user's shell, execute a
 1069        * command or start a subsystem such as SFTP.
 1070        * </p>
 1071        *
 1072        * @param eventListener an event listner interface to add to the channel
 1073        *
 1074        * @return
 1075        *
 1076        * @throws IOException
 1077        * @throws SshException
 1078        */
 1079       public SessionChannelClient openSessionChannel(
 1080           ChannelEventListener eventListener) throws IOException {
 1081           if (authenticationState != AuthenticationProtocolState.COMPLETE) {
 1082               throw new SshException("Authentication has not been completed!");
 1083           }
 1084   
 1085           SessionChannelClient session = new SessionChannelClient();
 1086           session.addEventListener(activeChannelListener);
 1087   
 1088           if (!connection.openChannel(session, eventListener)) {
 1089               throw new SshException("The server refused to open a session");
 1090           }
 1091   
 1092           return session;
 1093       }
 1094   
 1095       /**
 1096        * <p>
 1097        * Open an SFTP client for file transfer operations.
 1098        * </p>
 1099        * <blockquote><pre>
 1100        * SftpClient sftp = ssh.openSftpClient();
 1101        * sftp.cd("foo");
 1102        * sftp.put("somefile.txt");
 1103        * sftp.quit();
 1104        * </pre></blockquote>
 1105        *
 1106        * @return Returns an initialized SFTP client
 1107        *
 1108        * @exception IOException If an IO error occurs during the operation
 1109        *
 1110        * @see SftpClient
 1111        * @since 0.2.0
 1112        */
 1113       public SftpClient openSftpClient() throws IOException {
 1114           return openSftpClient(null);
 1115       }
 1116   
 1117       /**
 1118        * <p>
 1119        * Open an SFTP client for file transfer operations. Adds the supplied
 1120        * event listener to the underlying channel.
 1121        * </p>
 1122        *
 1123        * @param eventListener
 1124        *
 1125        * @return
 1126        *
 1127        * @throws IOException
 1128        */
 1129       public SftpClient openSftpClient(ChannelEventListener eventListener)
 1130           throws IOException {
 1131           SftpClient sftp = new SftpClient(this, eventListener);
 1132           activeSftpClients.add(sftp);
 1133   
 1134           return sftp;
 1135       }
 1136   
 1137       /**
 1138        * Determine if there are existing sftp clients open
 1139        *
 1140        * @return
 1141        */
 1142       public boolean hasActiveSftpClient() {
 1143           synchronized (activeSftpClients) {
 1144               return activeSftpClients.size() > 0;
 1145           }
 1146       }
 1147   
 1148       /**
 1149        * Get an active sftp client
 1150        *
 1151        * @return
 1152        *
 1153        * @throws IOException
 1154        * @throws SshException
 1155        */
 1156       public SftpClient getActiveSftpClient() throws IOException {
 1157           synchronized (activeSftpClients) {
 1158               if (activeSftpClients.size() > 0) {
 1159                   return (SftpClient) activeSftpClients.get(0);
 1160               } else {
 1161                   throw new SshException("There are no active SFTP clients");
 1162               }
 1163           }
 1164       }
 1165   
 1166       /**
 1167        * <p>
 1168        * Open an SCP client for file transfer operations where SFTP is not
 1169        * supported.
 1170        * </p>
 1171        *
 1172        * <p>
 1173        * Sets the local working directory to the user's home directory
 1174        * </p>
 1175        * <blockquote><pre>
 1176        * ScpClient scp = ssh.openScpClient();
 1177        * scp.put("somefile.txt");
 1178        * </pre></blockquote>
 1179        *
 1180        * @return An initialized SCP client
 1181        *
 1182        * @exception IOException If an IO error occurs during the operation
 1183        *
 1184        * @see ScpClient
 1185        * @since 0.2.0
 1186        */
 1187       public ScpClient openScpClient() throws IOException {
 1188           return new ScpClient(new File(System.getProperty("user.home")), this,
 1189               false, activeChannelListener);
 1190       }
 1191   
 1192       /**
 1193        * <p>
 1194        * Open an SCP client for file transfer operations where SFTP is not
 1195        * supported.
 1196        * </p>
 1197        *
 1198        * <p>
 1199        * This method sets a local current working directory.
 1200        * </p>
 1201        * <blockquote><pre>
 1202        * ScpClient scp = ssh.openScpClient("foo");
 1203        * scp.put("somefile.txt");
 1204        * </pre></blockquote>
 1205        *
 1206        * @param cwd The local directory as the base for all local files
 1207        *
 1208        * @return An intialized SCP client
 1209        *
 1210        * @exception IOException If an IO error occurs during the operation
 1211        *
 1212        * @see SftpClient
 1213        * @since 0.2.0
 1214        */
 1215       public ScpClient openScpClient(File cwd) throws IOException {
 1216           return new ScpClient(cwd, this, false, activeChannelListener);
 1217       }
 1218   
 1219       /**
 1220        * <p>
 1221        * Open's an Sftp channel.
 1222        * </p>
 1223        *
 1224        * <p>
 1225        * Use this sftp channel if you require a lower level api into the SFTP
 1226        * protocol.
 1227        * </p>
 1228        *
 1229        * @return an initialized sftp subsystem instance
 1230        *
 1231        * @throws IOException if an IO error occurs or the channel cannot be
 1232        *         opened
 1233        *
 1234        * @since 0.2.0
 1235        */
 1236       public SftpSubsystemClient openSftpChannel() throws IOException {
 1237           return openSftpChannel(null);
 1238       }
 1239   
 1240       /**
 1241        * Open an SftpSubsystemChannel. For advanced use only
 1242        *
 1243        * @param eventListener
 1244        *
 1245        * @return
 1246        *
 1247        * @throws IOException
 1248        * @throws SshException
 1249        */
 1250       public SftpSubsystemClient openSftpChannel(
 1251           ChannelEventListener eventListener) throws IOException {
 1252           SessionChannelClient session = openSessionChannel(eventListener);
 1253           SftpSubsystemClient sftp = new SftpSubsystemClient();
 1254   
 1255           if (!openChannel(sftp)) {
 1256               throw new SshException("The SFTP subsystem failed to start");
 1257           }
 1258   
 1259           // Initialize SFTP
 1260           if (!sftp.initialize()) {
 1261               throw new SshException(
 1262                   "The SFTP Subsystem could not be initialized");
 1263           }
 1264   
 1265           return sftp;
 1266       }
 1267   
 1268       /**
 1269        * <p>
 1270        * Open's a channel.
 1271        * </p>
 1272        *
 1273        * <p>
 1274        * Call this method to open a custom channel. This method is used by all
 1275        * other channel opening methods. For example the openSessionChannel
 1276        * method could be implemented as:<br>
 1277        * <blockquote><pre>
 1278        * SessionChannelClient session =
 1279        *                 new SessionChannelClient();
 1280        * if(ssh.openChannel(session)) {
 1281        *    // Channel is now open
 1282        * }
 1283        * </pre></blockquote>
 1284        * </p>
 1285        *
 1286        * @param channel
 1287        *
 1288        * @return true if the channel was opened, otherwise false
 1289        *
 1290        * @exception IOException if an IO error occurs
 1291        * @throws SshException
 1292        *
 1293        * @since 0.2.0
 1294        */
 1295       public boolean openChannel(Channel channel) throws IOException {
 1296           if (authenticationState != AuthenticationProtocolState.COMPLETE) {
 1297               throw new SshException("Authentication has not been completed!");
 1298           }
 1299   
 1300           // Open the channel providing our channel listener so we can track
 1301           return connection.openChannel(channel, activeChannelListener);
 1302       }
 1303   
 1304       /**
 1305        * <p>
 1306        * Instructs the underlying connection protocol to allow channels of the
 1307        * given type to be opened by the server.
 1308        * </p>
 1309        *
 1310        * <p>
 1311        * The client does not allow channels to be opened by default. Call this
 1312        * method to allow the server to open channels by providing a
 1313        * <code>ChannelFactory</code> implementation to create instances upon
 1314        * request.
 1315        * </p>
 1316        *
 1317        * @param channelName The channel type name
 1318        * @param cf The factory implementation that will create instances of the
 1319        *        channel when a channel open request is recieved.
 1320        *
 1321        * @exception IOException if an IO error occurs
 1322        *
 1323        * @since 0.2.0
 1324        */
 1325       public void allowChannelOpen(String channelName, ChannelFactory cf)
 1326           throws IOException {
 1327           connection.addChannelFactory(channelName, cf);
 1328       }
 1329   
 1330       /**
 1331        * <p>
 1332        * Stops the specified channel type from being opended.
 1333        * </p>
 1334        *
 1335        * @param channelName The channel type name
 1336        *
 1337        * @throws IOException if an IO error occurs
 1338        *
 1339        * @since 0.2.1
 1340        */
 1341       public void denyChannelOpen(String channelName) throws IOException {
 1342           connection.removeChannelFactory(channelName);
 1343       }
 1344   
 1345       /**
 1346        * <p>
 1347        * Send a global request to the server.
 1348        * </p>
 1349        *
 1350        * <p>
 1351        * The SSH specification provides a global request mechanism which is used
 1352        * for starting/stopping remote forwarding. This is a general mechanism
 1353        * which can be used for other purposes if the server supports the global
 1354        * requests.
 1355        * </p>
 1356        *
 1357        * @param requestName The name of the global request
 1358        * @param wantReply true if the server should send an explict reply
 1359        * @param requestData the global request data
 1360        *
 1361        * @return true if the global request succeeded or wantReply==false,
 1362        *         otherwise false
 1363        *
 1364        * @throws IOException if an IO error occurs
 1365        *
 1366        * @since 0.2.0
 1367        */
 1368       public byte[] sendGlobalRequest(String requestName, boolean wantReply,
 1369           byte[] requestData) throws IOException {
 1370           return connection.sendGlobalRequest(requestName, wantReply, requestData);
 1371       }
 1372   
 1373       /**
 1374        * <p>
 1375        * Implements the <code>ChannelEventListener</code> interface to provide
 1376        * real time tracking of active channels.
 1377        * </p>
 1378        */
 1379       class ActiveChannelEventListener extends ChannelEventAdapter {
 1380           /**
 1381            * <p>
 1382            * Adds the channel to the active channel list.
 1383            * </p>
 1384            *
 1385            * @param channel The channel being opened
 1386            */
 1387           public void onChannelOpen(Channel channel) {
 1388               synchronized (activeChannels) {
 1389                   activeChannels.add(channel);
 1390               }
 1391           }
 1392   
 1393           /**
 1394            * <p>
 1395            * Removes the closed channel from the clients active channels list.
 1396            * </p>
 1397            *
 1398            * @param channel The channle being closed
 1399            */
 1400           public void onChannelClose(Channel channel) {
 1401               synchronized (activeChannels) {
 1402                   activeChannels.remove(channel);
 1403               }
 1404           }
 1405       }
 1406   }

Save This Page
Home » j2ssh-0.2.9-src » com.sshtools.j2ssh » [javadoc | source]