--- trilead-ssh2-6401.orig/debian/libtrilead-ssh2-java.jlibs +++ trilead-ssh2-6401/debian/libtrilead-ssh2-java.jlibs @@ -0,0 +1 @@ +trilead-ssh2.jar --- trilead-ssh2-6401.orig/debian/compat +++ trilead-ssh2-6401/debian/compat @@ -0,0 +1 @@ +7 --- trilead-ssh2-6401.orig/debian/javabuild +++ trilead-ssh2-6401/debian/javabuild @@ -0,0 +1 @@ +trilead-ssh2.jar src --- trilead-ssh2-6401.orig/debian/libtrilead-ssh2-java.javadoc +++ trilead-ssh2-6401/debian/libtrilead-ssh2-java.javadoc @@ -0,0 +1 @@ +internal --- trilead-ssh2-6401.orig/debian/FAQ.html +++ trilead-ssh2-6401/debian/FAQ.html @@ -0,0 +1,389 @@ + +Trilead SSH-2 for Java FAQ + + + +

Trilead SSH-2 for Java FAQ

+ +

+This FAQ includes information regarding topics that were discussed in e-mails between developers and users +of the Trilead SSH-2 for Java library. +

+

+Trilead homepage: http://www.trilead.ethz.ch
+Last update of FAQ: oct-15-2007. +

+

+Please report bugs, typos and any kind of suggestions to support@trilead.com. +Also, please visit our support forum. +

+ +
+ +

Sections:

+ +

+

+

+ +

When I start program XYZ with putty (or openssh, ..., whatever) then everything +works. However, if I use "Session.execCommand", then XYZ behaves differently or does not work at all!

+ +

Short answer:

+ +

+The most often source of problems when executing a command with Session.execCommand() +are missing/wrong set environment variables on the remote machine. Make sure that the minimum needed +environment for XYZ is the same, independentely on how the shell is being invoked. +

+ +

+Example quickfix for bash users: +

+ +

+

    +
  1. Define all your settings in the file ~/.bashrc
  2. +
  3. Make sure that the file ~/.bash_profile only contains the line source +~/.bashrc.
  4. +
  5. Before executing Session.execCommand(), do NOT aquire any type of pseudo terminal in the +session. Be prepared to consume stdout and stderr data.
  6. +
+

+ +

+Note: If you really want to mimic the behavior of putty, then don't use Session.execCommand(), +instead aquire a pty (pseudo terminal) and then start a shell (use Session.requestPTY() and +Session.startShell()). You then have to communicate with the shell process at the other end +through stdin and stdout. However, you also have to implement terminal logic (e.g., escape sequence +handling (unless you use a "dumb" pty), "expect-send" logic (output parsing, shell prompt detection), etc.). +

+ +

Long answer:

+ +

+If you login by using putty, then putty will normally request a "xterm" pty and your assigned shell +(e.g., bash) will be started (a so called "interactive login shell"). In contrast, if you use +Session.execCommand() to start a command then (unless you ask for it) no pty will be aquired +and the command will be given to the shell as an argument (with the shell's "-c" option). +

+ +

+The way a shell is being invoked has an effect on the set of initialization files which will be read be the shell. +

+ +

+To demonstrate the difference, try the following (from the command line, e.g., with an OpenSSH client): +

+ +

+

    +
  1. Login interactively and print the environment with the "env" command:
     
    +[user@host ~] ssh 127.0.0.1
    +[user@host ~] env

     
    +
  2. +
  3. Let the ssh server execute the "env" command (equivalent to using Session.executeCommand()):
     
    +[user@host ~] ssh 127.0.0.1 "env" +
  4. +
+

+ +

+If you compare the two outputs, then you will (unless you have adjusted your shell's settings) +observe different environments. +

+ +

+If you are interested in the details, then please read the INVOCATION section in man page +for the bash shell. You may notice that the definitions of "interactive" and "non-interactive" +(and combinations with "login") are little bit tricky. +

+ +[TOP] + +

My program sometimes hangs when I only read output from stdout! +Or: can you explain me the story about the shared stdout/stderr window in the SSH-2 protocol? +Or: what is this "StreamGobbler" thing all about?

+ +

+In the SSH-2 low level protocol, each channel (e.g., session) has a receive window. When the remote +SSH daemon has filled up our receive window, it must wait until we have consumed the input and are ready to accept new data. +

+ +

+Unfortunately, the SSH-2 protocol defines a shared window for stderr and stdout. As a consequence, +if, for example, the remote process produces a lot of stderr data and you never consume it, then after +some time the local receive window will be full and the sender is blocked. If you then try to read() +from stdout, your call will be blocked: there is no stdout data (locally) available and the SSH daemon +cannot send you any, since the receive window is full (you would have to read some stderr data first +to "free" up space in the receive window). +

+ +

+Fortunately, Trilead SSH-2 uses a 30KB window - the above described scenario should be very rare. +

+ +

+Many other SSH-2 client implementations just blindly consume any remotely produced data into a buffer +which gets automatically extended - however, this can lead to another problem: in the extreme case +the remote side can overflow you with data (e.g., leading to out of memory errors). +

+ +

+What can you do about this? +

+ +

+

    +
  1. Bad: Do nothing - just work with stderr and stdout Inputstreams and hope that the 30KB +window is enough for your application.
  2. + +
  3. Better, recommended for most users: use two worker threads that consume remote stdout +and stderr in parallel. Since you probably are not in the mood to program such a thing, you can use +the StreamGobbler class supplied with Trilead SSH-2. The Streamgobbler is a special InputStream that +uses an internal worker thread to read and buffer internally all data produced by another InputStream. +It is very simple to use:
    InputStream stdout = new StreamGobbler(mysession.getStdout());
    +
    +InputStream stderr = new StreamGobbler(mysession.getStderr());
    +You then can access stdout and stderr in any order, in the background the StreamGobblers will +automatically consume all data from the remote side and store in an internal buffer.
  4. + +
  5. Advanced: you are paranoid and don't like programs that automatically extend buffers +without asking you. You then have to implement a state machine. The condition wait facility offered by +Session.waitForCondition() is exactly what you need: you can use it to wait until either stdout +or stderr data has arrived and can be consumed with the two InputStreams. You can either use the return value +of Session.waitForCondition() or check with InputStream.available() +(for stdout and stderr) which InputStream has data available (i.e., a read() call will not block). +Be careful when wrapping the InputStreams, also do not concurrently call read() on the InputStreams while calling +Session.waitForCondition() (unless you know what you are doing).
    Please have a look a the +SingleThreadStdoutStderr.java example.
  6. + +
  7. The lazy way: you don't mind if stdout and stderr data is being mixed into the same +stream. Just allocate a "dumb" pty and the server will hopefully not send you any data on the stderr +stream anymore. Note: by allocating a pty, the shell used to execute the command will probably +behave differently in terms of initialization (see also this question).
  8. +
+

+ + +[TOP] + +

Why are the session's Input- and OutputStreams not buffered?

+ +

+If you need it, then this library offers quite a raw type of access to the SSH-2 protocol stack. +Of course, many people don't need that kind of low level access. If you need buffered streams, +then you should the do the same thing as you would probably do with the streams of a TCP socket: +wrap them with instances of BufferedInputStream and BufferedOutputStream. In case you use +StreamGobblers for the InputStreams, then you don't need any additional wrappers, since the +StreamGobblers implement buffering already. +

+

+This code snippet will probably work well for most people: +

+

+ +

+InputStream stdout = new StreamGobbler(mysession.getStdout());
+InputStream stderr = new StreamGobbler(mysession.getStderr());
+OutputStream stdin = new BufferedOutputStream(mysession.getStdin(), 8192);
+
+ +

+ +[TOP] + +

Why can't I execute several commands in one single session?

+

+If you use Session.execCommand(), then you indeed can only execute only one command per session. +This is not a restriction of the library, but rather an enforcement by the underlying SSH-2 protocol +(a Session object models the underlying SSH-2 session). +

+

+There are several solutions: +

+

+

+

+ + +[TOP] + +

I cannot open more than 10 concurrent sessions (or SCP clients).

+

+You are probably using OpenSSH. By looking at their source code you will find out that there +is a hard-coded constant called MAX_SESSIONS in the session.c file which is set to "10" by default. +This is a per connection limit. Unfortunately, it is not a run-time tunable parameter. +However, this limit has no effect on the number of concurrent port forwardings. Please note: this information +is based on the OpenSSH 4.3 release. +

+

+Possible solutions: +

+

+

+Just for completeness: starting from release 210, the thrown exception may look as follows:
+ +

+java.io.IOException: Could not open channel (The server refused to open the channel (SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, 'open failed'))
+
+ +

+ +[TOP] + +

Password authentication fails, I get "Authentication method password +not supported by the server at this stage".

+ +

+Many default SSH server installations are configured to refuse the authentication type "password". +Often, they only accept "publickey" and "keyboard-interactive". You have different options: +

+ +

+

+

+ +

+In general it is a good idea to call either Connection.getRemainingAuthMethods() +or Connection.isAuthMethodAvailable() before using a certain authentication method. +

+ +

+Please note that most servers let you in after one successful authentication step. However, in rare cases +you may encounter servers that need several steps. I.e., if one of the Connection.authenticateWithXXX() +methods returns false and Connection.isAuthenticationPartialSuccess() returns +true, then further authentication is needed. For each step, to find out which authentication methods +may proceed, you can use either the Connection.getRemainingAuthMethods() +or the Connection.isAuthMethodAvailable() method. Again, please have a look into the +SwingShell.java example. +

+ +[TOP] + +

Why does public key authentication fail with my putty key?

+

+When using putty private keys (e.g., .ppk files) with public key authentication, you get a +"Publickey authentication failed" exception. The reason is that the library currently is not able to +directly handle private keys in the proprietary format used by putty. However, you can use the +"puttygen" tool (from the putty website) to convert your key to the desired format: load your key, +then go to the conversions menu and select "Save OpenSSH key" (which saves the key in openssl PEM format, +e.g., call it "private.pem"). +

+ +[TOP] + +

I am sending data to a remote file using the "cat" method, but not all data is being written.

+

+Please read carefully the answer to the following question. +

+ +[TOP] + + +

I want to pump data into a remote file, but the amount of data to be sent +is not known at the time the transfer starts.

+

+The SCP protocol communicates the amount of data to be sent at the start of the transfer, +so SCP remains out of consideration. Possible other solutions: +

+

+

+Be careful if you use the "cat" approach, as it may happen that not all your data will be +written. If you close the stdin stream and immediatelly close the session (or the whole connection) then +some SSH servers do not send the pending data to the process being executed ("cat" in this case). +You have to wait until "cat" has received the EOF and terminates before closing the session. However, +waiting for the termination may not always work, since SSH servers sometimes "forget" to send the exit code +of the remote process. The following code MAY work: +

+

+ +

+Session sess = conn.openSession();
+sess.execCommand("cat > test.txt");
+OutputStream stdin = sess.getStdin();
+
+... out.write(...) ... out.write(...) ...
+
+/* The following flush() is only needed if you wrap the  */
+/* stdin stream (e.g., with a BufferedOutputStream).     */
+out.flush();
+
+/* Now let's send EOF */
+out.close();
+
+/* Let's wait until cat has finished                     */
+sess.waitForCondition(ChannelCondition.EXIT_STATUS, 2000);
+/* Better: put the above statement into a while loop!    */
+/* In ANY CASE: read the Javadocs for waitForCondition() */
+
+/* Show exit status, if available (otherwise "null")     */
+System.out.println("ExitCode: " + sess.getExitStatus());
+/* Now its hopefully safe to close the session           */
+sess.close();
+
+ +

+

+(Just a thought for another solution: execute cat > test.txt && echo "FINISHED" +and wait until you get "FINISHED" on stdout... - try it on your own risk =) +

+ +[TOP] + +

Do you have an example for the usage of feature XYZ?

+

+Please have at look at the examples section in the distribution, especially at the SwingShell.java example. +

+ +[TOP] + + + + --- trilead-ssh2-6401.orig/debian/README.txt +++ trilead-ssh2-6401/debian/README.txt @@ -0,0 +1,24 @@ + +Trilead SSH-2 for Java - build 211 +================================== + +http://www.trilead.com + +Trilead SSH-2 for Java is a library which implements the SSH-2 protocol in pure Java +(minimum required JRE: 1.4.2). It allows one to connect to SSH servers from within +Java programs. It supports SSH sessions (remote command execution and shell access), +local and remote port forwarding, local stream forwarding, X11 forwarding, SCP and SFTP. +There are no dependencies on any JCE provider, as all crypto functionality is included. + +This distribution contains the source code, examples, javadoc and the FAQ. +It also includes a pre-compiled jar version of the library which is ready to use. + +- Please read the included LICENCE.txt +- Latest changes can be found in HISTORY.txt + +The latest version of the FAQ is available on the website. + +Please feel free to contact us. We welcome feedback of any kind! +Contact: support@trilead.com or go to the public forum at http://www.trilead.com + +Zurich, October 2007 --- trilead-ssh2-6401.orig/debian/rules +++ trilead-ssh2-6401/debian/rules @@ -0,0 +1,10 @@ +#!/usr/bin/make -f + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +export JAVA_HOME=/usr/lib/jvm/default-java + +%: + dh --with javahelper $@ + --- trilead-ssh2-6401.orig/debian/changelog +++ trilead-ssh2-6401/debian/changelog @@ -0,0 +1,28 @@ +trilead-ssh2 (6401-1) unstable; urgency=low + + * Switch upstream to svnkit + * New upstream release + * Version is svn revision from svnkit + * Import readme, faq and examples from old upstream + + -- Matthew Johnson Sat, 20 Feb 2010 13:52:54 +0000 + +trilead-ssh2 (211-3) unstable; urgency=low + + * Use javahelper rather than dh_javadoc + + -- Matthew Johnson Sat, 12 Dec 2009 10:33:09 +0000 + +trilead-ssh2 (211-2) unstable; urgency=low + + * Change to debhelper 7 + * Add build-dep on gjdoc because that's where dh_javadoc is now + * Change to section java + + -- Matthew Johnson Thu, 13 Aug 2009 00:12:29 +0100 + +trilead-ssh2 (211-1) unstable; urgency=low + + * Initial release. (Closes: #466694) + + -- Matthew Johnson Wed, 20 Feb 2008 11:41:06 +0000 --- trilead-ssh2-6401.orig/debian/libtrilead-ssh2-java.docs +++ trilead-ssh2-6401/debian/libtrilead-ssh2-java.docs @@ -0,0 +1,3 @@ +debian/README.txt +debian/examples +debian/FAQ.html --- trilead-ssh2-6401.orig/debian/control +++ trilead-ssh2-6401/debian/control @@ -0,0 +1,20 @@ +Source: trilead-ssh2 +Section: java +Priority: optional +Maintainer: Matthew Johnson +Build-Depends: debhelper (>> 7), javahelper (>=0.25) +Build-Depends-Indep: default-jdk +Standards-Version: 3.7.3 +Homepage: http://svn.svnkit.com/repos/svnkit/tags/1.3.2/contrib/trilead/ + +Package: libtrilead-ssh2-java +Architecture: all +Depends: ${java:Depends}, ${misc:Depends} +Description: Java SSH libarary + Trilead SSH for Java is a freely available open-source library which + implements the SSH-2 protocol in pure Java (tested on J2SE 1.4.2 and 5.0). It + allows one to connect to SSH servers from within Java programs. It supports + SSH sessions (remote command execution and shell access), local and remote + port forwarding, local stream forwarding, X11 forwarding, SCP and SFTP. There + are no dependencies on any JCE provider, as all crypto functionality is + included. --- trilead-ssh2-6401.orig/debian/copyright +++ trilead-ssh2-6401/debian/copyright @@ -0,0 +1,97 @@ +This package was Debianised by Matthew Johnson on Wed Feb 20 11:41:05 GMT 2008 + +This package was originally downloaded from http://www.trilead.com/Download/Trilead-SSH-2-Java/, +but now upstream is http://svn.svnkit.com/repos/svnkit/tags/1.3.2/contrib/trilead/ + +Copyright (c) 2007 Trilead AG (http://www.trilead.com) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +a.) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +b.) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +c.) Neither the name of Trilead nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +Trilead SSH-2 for Java includes code that was written by Dr. Christian Plattner +during his PhD at ETH Zurich. The license states the following: + +Copyright (c) 2005 - 2006 Swiss Federal Institute of Technology (ETH Zurich), + Department of Computer Science (http://www.inf.ethz.ch), + Christian Plattner. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +a.) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +b.) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +c.) Neither the name of ETH Zurich nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +The Java implementations of the AES, Blowfish and 3DES ciphers have been +taken (and slightly modified) from the cryptography package released by +"The Legion Of The Bouncy Castle". + +Their license states the following: + +Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle +(http://www.bouncycastle.org) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +The packaging is Copyright 2008 Matthew Johnson and is licenced +under the terms of the BSD licence. On Debian systems the BSD licence can be +found in /usr/share/common-licenses/BSD. --- trilead-ssh2-6401.orig/debian/examples/PortForwarding.java +++ trilead-ssh2-6401/debian/examples/PortForwarding.java @@ -0,0 +1,116 @@ +import java.io.File; +import java.io.IOException; + +import com.trilead.ssh2.Connection; +import com.trilead.ssh2.LocalPortForwarder; + +/** + * This example shows how to deal with port forwardings. + * + * @author Christian Plattner, plattner@trilead.com + * @version $Id: PortForwarding.java,v 1.2 2007/10/15 12:49:57 cplattne Exp $ + */ +public class PortForwarding +{ + public static void sleepSomeTime(long milliSeconds) + { + try + { + Thread.sleep(milliSeconds); + } + catch (InterruptedException e) + { + } + } + + public static void main(String[] args) + { + String hostname = "127.0.0.1"; + String username = "joe"; + + File keyfile = new File("~/.ssh/id_rsa"); // or "~/.ssh/id_dsa" + String keyfilePass = "joespass"; // will be ignored if not needed + + try + { + /* Create a connection instance */ + + Connection conn = new Connection(hostname); + + /* Now connect */ + + conn.connect(); + + /* Authenticate */ + + boolean isAuthenticated = conn.authenticateWithPublicKey(username, keyfile, keyfilePass); + + if (isAuthenticated == false) + throw new IOException("Authentication failed."); + + /* ===== OK, now let's establish some local port forwardings ===== */ + + /* Example Port Forwarding: -L 8080:www.icann.org:80 (OpenSSH notation) + * + * This works by allocating a socket to listen on 8080 on the local interface (127.0.0.1). + * Whenever a connection is made to this port (127.0.0.1:8080), the connection is forwarded + * over the secure channel, and a connection is made to www.icann.org:80 from the remote + * machine (i.e., the ssh server). + * + * (the above text is based partially on the OpenSSH man page) + */ + + /* You can create as many of them as you want */ + + LocalPortForwarder lpf1 = conn.createLocalPortForwarder(8080, "www.icann.org", 80); + + /* Now simply point your webbrowser to 127.0.0.1:8080 */ + /* (on the host where you execute this program) */ + + /* ===== OK, now let's establish some remote port forwardings ===== */ + + /* Example Port Forwarding: -R 127.0.0.1:8080:www.ripe.net:80 (OpenSSH notation) + * + * Specifies that the port 127.0.0.1:8080 on the remote server is to be forwarded to the + * given host and port on the local side. This works by allocating a socket to listen to port + * 8080 on the remote side (the ssh server), and whenever a connection is made to this port, the + * connection is forwarded over the secure channel, and a connection is made to + * www.ripe.net:80 by the Trilead SSH-2 library. + * + * (the above text is based partially on the OpenSSH man page) + */ + + /* You can create as many of them as you want */ + + conn.requestRemotePortForwarding("127.0.0.1", 8080, "www.ripe.net", 80); + + /* Now, on the ssh server, if you connect to 127.0.0.1:8080, then the connection is forwarded + * through the secure tunnel to the library, which in turn will forward the connection + * to www.ripe.net:80. */ + + /* Sleep a bit... (30 seconds) */ + sleepSomeTime(30000); + + /* Stop accepting remote connections that are being forwarded to www.ripe.net:80 */ + + conn.cancelRemotePortForwarding(8080); + + /* Sleep a bit... (20 seconds) */ + sleepSomeTime(20000); + + /* Stop accepting connections on 127.0.0.1:8080 that are being forwarded to www.icann.org:80 */ + + lpf1.close(); + + /* Close the connection */ + + conn.close(); + + } + catch (IOException e) + { + e.printStackTrace(System.err); + System.exit(2); + } + } +} --- trilead-ssh2-6401.orig/debian/examples/PublicKeyAuthentication.java +++ trilead-ssh2-6401/debian/examples/PublicKeyAuthentication.java @@ -0,0 +1,80 @@ +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import com.trilead.ssh2.Connection; +import com.trilead.ssh2.Session; +import com.trilead.ssh2.StreamGobbler; + +/** + * This example shows how to login using + * public key authentication. + * + * @author Christian Plattner, plattner@trilead.com + * @version $Id: PublicKeyAuthentication.java,v 1.2 2007/10/15 12:49:57 cplattne Exp $ + */ +public class PublicKeyAuthentication +{ + public static void main(String[] args) + { + String hostname = "127.0.0.1"; + String username = "joe"; + + File keyfile = new File("~/.ssh/id_rsa"); // or "~/.ssh/id_dsa" + String keyfilePass = "joespass"; // will be ignored if not needed + + try + { + /* Create a connection instance */ + + Connection conn = new Connection(hostname); + + /* Now connect */ + + conn.connect(); + + /* Authenticate */ + + boolean isAuthenticated = conn.authenticateWithPublicKey(username, keyfile, keyfilePass); + + if (isAuthenticated == false) + throw new IOException("Authentication failed."); + + /* Create a session */ + + Session sess = conn.openSession(); + + sess.execCommand("uname -a && date && uptime && who"); + + InputStream stdout = new StreamGobbler(sess.getStdout()); + + BufferedReader br = new BufferedReader(new InputStreamReader(stdout)); + + System.out.println("Here is some information about the remote host:"); + + while (true) + { + String line = br.readLine(); + if (line == null) + break; + System.out.println(line); + } + + /* Close this session */ + + sess.close(); + + /* Close the connection */ + + conn.close(); + + } + catch (IOException e) + { + e.printStackTrace(System.err); + System.exit(2); + } + } +} --- trilead-ssh2-6401.orig/debian/examples/SwingShell.java +++ trilead-ssh2-6401/debian/examples/SwingShell.java @@ -0,0 +1,786 @@ +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; + +import com.trilead.ssh2.Connection; +import com.trilead.ssh2.InteractiveCallback; +import com.trilead.ssh2.KnownHosts; +import com.trilead.ssh2.ServerHostKeyVerifier; +import com.trilead.ssh2.Session; + +/** + * This is a very primitive SSH-2 dumb terminal (Swing based). + *

+ * The purpose of this class is to demonstrate: + *

    + *
  • Verifying server hostkeys with an existing known_hosts file
  • + *
  • Displaying fingerprints of server hostkeys
  • + *
  • Adding a server hostkey to a known_hosts file (+hashing the hostname for security)
  • + *
  • Authentication with DSA, RSA, password and keyboard-interactive methods
  • + *
+ * + * @author Christian Plattner, plattner@trilead.com + * @version $Id: SwingShell.java,v 1.10 2007/10/15 12:49:57 cplattne Exp $ + * + */ +public class SwingShell +{ + /* + * NOTE: to get this feature to work, replace the "tilde" with your home directory, + * at least my JVM does not understand it. Need to check the specs. + */ + + static final String knownHostPath = "~/.ssh/known_hosts"; + static final String idDSAPath = "~/.ssh/id_dsa"; + static final String idRSAPath = "~/.ssh/id_rsa"; + + JFrame loginFrame = null; + JLabel hostLabel; + JLabel userLabel; + JTextField hostField; + JTextField userField; + JButton loginButton; + + KnownHosts database = new KnownHosts(); + + public SwingShell() + { + File knownHostFile = new File(knownHostPath); + if (knownHostFile.exists()) + { + try + { + database.addHostkeys(knownHostFile); + } + catch (IOException e) + { + } + } + } + + /** + * This dialog displays a number of text lines and a text field. + * The text field can either be plain text or a password field. + */ + class EnterSomethingDialog extends JDialog + { + private static final long serialVersionUID = 1L; + + JTextField answerField; + JPasswordField passwordField; + + final boolean isPassword; + + String answer; + + public EnterSomethingDialog(JFrame parent, String title, String content, boolean isPassword) + { + this(parent, title, new String[] { content }, isPassword); + } + + public EnterSomethingDialog(JFrame parent, String title, String[] content, boolean isPassword) + { + super(parent, title, true); + + this.isPassword = isPassword; + + JPanel pan = new JPanel(); + pan.setLayout(new BoxLayout(pan, BoxLayout.Y_AXIS)); + + for (int i = 0; i < content.length; i++) + { + if ((content[i] == null) || (content[i] == "")) + continue; + JLabel contentLabel = new JLabel(content[i]); + pan.add(contentLabel); + + } + + answerField = new JTextField(20); + passwordField = new JPasswordField(20); + + if (isPassword) + pan.add(passwordField); + else + pan.add(answerField); + + KeyAdapter kl = new KeyAdapter() + { + public void keyTyped(KeyEvent e) + { + if (e.getKeyChar() == '\n') + finish(); + } + }; + + answerField.addKeyListener(kl); + passwordField.addKeyListener(kl); + + getContentPane().add(BorderLayout.CENTER, pan); + + setResizable(false); + pack(); + setLocationRelativeTo(null); + } + + private void finish() + { + if (isPassword) + answer = new String(passwordField.getPassword()); + else + answer = answerField.getText(); + + dispose(); + } + } + + /** + * TerminalDialog is probably the worst terminal emulator ever written - implementing + * a real vt100 is left as an exercise to the reader, i.e., to you =) + * + */ + class TerminalDialog extends JDialog + { + private static final long serialVersionUID = 1L; + + JPanel botPanel; + JButton logoffButton; + JTextArea terminalArea; + + Session sess; + InputStream in; + OutputStream out; + + int x, y; + + /** + * This thread consumes output from the remote server and displays it in + * the terminal window. + * + */ + class RemoteConsumer extends Thread + { + char[][] lines = new char[y][]; + int posy = 0; + int posx = 0; + + private void addText(byte[] data, int len) + { + for (int i = 0; i < len; i++) + { + char c = (char) (data[i] & 0xff); + + if (c == 8) // Backspace, VERASE + { + if (posx < 0) + continue; + posx--; + continue; + } + + if (c == '\r') + { + posx = 0; + continue; + } + + if (c == '\n') + { + posy++; + if (posy >= y) + { + for (int k = 1; k < y; k++) + lines[k - 1] = lines[k]; + posy--; + lines[y - 1] = new char[x]; + for (int k = 0; k < x; k++) + lines[y - 1][k] = ' '; + } + continue; + } + + if (c < 32) + { + continue; + } + + if (posx >= x) + { + posx = 0; + posy++; + if (posy >= y) + { + posy--; + for (int k = 1; k < y; k++) + lines[k - 1] = lines[k]; + lines[y - 1] = new char[x]; + for (int k = 0; k < x; k++) + lines[y - 1][k] = ' '; + } + } + + if (lines[posy] == null) + { + lines[posy] = new char[x]; + for (int k = 0; k < x; k++) + lines[posy][k] = ' '; + } + + lines[posy][posx] = c; + posx++; + } + + StringBuffer sb = new StringBuffer(x * y); + + for (int i = 0; i < lines.length; i++) + { + if (i != 0) + sb.append('\n'); + + if (lines[i] != null) + { + sb.append(lines[i]); + } + + } + setContent(sb.toString()); + } + + public void run() + { + byte[] buff = new byte[8192]; + + try + { + while (true) + { + int len = in.read(buff); + if (len == -1) + return; + addText(buff, len); + } + } + catch (Exception e) + { + } + } + } + + public TerminalDialog(JFrame parent, String title, Session sess, int x, int y) throws IOException + { + super(parent, title, true); + + this.sess = sess; + + in = sess.getStdout(); + out = sess.getStdin(); + + this.x = x; + this.y = y; + + botPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + + logoffButton = new JButton("Logout"); + botPanel.add(logoffButton); + + logoffButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + /* Dispose the dialog, "setVisible(true)" method will return */ + dispose(); + } + }); + + Font f = new Font("Monospaced", Font.PLAIN, 16); + + terminalArea = new JTextArea(y, x); + terminalArea.setFont(f); + terminalArea.setBackground(Color.BLACK); + terminalArea.setForeground(Color.ORANGE); + /* This is a hack. We cannot disable the caret, + * since setting editable to false also changes + * the meaning of the TAB key - and I want to use it in bash. + * Again - this is a simple DEMO terminal =) + */ + terminalArea.setCaretColor(Color.BLACK); + + KeyAdapter kl = new KeyAdapter() + { + public void keyTyped(KeyEvent e) + { + int c = e.getKeyChar(); + + try + { + out.write(c); + } + catch (IOException e1) + { + } + e.consume(); + } + }; + + terminalArea.addKeyListener(kl); + + getContentPane().add(terminalArea, BorderLayout.CENTER); + getContentPane().add(botPanel, BorderLayout.PAGE_END); + + setResizable(false); + pack(); + setLocationRelativeTo(parent); + + new RemoteConsumer().start(); + } + + public void setContent(String lines) + { + // setText is thread safe, it does not have to be called from + // the Swing GUI thread. + terminalArea.setText(lines); + } + } + + /** + * This ServerHostKeyVerifier asks the user on how to proceed if a key cannot be found + * in the in-memory database. + * + */ + class AdvancedVerifier implements ServerHostKeyVerifier + { + public boolean verifyServerHostKey(String hostname, int port, String serverHostKeyAlgorithm, + byte[] serverHostKey) throws Exception + { + final String host = hostname; + final String algo = serverHostKeyAlgorithm; + + String message; + + /* Check database */ + + int result = database.verifyHostkey(hostname, serverHostKeyAlgorithm, serverHostKey); + + switch (result) + { + case KnownHosts.HOSTKEY_IS_OK: + return true; + + case KnownHosts.HOSTKEY_IS_NEW: + message = "Do you want to accept the hostkey (type " + algo + ") from " + host + " ?\n"; + break; + + case KnownHosts.HOSTKEY_HAS_CHANGED: + message = "WARNING! Hostkey for " + host + " has changed!\nAccept anyway?\n"; + break; + + default: + throw new IllegalStateException(); + } + + /* Include the fingerprints in the message */ + + String hexFingerprint = KnownHosts.createHexFingerprint(serverHostKeyAlgorithm, serverHostKey); + String bubblebabbleFingerprint = KnownHosts.createBubblebabbleFingerprint(serverHostKeyAlgorithm, + serverHostKey); + + message += "Hex Fingerprint: " + hexFingerprint + "\nBubblebabble Fingerprint: " + bubblebabbleFingerprint; + + /* Now ask the user */ + + int choice = JOptionPane.showConfirmDialog(loginFrame, message); + + if (choice == JOptionPane.YES_OPTION) + { + /* Be really paranoid. We use a hashed hostname entry */ + + String hashedHostname = KnownHosts.createHashedHostname(hostname); + + /* Add the hostkey to the in-memory database */ + + database.addHostkey(new String[] { hashedHostname }, serverHostKeyAlgorithm, serverHostKey); + + /* Also try to add the key to a known_host file */ + + try + { + KnownHosts.addHostkeyToFile(new File(knownHostPath), new String[] { hashedHostname }, + serverHostKeyAlgorithm, serverHostKey); + } + catch (IOException ignore) + { + } + + return true; + } + + if (choice == JOptionPane.CANCEL_OPTION) + { + throw new Exception("The user aborted the server hostkey verification."); + } + + return false; + } + } + + /** + * The logic that one has to implement if "keyboard-interactive" autentication shall be + * supported. + * + */ + class InteractiveLogic implements InteractiveCallback + { + int promptCount = 0; + String lastError; + + public InteractiveLogic(String lastError) + { + this.lastError = lastError; + } + + /* the callback may be invoked several times, depending on how many questions-sets the server sends */ + + public String[] replyToChallenge(String name, String instruction, int numPrompts, String[] prompt, + boolean[] echo) throws IOException + { + String[] result = new String[numPrompts]; + + for (int i = 0; i < numPrompts; i++) + { + /* Often, servers just send empty strings for "name" and "instruction" */ + + String[] content = new String[] { lastError, name, instruction, prompt[i] }; + + if (lastError != null) + { + /* show lastError only once */ + lastError = null; + } + + EnterSomethingDialog esd = new EnterSomethingDialog(loginFrame, "Keyboard Interactive Authentication", + content, !echo[i]); + + esd.setVisible(true); + + if (esd.answer == null) + throw new IOException("Login aborted by user"); + + result[i] = esd.answer; + promptCount++; + } + + return result; + } + + /* We maintain a prompt counter - this enables the detection of situations where the ssh + * server is signaling "authentication failed" even though it did not send a single prompt. + */ + + public int getPromptCount() + { + return promptCount; + } + } + + /** + * The SSH-2 connection is established in this thread. + * If we would not use a separate thread (e.g., put this code in + * the event handler of the "Login" button) then the GUI would not + * be responsive (missing window repaints if you move the window etc.) + */ + class ConnectionThread extends Thread + { + String hostname; + String username; + + public ConnectionThread(String hostname, String username) + { + this.hostname = hostname; + this.username = username; + } + + public void run() + { + Connection conn = new Connection(hostname); + + try + { + /* + * + * CONNECT AND VERIFY SERVER HOST KEY (with callback) + * + */ + + String[] hostkeyAlgos = database.getPreferredServerHostkeyAlgorithmOrder(hostname); + + if (hostkeyAlgos != null) + conn.setServerHostKeyAlgorithms(hostkeyAlgos); + + conn.connect(new AdvancedVerifier()); + + /* + * + * AUTHENTICATION PHASE + * + */ + + boolean enableKeyboardInteractive = true; + boolean enableDSA = true; + boolean enableRSA = true; + + String lastError = null; + + while (true) + { + if ((enableDSA || enableRSA) && conn.isAuthMethodAvailable(username, "publickey")) + { + if (enableDSA) + { + File key = new File(idDSAPath); + + if (key.exists()) + { + EnterSomethingDialog esd = new EnterSomethingDialog(loginFrame, "DSA Authentication", + new String[] { lastError, "Enter DSA private key password:" }, true); + esd.setVisible(true); + + boolean res = conn.authenticateWithPublicKey(username, key, esd.answer); + + if (res == true) + break; + + lastError = "DSA authentication failed."; + } + enableDSA = false; // do not try again + } + + if (enableRSA) + { + File key = new File(idRSAPath); + + if (key.exists()) + { + EnterSomethingDialog esd = new EnterSomethingDialog(loginFrame, "RSA Authentication", + new String[] { lastError, "Enter RSA private key password:" }, true); + esd.setVisible(true); + + boolean res = conn.authenticateWithPublicKey(username, key, esd.answer); + + if (res == true) + break; + + lastError = "RSA authentication failed."; + } + enableRSA = false; // do not try again + } + + continue; + } + + if (enableKeyboardInteractive && conn.isAuthMethodAvailable(username, "keyboard-interactive")) + { + InteractiveLogic il = new InteractiveLogic(lastError); + + boolean res = conn.authenticateWithKeyboardInteractive(username, il); + + if (res == true) + break; + + if (il.getPromptCount() == 0) + { + // aha. the server announced that it supports "keyboard-interactive", but when + // we asked for it, it just denied the request without sending us any prompt. + // That happens with some server versions/configurations. + // We just disable the "keyboard-interactive" method and notify the user. + + lastError = "Keyboard-interactive does not work."; + + enableKeyboardInteractive = false; // do not try this again + } + else + { + lastError = "Keyboard-interactive auth failed."; // try again, if possible + } + + continue; + } + + if (conn.isAuthMethodAvailable(username, "password")) + { + final EnterSomethingDialog esd = new EnterSomethingDialog(loginFrame, + "Password Authentication", + new String[] { lastError, "Enter password for " + username }, true); + + esd.setVisible(true); + + if (esd.answer == null) + throw new IOException("Login aborted by user"); + + boolean res = conn.authenticateWithPassword(username, esd.answer); + + if (res == true) + break; + + lastError = "Password authentication failed."; // try again, if possible + + continue; + } + + throw new IOException("No supported authentication methods available."); + } + + /* + * + * AUTHENTICATION OK. DO SOMETHING. + * + */ + + Session sess = conn.openSession(); + + int x_width = 90; + int y_width = 30; + + sess.requestPTY("dumb", x_width, y_width, 0, 0, null); + sess.startShell(); + + TerminalDialog td = new TerminalDialog(loginFrame, username + "@" + hostname, sess, x_width, y_width); + + /* The following call blocks until the dialog has been closed */ + + td.setVisible(true); + + } + catch (IOException e) + { + //e.printStackTrace(); + JOptionPane.showMessageDialog(loginFrame, "Exception: " + e.getMessage()); + } + + /* + * + * CLOSE THE CONNECTION. + * + */ + + conn.close(); + + /* + * + * CLOSE THE LOGIN FRAME - APPLICATION WILL BE EXITED (no more frames) + * + */ + + Runnable r = new Runnable() + { + public void run() + { + loginFrame.dispose(); + } + }; + + SwingUtilities.invokeLater(r); + } + } + + void loginPressed() + { + String hostname = hostField.getText().trim(); + String username = userField.getText().trim(); + + if ((hostname.length() == 0) || (username.length() == 0)) + { + JOptionPane.showMessageDialog(loginFrame, "Please fill out both fields!"); + return; + } + + loginButton.setEnabled(false); + hostField.setEnabled(false); + userField.setEnabled(false); + + ConnectionThread ct = new ConnectionThread(hostname, username); + + ct.start(); + } + + void showGUI() + { + loginFrame = new JFrame("Trilead SSH-2 for Java SwingShell"); + + hostLabel = new JLabel("Hostname:"); + userLabel = new JLabel("Username:"); + + hostField = new JTextField("", 20); + userField = new JTextField("", 10); + + loginButton = new JButton("Login"); + + loginButton.addActionListener(new ActionListener() + { + public void actionPerformed(java.awt.event.ActionEvent e) + { + loginPressed(); + } + }); + + JPanel loginPanel = new JPanel(); + + loginPanel.add(hostLabel); + loginPanel.add(hostField); + loginPanel.add(userLabel); + loginPanel.add(userField); + loginPanel.add(loginButton); + + loginFrame.getRootPane().setDefaultButton(loginButton); + + loginFrame.getContentPane().add(loginPanel, BorderLayout.PAGE_START); + //loginFrame.getContentPane().add(textArea, BorderLayout.CENTER); + + loginFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + loginFrame.pack(); + loginFrame.setResizable(false); + loginFrame.setLocationRelativeTo(null); + loginFrame.setVisible(true); + } + + void startGUI() + { + Runnable r = new Runnable() + { + public void run() + { + showGUI(); + } + }; + + SwingUtilities.invokeLater(r); + + } + + public static void main(String[] args) + { + SwingShell client = new SwingShell(); + client.startGUI(); + } +} --- trilead-ssh2-6401.orig/debian/examples/Basic.java +++ trilead-ssh2-6401/debian/examples/Basic.java @@ -0,0 +1,91 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import com.trilead.ssh2.Connection; +import com.trilead.ssh2.Session; +import com.trilead.ssh2.StreamGobbler; + + +/** + * This is a very basic example that shows + * how one can login to a machine and execute a command. + * + * @author Christian Plattner, plattner@trilead.com + * @version $Id: Basic.java,v 1.4 2007/10/15 12:49:57 cplattne Exp $ + */ +public class Basic +{ + public static void main(String[] args) + { + String hostname = "127.0.0.1"; + String username = "joe"; + String password = "joespass"; + + try + { + /* Create a connection instance */ + + Connection conn = new Connection(hostname); + + /* Now connect */ + + conn.connect(); + + /* Authenticate. + * If you get an IOException saying something like + * "Authentication method password not supported by the server at this stage." + * then please check the FAQ. + */ + + boolean isAuthenticated = conn.authenticateWithPassword(username, password); + + if (isAuthenticated == false) + throw new IOException("Authentication failed."); + + /* Create a session */ + + Session sess = conn.openSession(); + + sess.execCommand("uname -a && date && uptime && who"); + + System.out.println("Here is some information about the remote host:"); + + /* + * This basic example does not handle stderr, which is sometimes dangerous + * (please read the FAQ). + */ + + InputStream stdout = new StreamGobbler(sess.getStdout()); + + BufferedReader br = new BufferedReader(new InputStreamReader(stdout)); + + while (true) + { + String line = br.readLine(); + if (line == null) + break; + System.out.println(line); + } + + /* Show exit status, if available (otherwise "null") */ + + System.out.println("ExitCode: " + sess.getExitStatus()); + + /* Close this session */ + + sess.close(); + + /* Close the connection */ + + conn.close(); + + } + catch (IOException e) + { + e.printStackTrace(System.err); + System.exit(2); + } + } +} --- trilead-ssh2-6401.orig/debian/examples/UsingKnownHosts.java +++ trilead-ssh2-6401/debian/examples/UsingKnownHosts.java @@ -0,0 +1,86 @@ +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import com.trilead.ssh2.Connection; +import com.trilead.ssh2.KnownHosts; +import com.trilead.ssh2.Session; +import com.trilead.ssh2.StreamGobbler; + +/** + * This example shows how to deal with "known_hosts" files. + * + * @author Christian Plattner, plattner@trilead.com + * @version $Id: UsingKnownHosts.java,v 1.2 2007/10/15 12:49:57 cplattne Exp $ + */ +public class UsingKnownHosts +{ + static KnownHosts database = new KnownHosts(); + + public static void main(String[] args) throws IOException + { + String hostname = "somehost"; + String username = "joe"; + String password = "joespass"; + + File knownHosts = new File("~/.ssh/known_hosts"); + + try + { + /* Load known_hosts file into in-memory database */ + + if (knownHosts.exists()) + database.addHostkeys(knownHosts); + + /* Create a connection instance */ + + Connection conn = new Connection(hostname); + + /* Now connect and use the SimpleVerifier */ + + conn.connect(new SimpleVerifier(database)); + + /* Authenticate */ + + boolean isAuthenticated = conn.authenticateWithPassword(username, password); + + if (isAuthenticated == false) + throw new IOException("Authentication failed."); + + /* Create a session */ + + Session sess = conn.openSession(); + + sess.execCommand("uname -a && date && uptime && who"); + + InputStream stdout = new StreamGobbler(sess.getStdout()); + BufferedReader br = new BufferedReader(new InputStreamReader(stdout)); + + System.out.println("Here is some information about the remote host:"); + + while (true) + { + String line = br.readLine(); + if (line == null) + break; + System.out.println(line); + } + + /* Close this session */ + + sess.close(); + + /* Close the connection */ + + conn.close(); + + } + catch (IOException e) + { + e.printStackTrace(System.err); + System.exit(2); + } + } +} --- trilead-ssh2-6401.orig/debian/examples/BasicWithHTTPProxy.java +++ trilead-ssh2-6401/debian/examples/BasicWithHTTPProxy.java @@ -0,0 +1,102 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import com.trilead.ssh2.Connection; +import com.trilead.ssh2.HTTPProxyData; +import com.trilead.ssh2.Session; +import com.trilead.ssh2.StreamGobbler; + +/** + * This is a very basic example that shows + * how one can login to a machine (via a HTTP proxy) + * and execute a command. + * + * @author Christian Plattner, plattner@trilead.com + * @version $Id: BasicWithHTTPProxy.java,v 1.3 2007/10/15 12:49:57 cplattne Exp $ + */ +public class BasicWithHTTPProxy +{ + public static void main(String[] args) + { + String hostname = "my-ssh-server"; + String username = "joe"; + String password = "joespass"; + + String proxyHost = "192.168.1.1"; + int proxyPort = 3128; // default port used by squid + + try + { + /* Create a connection instance */ + + Connection conn = new Connection(hostname); + + /* We want to connect through a HTTP proxy */ + + conn.setProxyData(new HTTPProxyData(proxyHost, proxyPort)); + + // if the proxy requires basic authentication: + // conn.setProxyData(new HTTPProxyData(proxyHost, proxyPort, "username", "secret")); + + /* Now connect (through the proxy) */ + + conn.connect(); + + /* Authenticate. + * If you get an IOException saying something like + * "Authentication method password not supported by the server at this stage." + * then please check the FAQ. + */ + + boolean isAuthenticated = conn.authenticateWithPassword(username, password); + + if (isAuthenticated == false) + throw new IOException("Authentication failed."); + + /* Create a session */ + + Session sess = conn.openSession(); + + sess.execCommand("uname -a && date && uptime && who"); + + System.out.println("Here is some information about the remote host:"); + + /* + * This basic example does not handle stderr, which is sometimes dangerous + * (please read the FAQ). + */ + + InputStream stdout = new StreamGobbler(sess.getStdout()); + + BufferedReader br = new BufferedReader(new InputStreamReader(stdout)); + + while (true) + { + String line = br.readLine(); + if (line == null) + break; + System.out.println(line); + } + + /* Show exit status, if available (otherwise "null") */ + + System.out.println("ExitCode: " + sess.getExitStatus()); + + /* Close this session */ + + sess.close(); + + /* Close the connection */ + + conn.close(); + + } + catch (IOException e) + { + e.printStackTrace(System.err); + System.exit(2); + } + } +} --- trilead-ssh2-6401.orig/debian/examples/SingleThreadStdoutStderr.java +++ trilead-ssh2-6401/debian/examples/SingleThreadStdoutStderr.java @@ -0,0 +1,142 @@ +import java.io.IOException; +import java.io.InputStream; + +import com.trilead.ssh2.ChannelCondition; +import com.trilead.ssh2.Connection; +import com.trilead.ssh2.Session; + +/** + * This example shows how to use the Session.waitForCondition + * method to implement a state machine approach for + * proper stdout/stderr output handling in a single thread. + * + * @author Christian Plattner, plattner@trilead.com + * @version $Id: SingleThreadStdoutStderr.java,v 1.6 2007/10/15 12:49:57 cplattne Exp $ + */ +public class SingleThreadStdoutStderr +{ + public static void main(String[] args) + { + String hostname = "127.0.0.1"; + String username = "joe"; + String password = "joespass"; + + try + { + /* Create a connection instance */ + + Connection conn = new Connection(hostname); + + /* Now connect */ + + conn.connect(); + + /* Authenticate */ + + boolean isAuthenticated = conn.authenticateWithPassword(username, password); + + if (isAuthenticated == false) + throw new IOException("Authentication failed."); + + /* Create a session */ + + Session sess = conn.openSession(); + + sess.execCommand("echo \"Huge amounts of text on STDOUT\"; echo \"Huge amounts of text on STDERR\" >&2"); + + /* + * Advanced: + * The following is a demo on how one can read from stdout and + * stderr without having to use two parallel worker threads (i.e., + * we don't use the Streamgobblers here) and at the same time not + * risking a deadlock (due to a filled SSH2 channel window, caused + * by the stream which you are currently NOT reading from =). + */ + + /* Don't wrap these streams and don't let other threads work on + * these streams while you work with Session.waitForCondition()!!! + */ + + InputStream stdout = sess.getStdout(); + InputStream stderr = sess.getStderr(); + + byte[] buffer = new byte[8192]; + + while (true) + { + if ((stdout.available() == 0) && (stderr.available() == 0)) + { + /* Even though currently there is no data available, it may be that new data arrives + * and the session's underlying channel is closed before we call waitForCondition(). + * This means that EOF and STDOUT_DATA (or STDERR_DATA, or both) may + * be set together. + */ + + int conditions = sess.waitForCondition(ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA + | ChannelCondition.EOF, 2000); + + /* Wait no longer than 2 seconds (= 2000 milliseconds) */ + + if ((conditions & ChannelCondition.TIMEOUT) != 0) + { + /* A timeout occured. */ + throw new IOException("Timeout while waiting for data from peer."); + } + + /* Here we do not need to check separately for CLOSED, since CLOSED implies EOF */ + + if ((conditions & ChannelCondition.EOF) != 0) + { + /* The remote side won't send us further data... */ + + if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) == 0) + { + /* ... and we have consumed all data in the local arrival window. */ + break; + } + } + + /* OK, either STDOUT_DATA or STDERR_DATA (or both) is set. */ + + // You can be paranoid and check that the library is not going nuts: + // if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) == 0) + // throw new IllegalStateException("Unexpected condition result (" + conditions + ")"); + } + + /* If you below replace "while" with "if", then the way the output appears on the local + * stdout and stder streams is more "balanced". Addtionally reducing the buffer size + * will also improve the interleaving, but performance will slightly suffer. + * OKOK, that all matters only if you get HUGE amounts of stdout and stderr data =) + */ + + while (stdout.available() > 0) + { + int len = stdout.read(buffer); + if (len > 0) // this check is somewhat paranoid + System.out.write(buffer, 0, len); + } + + while (stderr.available() > 0) + { + int len = stderr.read(buffer); + if (len > 0) // this check is somewhat paranoid + System.err.write(buffer, 0, len); + } + } + + /* Close this session */ + + sess.close(); + + /* Close the connection */ + + conn.close(); + + } + catch (IOException e) + { + e.printStackTrace(System.err); + System.exit(2); + } + } +} --- trilead-ssh2-6401.orig/debian/examples/StdoutAndStderr.java +++ trilead-ssh2-6401/debian/examples/StdoutAndStderr.java @@ -0,0 +1,93 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import com.trilead.ssh2.Connection; +import com.trilead.ssh2.Session; +import com.trilead.ssh2.StreamGobbler; + +/** + * This example shows how to consume stdout/stderr output + * using two StreamGobblers. This is simpler to program + * than the state machine approach (see SingleThreadStdoutStderr.java), + * but you cannot control the amount of memory that is + * consumed by your application (i.e., in case the other + * side sends you lots of data). + * + * @author Christian Plattner, plattner@trilead.com + * @version $Id: StdoutAndStderr.java,v 1.2 2007/10/15 12:49:57 cplattne Exp $ + */ +public class StdoutAndStderr +{ + public static void main(String[] args) + { + String hostname = "127.0.0.1"; + String username = "joe"; + String password = "joespass"; + + try + { + /* Create a connection instance */ + + Connection conn = new Connection(hostname); + + /* Now connect */ + + conn.connect(); + + /* Authenticate */ + + boolean isAuthenticated = conn.authenticateWithPassword(username, password); + + if (isAuthenticated == false) + throw new IOException("Authentication failed."); + + /* Create a session */ + + Session sess = conn.openSession(); + + sess.execCommand("echo \"Text on STDOUT\"; echo \"Text on STDERR\" >&2"); + + InputStream stdout = new StreamGobbler(sess.getStdout()); + InputStream stderr = new StreamGobbler(sess.getStderr()); + + BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(stdout)); + BufferedReader stderrReader = new BufferedReader(new InputStreamReader(stderr)); + + System.out.println("Here is the output from stdout:"); + + while (true) + { + String line = stdoutReader.readLine(); + if (line == null) + break; + System.out.println(line); + } + + System.out.println("Here is the output from stderr:"); + + while (true) + { + String line = stderrReader.readLine(); + if (line == null) + break; + System.out.println(line); + } + + /* Close this session */ + + sess.close(); + + /* Close the connection */ + + conn.close(); + + } + catch (IOException e) + { + e.printStackTrace(System.err); + System.exit(2); + } + } +} --- trilead-ssh2-6401.orig/debian/examples/SimpleVerifier.java +++ trilead-ssh2-6401/debian/examples/SimpleVerifier.java @@ -0,0 +1,55 @@ +import com.trilead.ssh2.KnownHosts; +import com.trilead.ssh2.ServerHostKeyVerifier; + +/** + * This example hostkey verifier is used by the + * UsingKnownHosts.java example. + * + * @author Christian Plattner, plattner@trilead.com + * @version $Id: SimpleVerifier.java,v 1.4 2007/10/15 12:49:57 cplattne Exp $ + */ +class SimpleVerifier implements ServerHostKeyVerifier +{ + KnownHosts database; + + public SimpleVerifier(KnownHosts database) + { + if (database == null) + throw new IllegalArgumentException(); + + this.database = database; + } + + public boolean verifyServerHostKey(String hostname, int port, String serverHostKeyAlgorithm, byte[] serverHostKey) + throws Exception + { + int result = database.verifyHostkey(hostname, serverHostKeyAlgorithm, serverHostKey); + + switch (result) + { + case KnownHosts.HOSTKEY_IS_OK: + + return true; // We are happy + + case KnownHosts.HOSTKEY_IS_NEW: + + // Unknown host? Blindly accept the key and put it into the cache. + // Well, you definitely can do better (e.g., ask the user). + + // The following call will ONLY put the key into the memory cache! + // To save it in a known hosts file, also call "KnownHosts.addHostkeyToFile(...)" + database.addHostkey(new String[] { hostname }, serverHostKeyAlgorithm, serverHostKey); + + return true; + + case KnownHosts.HOSTKEY_HAS_CHANGED: + + // Close the connection if the hostkey has changed. + // Better: ask user and add new key to database. + return false; + + default: + throw new IllegalStateException(); + } + } +} \ No newline at end of file