Compare commits

...

66 Commits

Author SHA1 Message Date
Shikhar Bhushan
f2abc4b397 [maven-release-plugin] prepare release v0.2.3 2010-06-13 14:28:27 +01:00
Shikhar Bhushan
fe0d42fc97 [maven-release-plugin] prepare for next development iteration 2010-06-13 13:58:59 +01:00
Shikhar Bhushan
19e4670c24 [maven-release-plugin] prepare release v0.2.2 2010-06-13 13:58:51 +01:00
Shikhar Bhushan
fbd6e00720 [maven-release-plugin] prepare for next development iteration 2010-06-13 00:11:53 +01:00
Shikhar Bhushan
f69cdb1505 [maven-release-plugin] prepare release v0.2.1 2010-06-13 00:11:42 +01:00
Shikhar Bhushan
135b1c819b dep update 2010-06-13 00:09:11 +01:00
Shikhar Bhushan
9c51b862cd can't throw exception, shit fails on windows 2010-06-12 23:10:47 +01:00
Shikhar Bhushan
a6353cbb2d 2010-05-31 16:24:17 -07:00
Shikhar Bhushan
f11055a726 java 1.6 is a dep 2010-06-01 00:20:38 +01:00
Shikhar Bhushan
da98153ab6 [maven-release-plugin] prepare for next development iteration 2010-05-31 00:02:39 +01:00
Shikhar Bhushan
70d4dbd88a [maven-release-plugin] prepare release sshj-0.2.0 2010-05-31 00:02:32 +01:00
Shikhar Bhushan
b2a74935d4 added maven assembly plugin config. for packaging examples 2010-05-31 00:01:18 +01:00
Shikhar Bhushan
f3c072fb06 keybased auth cleanups 2010-05-24 23:51:24 +01:00
Shikhar Bhushan
738b317dcf more versatile password response provider 2010-05-24 23:20:49 +01:00
Shikhar Bhushan
d87e0c2da2 logging statement 2010-05-24 22:55:28 +01:00
Shikhar Bhushan
72ff74c99d some authentication refactoring esp. keyboard-interactive auth 2010-05-24 22:48:20 +01:00
Shikhar Bhushan
5cb4f1be43 ArrayList makes more sense 2010-05-24 22:34:16 +01:00
Shikhar Bhushan
693379feb4 method rename 2010-05-24 22:09:32 +01:00
Shikhar Bhushan
98529f733c vestigal constructor 2010-05-24 22:08:53 +01:00
Shikhar Bhushan
582f789db4 make findbugs happi 2010-05-24 00:22:28 +01:00
Shikhar Bhushan
c16ccc2644 missing annotation 2010-05-23 23:53:21 +01:00
Shikhar Bhushan
5c3ba2282c * further fixed up getting & setting of file attributes
* added a TransferListener for monitoring file transfer
2010-05-23 23:51:06 +01:00
Shikhar Bhushan
e765536fa1 deque recommended over stack 2010-05-23 23:47:22 +01:00
Shikhar Bhushan
068fbdfc55 adding a ProgressListener interface, tho it still needs to be called from somewhere... 2010-05-22 03:50:26 +01:00
Shikhar Bhushan
f4f9249b35 make kbd-interactive a fallback option for SSHClient#authPassword() 2010-05-22 03:25:35 +01:00
Shikhar Bhushan
252fcebeac keyboard-interactive auth! 2010-05-22 03:06:40 +01:00
Shikhar Bhushan
a7ccccaacf minor logging change 2010-05-22 01:25:18 +01:00
Shikhar Bhushan
2420027a58 ... now this should be solid 2010-05-22 01:12:42 +01:00
Shikhar Bhushan
b54a4abfce bugfix related to setting attributes on sftp upload 2010-05-22 00:57:50 +01:00
Shikhar Bhushan
0c28deab88 minor 2010-05-22 00:34:47 +01:00
Shikhar Bhushan
12c79dc2b2 who am i kidding 2010-05-22 00:16:16 +01:00
Shikhar Bhushan
6ef3dacc81 minor 2010-05-21 23:49:20 +01:00
Shikhar Bhushan
700998d064 provide last access time via DefaultModeGetter 2010-05-21 23:48:34 +01:00
Shikhar Bhushan
dea6e3db91 eliminate maven warning regarding encoding of resources 2010-05-21 23:43:43 +01:00
Shikhar Bhushan
dc5ff451f0 manual backmerge from netling/ 2010-05-21 22:56:19 +01:00
Shikhar Bhushan
ca521500ed this gonna be 0.2 2010-05-21 21:41:18 +01:00
Shikhar Bhushan
ca07e0d25a logback instead of log4j 2010-05-21 21:40:59 +01:00
Shikhar Bhushan
f372ae782a iffy bug with directory listing 2010-05-21 21:39:06 +01:00
Shikhar Bhushan
460a730879 mutable state, protect with synchronized 2010-03-26 01:16:51 +01:00
Shikhar Bhushan
25a18c6fd7 make pathHelper final + renamed exists() -> statExistence() 2010-03-26 00:49:07 +01:00
Shikhar Bhushan
53389e6989 docfix 2010-03-25 23:40:20 +01:00
Shikhar Bhushan
2f1b2c4e77 mkdirs() and exists() 2010-03-25 23:38:25 +01:00
Shikhar Bhushan
09b93ec11a make path util classes public 2010-03-25 23:30:46 +01:00
Shikhar Bhushan
63b321e8d1 kex exception handling cleanups 2010-03-21 17:24:46 +01:00
Shikhar Bhushan
49e3d4ec27 why copyOf(), when its a new byte[] anyway 2010-03-21 14:46:35 +01:00
Shikhar Bhushan
8e9a773e92 keyexchange refactoring and cleanups 2010-03-21 14:45:46 +01:00
Shikhar Bhushan
f30afe50f4 endoffile newline 2010-03-21 14:44:41 +01:00
Shikhar Bhushan
4af8fab434 license compliance, should be including SSHD's notice 2010-03-21 14:32:07 +01:00
Shikhar Bhushan
436e5774a8 license 2010-03-21 01:39:44 +01:00
Shikhar Bhushan
7a2850d760 fhm 2010-03-21 01:31:41 +01:00
Shikhar Bhushan
53d8d548cf fhm 2010-03-21 01:29:07 +01:00
Shikhar Bhushan
89d03361ba SFTPPacket constructor takes care of putting the type byte 2010-03-21 01:28:45 +01:00
Shikhar Bhushan
db4185608d redundant exception declarations 2010-03-21 01:25:24 +01:00
Shikhar Bhushan
71b6cee424 make final 2010-03-21 01:23:12 +01:00
Shikhar Bhushan
bdb1fe73e3 slashes 2010-03-21 01:21:27 +01:00
Shikhar Bhushan
e327e2e8ad no need to copy 2010-03-21 01:18:29 +01:00
Shikhar Bhushan
66fd4a4823 futher simplify equals() 2010-03-21 00:30:18 +01:00
Shikhar Bhushan
8be0e1c8b0 minor 2010-03-17 23:55:47 +01:00
Shikhar Bhushan
37de8faf9b was fine before: shouldn't be specifying type here, it's pretty clear from whether we're doing mkdir() or open() that its a file or directory 2010-03-17 23:50:18 +01:00
Shikhar Bhushan
9e92463ff2 compression cleanups 2010-03-17 23:41:22 +01:00
Shikhar Bhushan
9cbb75084a minor cleanup 2010-03-17 23:40:47 +01:00
Shikhar Bhushan
54ee1a6917 simplify equals() method 2010-03-17 23:37:24 +01:00
Shikhar Bhushan
dd1be04a61 strange line wrap 2010-03-17 23:36:56 +01:00
Shikhar Bhushan
839021cd2b redundant 2010-03-14 05:16:11 -07:00
Shikhar Bhushan
e6f2ed3035 fix potential bug / negative bytes 2010-03-12 21:22:55 +01:00
Shikhar Bhushan
6581772c18 [maven-release-plugin] prepare for next development iteration 2010-03-12 17:47:28 +01:00
127 changed files with 1437 additions and 795 deletions

57
NOTICE
View File

@@ -6,3 +6,60 @@ The Apache Software Foundation (http://www.apache.org/):
- Apache MINA SSHD
- Apache Commons-Net
// Apache Mina SSHD notice
=========================================================================
== NOTICE file for use with the Apache License, Version 2.0, ==
== in this case for the SSHD distribution. ==
=========================================================================
This product contains software developped by JCraft,Inc. and subject to
the following license:
Copyright (c) 2002,2003,2004,2005,2006,2007,2008 Atsuhiko Yamanaka, JCraft,Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. 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.
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
--------------------------------------------------------------------------------
Copyright (c) 2000 - 2006 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.

View File

@@ -37,7 +37,7 @@ If you need something that is not implemented, it shouldn't be too hard to add (
Dependencies
-------------
slf4j_ is required. bouncycastle_ is highly recommended and required for using some of the crypto algorithms.
Java 6+. slf4j_ is required. bouncycastle_ is highly recommended and required for using some of the crypto algorithms.
jzlib_ is required for using zlib compression.

116
pom.xml
View File

@@ -6,7 +6,7 @@
<groupId>net.schmizz</groupId>
<artifactId>sshj</artifactId>
<packaging>jar</packaging>
<version>0.1.1</version>
<version>0.2.3</version>
<name>sshj</name>
<description>SSHv2 library for Java</description>
@@ -41,61 +41,39 @@
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15</artifactId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.45</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jzlib</artifactId>
<version>1.0.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>0.3.0</version>
<version>0.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.11</version>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>0.9.20</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.20</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>oro</groupId>
<artifactId>oro</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
@@ -109,6 +87,10 @@
</developer>
</developers>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
@@ -118,8 +100,8 @@
<excludes>
<exclude>examples/*.java</exclude>
</excludes>
<source>1.5</source>
<target>1.5</target>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
@@ -127,6 +109,24 @@
<artifactId>maven-release-plugin</artifactId>
<version>2.0</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
<descriptors>
<descriptor>src/assemble/examples.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
@@ -172,11 +172,11 @@
<profiles>
<profile>
<id>dev</id>
<id>full-deps</id>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15</artifactId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.45</version>
</dependency>
<dependency>
@@ -185,36 +185,14 @@
<version>1.0.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.11</version>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>0.9.20</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>oro</groupId>
<artifactId>oro</artifactId>
</exclusion>
</exclusions>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.20</version>
</dependency>
</dependencies>
</profile>

15
src/assemble/examples.xml Normal file
View File

@@ -0,0 +1,15 @@
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>examples</id>
<formats>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>src/main/java/examples</directory>
<includes/>
<outputDirectory>examples</outputDirectory>
</fileSet>
</fileSets>
</assembly>

View File

@@ -23,10 +23,6 @@ import java.io.IOException;
/** This examples demonstrates how a remote command can be executed. */
public class Exec {
// static {
// BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%d [%-15.15t] %-5p %-30.30c{1} - %m%n")));
// }
public static void main(String... args)
throws IOException {
SSHClient ssh = new SSHClient();
@@ -37,9 +33,8 @@ public class Exec {
ssh.authPublickey(System.getProperty("user.name"));
Command cmd = ssh.startSession().exec("ping google.com -n 1");
Command cmd = ssh.startSession().exec("ping -c 1 google.com");
// Pipe.pipe(cmd.getInputStream(), System.out, cmd.getLocalMaxPacketSize(), false);
System.out.print(cmd.getOutputAsString());
System.out.println("\n** exit status: " + cmd.getExitStatus());

View File

@@ -26,11 +26,6 @@ import java.net.InetSocketAddress;
*/
public class LocalPF {
// static
// {
// BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%d [%-15.15t] %-5p %-30.30c{1} - %m%n")));
// }
public static void main(String... args)
throws IOException {
SSHClient ssh = new SSHClient();
@@ -46,7 +41,6 @@ public class LocalPF {
* _We_ listen on localhost:8080 and forward all connections on to server, which then forwards it to
* google.com:80
*/
ssh.newLocalPortForwarder(new InetSocketAddress("localhost", 8080), "google.com", 80)
.listen();

View File

@@ -28,10 +28,6 @@ import java.net.InetSocketAddress;
*/
public class RemotePF {
// static {
// BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%d [%-15.15t] %-5p %-30.30c{1} - %m%n")));
// }
public static void main(String... args)
throws IOException {
SSHClient client = new SSHClient();

View File

@@ -28,10 +28,6 @@ import java.io.IOException;
/** A very rudimentary psuedo-terminal based on console I/O. */
class RudimentaryPTY {
// static {
// BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%d [%-15.15t] %-5p %-30.30c{1} - %m%n")));
// }
public static void main(String... args)
throws IOException {
@@ -70,7 +66,6 @@ class RudimentaryPTY {
if (shell != null)
shell.close();
ssh.disconnect();
}
}

View File

@@ -22,20 +22,17 @@ import java.io.IOException;
/** This example demonstrates downloading of a file over SCP from the SSH server. */
public class SCPDownload {
// static {
// BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%d [%-15.15t] %-5p %-30.30c{1} - %m%n")));
// }
public static void main(String[] args)
throws IOException {
SSHClient ssh = new SSHClient();
// ssh.useCompression(); // Can lead to significant speedup
// ssh.useCompression(); // Can lead to significant speedup (needs JZlib in classpath)
ssh.loadKnownHosts();
ssh.connect("localhost");
try {
ssh.authPublickey(System.getProperty("user.name"));
ssh.newSCPFileTransfer()
.download("well", "/tmp/");
final String src = "test_file";
final String target = "/tmp/";
ssh.newSCPFileTransfer().download(src, target);
} finally {
ssh.disconnect();
}

View File

@@ -17,15 +17,12 @@ package examples;
import net.schmizz.sshj.SSHClient;
import java.io.File;
import java.io.IOException;
/** This example demonstrates uploading of a file over SCP to the SSH server. */
public class SCPUpload {
// static {
// BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%d [%-15.15t] %-5p %-30.30c{1} - %m%n")));
// }
public static void main(String[] args)
throws IOException, ClassNotFoundException {
SSHClient ssh = new SSHClient();
@@ -35,10 +32,12 @@ public class SCPUpload {
ssh.authPublickey(System.getProperty("user.name"));
// Present here to demo algorithm renegotiation - could have just put this before connect()
// Make sure JZlib is in classpath for this to work
ssh.useCompression();
ssh.newSCPFileTransfer()
.upload("/Users/shikhar/well", "/tmp/");
final String src = System.getProperty("user.home") + File.separator + "test_file";
final String target = "/tmp/";
ssh.newSCPFileTransfer().upload(src, target);
} finally {
ssh.disconnect();
}

View File

@@ -22,10 +22,6 @@ import java.io.IOException;
/** This example demonstrates downloading of a file over SFTP from the SSH server. */
public class SFTPDownload {
// static {
// BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%d [%-15.15t] %-5p %-30.30c{1} - %m%n")));
// }
public static void main(String[] args)
throws IOException {
SSHClient ssh = new SSHClient();
@@ -33,7 +29,9 @@ public class SFTPDownload {
ssh.connect("localhost");
try {
ssh.authPublickey(System.getProperty("user.name"));
ssh.newSFTPClient().get("well", "/tmp/");
final String src = "test_file";
final String target = "/tmp/";
ssh.newSFTPClient().get(src, target);
} finally {
ssh.disconnect();
}

View File

@@ -17,16 +17,12 @@ package examples;
import net.schmizz.sshj.SSHClient;
import java.io.File;
import java.io.IOException;
/** This example demonstrates uploading of a file over SFTP to the SSH server. */
public class SFTPUpload {
// static
// {
// BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%d [%-15.15t] %-5p %-30.30c{1} - %m%n")));
// }
public static void main(String[] args)
throws IOException {
SSHClient ssh = new SSHClient();
@@ -34,7 +30,9 @@ public class SFTPUpload {
ssh.connect("localhost");
try {
ssh.authPublickey(System.getProperty("user.name"));
ssh.newSFTPClient().put("/Users/shikhar/well", "/tmp/");
final String src = System.getProperty("user.home") + File.separator + "test_file";
final String target = "/tmp/";
ssh.newSFTPClient().put(src, target);
} finally {
ssh.disconnect();
}

View File

@@ -27,10 +27,6 @@ import java.net.InetSocketAddress;
/** This example demonstrates how forwarding X11 connections from a remote host can be accomplished. */
public class X11 {
// static {
// BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%d [%-15.15t] %-5p %-30.30c{1} - %m%n")));
// }
public static void main(String... args)
throws IOException, InterruptedException {
SSHClient ssh = new SSHClient();
@@ -59,7 +55,7 @@ public class X11 {
*/
sess.reqX11Forwarding("MIT-MAGIC-COOKIE-1", "b0956167c9ad8f34c8a2788878307dc9", 0);
Command cmd = sess.exec("mate");
Command cmd = sess.exec("/usr/X11/bin/xcalc");
new StreamCopier("stdout", cmd.getInputStream(), System.out).start();
new StreamCopier("stderr", cmd.getErrorStream(), System.err).start();

View File

@@ -44,29 +44,35 @@ public abstract class AbstractService
timeout = trans.getTimeout();
}
@Override
public String getName() {
return name;
}
@Override
public void handle(Message msg, SSHPacket buf)
throws SSHException {
trans.sendUnimplemented();
}
@Override
public void notifyError(SSHException error) {
log.debug("Was notified of {}", error.toString());
}
@Override
public void notifyUnimplemented(long seqNum)
throws SSHException {
throw new SSHException(DisconnectReason.PROTOCOL_ERROR, "Unexpected: SSH_MSG_UNIMPLEMENTED");
}
@Override
public void notifyDisconnect()
throws SSHException {
log.debug("Was notified of disconnect");
}
@Override
public void request()
throws TransportException {
final Service active = trans.getService();

View File

@@ -142,5 +142,5 @@ public interface Config {
* @param version software version info
*/
void setVersion(String version);
}

View File

@@ -62,34 +62,42 @@ public class ConfigImpl
private List<Factory.Named<Signature>> signatureFactories;
private List<Factory.Named<FileKeyProvider>> fileKeyProviderFactories;
@Override
public List<Factory.Named<Cipher>> getCipherFactories() {
return cipherFactories;
}
@Override
public List<Factory.Named<Compression>> getCompressionFactories() {
return compressionFactories;
}
@Override
public List<Factory.Named<FileKeyProvider>> getFileKeyProviderFactories() {
return fileKeyProviderFactories;
}
@Override
public List<Factory.Named<KeyExchange>> getKeyExchangeFactories() {
return kexFactories;
}
@Override
public List<Factory.Named<MAC>> getMACFactories() {
return macFactories;
}
@Override
public Factory<Random> getRandomFactory() {
return randomFactory;
}
@Override
public List<Factory.Named<Signature>> getSignatureFactories() {
return signatureFactories;
}
@Override
public String getVersion() {
return version;
}
@@ -98,6 +106,7 @@ public class ConfigImpl
setCipherFactories(Arrays.asList(cipherFactories));
}
@Override
public void setCipherFactories(List<Factory.Named<Cipher>> cipherFactories) {
this.cipherFactories = cipherFactories;
}
@@ -106,6 +115,7 @@ public class ConfigImpl
setCompressionFactories(Arrays.asList(compressionFactories));
}
@Override
public void setCompressionFactories(List<Factory.Named<Compression>> compressionFactories) {
this.compressionFactories = compressionFactories;
}
@@ -114,6 +124,7 @@ public class ConfigImpl
setFileKeyProviderFactories(Arrays.asList(fileKeyProviderFactories));
}
@Override
public void setFileKeyProviderFactories(List<Factory.Named<FileKeyProvider>> fileKeyProviderFactories) {
this.fileKeyProviderFactories = fileKeyProviderFactories;
}
@@ -122,6 +133,7 @@ public class ConfigImpl
setKeyExchangeFactories(Arrays.asList(kexFactories));
}
@Override
public void setKeyExchangeFactories(List<Factory.Named<KeyExchange>> kexFactories) {
this.kexFactories = kexFactories;
}
@@ -130,10 +142,12 @@ public class ConfigImpl
setMACFactories(Arrays.asList(macFactories));
}
@Override
public void setMACFactories(List<Factory.Named<MAC>> macFactories) {
this.macFactories = macFactories;
}
@Override
public void setRandomFactory(Factory<Random> randomFactory) {
this.randomFactory = randomFactory;
}
@@ -142,10 +156,12 @@ public class ConfigImpl
setSignatureFactories(Arrays.asList(signatureFactories));
}
@Override
public void setSignatureFactories(List<Factory.Named<Signature>> signatureFactories) {
this.signatureFactories = signatureFactories;
}
@Override
public void setVersion(String version) {
this.version = version;
}

View File

@@ -49,11 +49,14 @@ import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider;
import net.schmizz.sshj.userauth.keyprovider.KeyPairWrapper;
import net.schmizz.sshj.userauth.keyprovider.KeyProvider;
import net.schmizz.sshj.userauth.keyprovider.KeyProviderUtil;
import net.schmizz.sshj.userauth.method.AuthKeyboardInteractive;
import net.schmizz.sshj.userauth.method.AuthMethod;
import net.schmizz.sshj.userauth.method.AuthPassword;
import net.schmizz.sshj.userauth.method.AuthPublickey;
import net.schmizz.sshj.userauth.method.PasswordResponseProvider;
import net.schmizz.sshj.userauth.password.PasswordFinder;
import net.schmizz.sshj.userauth.password.PasswordUtils;
import net.schmizz.sshj.userauth.password.Resource;
import net.schmizz.sshj.xfer.scp.SCPFileTransfer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -87,7 +90,6 @@ import java.util.List;
* <p/>
* <em>A simple example:</em>
* <p/>
* <p/>
* <pre>
* client = new SSHClient();
* client.initUserKnownHosts();
@@ -165,6 +167,7 @@ public class SSHClient
*/
public void addHostKeyVerifier(final String host, final int port, final String fingerprint) {
addHostKeyVerifier(new HostKeyVerifier() {
@Override
public boolean verify(String h, int p, PublicKey k) {
return host.equals(h) && port == p && SecurityUtils.getFingerprint(k).equals(fingerprint);
}
@@ -202,36 +205,8 @@ public class SSHClient
}
/**
* Authenticate {@code username} using the {@code "password"} authentication method. The {@code password} array is
* blanked out after use.
*
* @param username user to authenticate
* @param password the password to use for authentication
*
* @throws UserAuthException in case of authentication failure
* @throws TransportException if there was a transport-layer error
*/
public void authPassword(String username, char[] password)
throws UserAuthException, TransportException {
authPassword(username, PasswordUtils.createOneOff(password));
}
/**
* Authenticate {@code username} using the {@code "password"} authentication method.
*
* @param username user to authenticate
* @param pfinder the {@link PasswordFinder} to use for authentication
*
* @throws UserAuthException in case of authentication failure
* @throws TransportException if there was a transport-layer error
*/
public void authPassword(String username, PasswordFinder pfinder)
throws UserAuthException, TransportException {
auth(username, new AuthPassword(pfinder));
}
/**
* Authenticate {@code username} using the {@code "password"} authentication method.
* Authenticate {@code username} using the {@code "password"} authentication method and as a fallback basic
* challenge-response authentication.
*
* @param username user to authenticate
* @param password the password to use for authentication
@@ -244,6 +219,52 @@ public class SSHClient
authPassword(username, password.toCharArray());
}
/**
* Authenticate {@code username} using the {@code "password"} authentication method and as a fallback basic
* challenge-response authentication.. The {@code password} array is blanked out after use.
*
* @param username user to authenticate
* @param password the password to use for authentication
*
* @throws UserAuthException in case of authentication failure
* @throws TransportException if there was a transport-layer error
*/
public void authPassword(final String username, final char[] password)
throws UserAuthException, TransportException {
try {
authPassword(username, new PasswordFinder() {
@Override
public char[] reqPassword(Resource<?> resource) {
return password.clone();
}
@Override
public boolean shouldRetry(Resource<?> resource) {
return false;
}
});
} finally {
PasswordUtils.blankOut(password);
}
}
/**
* Authenticate {@code username} using the {@code "password"} authentication method and as a fallback basic
* challenge-response authentication.
*
* @param username user to authenticate
* @param pfinder the {@link PasswordFinder} to use for authentication
*
* @throws UserAuthException in case of authentication failure
* @throws TransportException if there was a transport-layer error
*/
public void authPassword(String username, PasswordFinder pfinder)
throws UserAuthException, TransportException {
auth(username, new AuthPassword(pfinder), new AuthKeyboardInteractive(new PasswordResponseProvider(pfinder)));
}
/**
* Authenticate {@code username} using the {@code "publickey"} authentication method, with keys from some common
* locations on the file system. This method relies on {@code ~/.ssh/id_rsa} and {@code ~/.ssh/id_dsa}.
@@ -587,6 +608,7 @@ public class SSHClient
doKex();
}
@Override
public Session startSession()
throws ConnectionException, TransportException {
assert isConnected() && isAuthenticated();
@@ -607,7 +629,7 @@ public class SSHClient
* @throws TransportException if an error occurs during renegotiation
*/
public void useCompression()
throws ClassNotFoundException, TransportException {
throws TransportException {
trans.getConfig().setCompressionFactories(Arrays.asList(
new DelayedZlibCompression.Factory(),
new ZlibCompression.Factory(),

View File

@@ -120,8 +120,6 @@ abstract class SocketClient {
output.close();
output = null;
}
input = null;
output = null;
}
public boolean isConnected() {

View File

@@ -38,12 +38,7 @@ package net.schmizz.sshj.common;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Arrays;
public class Buffer<T extends Buffer<T>> {
@@ -445,71 +440,34 @@ public class Buffer<T extends Buffer<T>> {
* This is useful when a plaintext password needs to be sent. If {@code passwd} is {@code null}, an empty string is
* written.
*
* @param passwd (null-ok) the password as a character array
* @param str (null-ok) the password as a character array
*
* @return this
*/
@SuppressWarnings("unchecked")
public T putPassword(char[] passwd) {
if (passwd == null)
public T putSensitiveString(char[] str) {
if (str == null)
return putString("");
putInt(passwd.length);
ensureCapacity(passwd.length);
for (char c : passwd)
putInt(str.length);
ensureCapacity(str.length);
for (char c : str)
data[wpos++] = (byte) c;
Arrays.fill(passwd, ' ');
Arrays.fill(str, ' ');
return (T) this;
}
public PublicKey readPublicKey() {
try {
switch (KeyType.fromString(readString())) {
case RSA: {
BigInteger e = readMPInt();
BigInteger n = readMPInt();
KeyFactory keyFactory = SecurityUtils.getKeyFactory("RSA");
return keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
}
case DSA: {
BigInteger p = readMPInt();
BigInteger q = readMPInt();
BigInteger g = readMPInt();
BigInteger y = readMPInt();
KeyFactory keyFactory = SecurityUtils.getKeyFactory("DSA");
return keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
}
default:
assert false;
}
final String type = readString();
return KeyType.fromString(type).readPubKeyFromBuffer(type, this);
} catch (GeneralSecurityException e) {
throw new SSHRuntimeException(e);
}
return null;
}
@SuppressWarnings("unchecked")
public T putPublicKey(PublicKey key) {
final KeyType type = KeyType.fromKey(key);
switch (type) {
case RSA: {
final RSAPublicKey rsaKey = (RSAPublicKey) key;
putString(type.toString()) // ssh-rsa
.putMPInt(rsaKey.getPublicExponent()) // e
.putMPInt(rsaKey.getModulus()); // n
break;
}
case DSA: {
final DSAPublicKey dsaKey = (DSAPublicKey) key;
putString(type.toString()) // ssh-dss
.putMPInt(dsaKey.getParams().getP()) // p
.putMPInt(dsaKey.getParams().getQ()) // q
.putMPInt(dsaKey.getParams().getG()) // g
.putMPInt(dsaKey.getY()); // y
break;
}
default:
throw new SSHRuntimeException("Don't know how to encode key: " + key);
}
KeyType.fromKey(key).putPubKeyIntoBuffer(key, this);
return (T) this;
}

View File

@@ -15,47 +15,117 @@
*/
package net.schmizz.sshj.common;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.RSAPublicKeySpec;
/** Type of key e.g. rsa, dsa */
public enum KeyType {
/** SSH identifier for RSA keys */
RSA("ssh-rsa", new KeyChecker() {
public boolean isMyType(Key key) {
RSA("ssh-rsa") {
@Override
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
throws GeneralSecurityException {
final BigInteger e = buf.readMPInt();
final BigInteger n = buf.readMPInt();
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("RSA");
return keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
}
@Override
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
final RSAPublicKey rsaKey = (RSAPublicKey) pk;
buf.putString(sType)
.putMPInt(rsaKey.getPublicExponent()) // e
.putMPInt(rsaKey.getModulus()); // n
}
@Override
protected boolean isMyType(Key key) {
return (key instanceof RSAPublicKey || key instanceof RSAPrivateKey);
}
}),
},
/** SSH identifier for DSA keys */
DSA("ssh-dss", new KeyChecker() {
public boolean isMyType(Key key) {
DSA("ssh-dss") {
@Override
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
throws GeneralSecurityException {
final BigInteger p = buf.readMPInt();
final BigInteger q = buf.readMPInt();
final BigInteger g = buf.readMPInt();
final BigInteger y = buf.readMPInt();
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("DSA");
return keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
}
@Override
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
final DSAPublicKey dsaKey = (DSAPublicKey) pk;
buf.putString(sType)
.putMPInt(dsaKey.getParams().getP()) // p
.putMPInt(dsaKey.getParams().getQ()) // q
.putMPInt(dsaKey.getParams().getG()) // g
.putMPInt(dsaKey.getY()); // y
}
@Override
protected boolean isMyType(Key key) {
return (key instanceof DSAPublicKey || key instanceof DSAPrivateKey);
}
}),
},
/** Unrecognized */
UNKNOWN("unknown", null);
UNKNOWN("unknown") {
private static interface KeyChecker {
boolean isMyType(Key key);
}
@Override
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
throws GeneralSecurityException {
throw new UnsupportedOperationException("Don't know how to decode key:" + type);
}
private final String sType;
private final KeyChecker checker;
@Override
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
throw new UnsupportedOperationException("Don't know how to encode key: " + pk);
}
private KeyType(String type, KeyChecker checker) {
@Override
protected boolean isMyType(Key key) {
return false;
}
};
protected final String sType;
private KeyType(String type) {
this.sType = type;
this.checker = checker;
}
public abstract PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
throws GeneralSecurityException;
public abstract void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf);
protected abstract boolean isMyType(Key key);
public static KeyType fromKey(Key key) {
for (KeyType kt : values())
if (kt.checker != null && kt.checker.isMyType((key)))
if (kt.isMyType((key)))
return kt;
return UNKNOWN;
}

View File

@@ -48,6 +48,7 @@ public class SSHException
public static final ExceptionChainer<SSHException> chainer = new ExceptionChainer<SSHException>() {
@Override
public SSHException chain(Throwable t) {
if (t instanceof SSHException)
return (SSHException) t;

View File

@@ -22,7 +22,6 @@ import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
public class StreamCopier
extends Thread {
@@ -34,18 +33,23 @@ public class StreamCopier
}
public static ErrorCallback closeOnErrorCallback(final Closeable... toClose) {
final Closeable[] closeables = Arrays.copyOf(toClose, toClose.length);
return new ErrorCallback() {
@Override
public void onError(IOException ioe) {
IOUtils.closeQuietly(closeables);
IOUtils.closeQuietly(toClose);
}
};
}
public static long copy(InputStream in, OutputStream out, int bufSize, boolean keepFlushing)
public interface Listener {
void reportProgress(long transferred);
}
public static long copy(InputStream in, OutputStream out, int bufSize, boolean keepFlushing, Listener listener)
throws IOException {
long count = 0;
final boolean reportProgress = listener != null;
final long startTime = System.currentTimeMillis();
final byte[] buf = new byte[bufSize];
@@ -55,6 +59,8 @@ public class StreamCopier
count += read;
if (keepFlushing)
out.flush();
if (reportProgress)
listener.reportProgress(count);
}
if (!keepFlushing)
out.flush();
@@ -66,6 +72,11 @@ public class StreamCopier
return count;
}
public static long copy(InputStream in, OutputStream out, int bufSize, boolean keepFlushing)
throws IOException {
return copy(in, out, bufSize, keepFlushing, null);
}
public static String copyStreamToString(InputStream stream)
throws IOException {
final StringBuilder sb = new StringBuilder();
@@ -84,6 +95,7 @@ public class StreamCopier
private boolean keepFlushing = true;
private ErrorCallback errCB = new ErrorCallback() {
@Override
public void onError(IOException ioe) {
}
}; // Default null cb

View File

@@ -24,6 +24,7 @@ public class ConnectionException
extends SSHException {
public static final ExceptionChainer<ConnectionException> chainer = new ExceptionChainer<ConnectionException>() {
@Override
public ConnectionException chain(Throwable t) {
if (t instanceof ConnectionException)
return (ConnectionException) t;

View File

@@ -63,19 +63,23 @@ public class ConnectionImpl
super("ssh-connection", trans);
}
@Override
public void attach(Channel chan) {
log.info("Attaching `{}` channel (#{})", chan.getType(), chan.getID());
channels.put(chan.getID(), chan);
}
@Override
public Channel get(int id) {
return channels.get(id);
}
@Override
public ForwardedChannelOpener get(String chanType) {
return openers.get(chanType);
}
@Override
public void forget(Channel chan) {
log.info("Forgetting `{}` channel (#{})", chan.getType(), chan.getID());
channels.remove(chan.getID());
@@ -85,11 +89,13 @@ public class ConnectionImpl
}
}
@Override
public void forget(ForwardedChannelOpener opener) {
log.info("Forgetting opener for `{}` channels: {}", opener.getChannelType(), opener);
openers.remove(opener.getChannelType());
}
@Override
public void attach(ForwardedChannelOpener opener) {
log.info("Attaching opener for `{}` channels: {}", opener.getChannelType(), opener);
openers.put(opener.getChannelType(), opener);
@@ -146,26 +152,32 @@ public class ConnectionImpl
channels.clear();
}
@Override
public int getMaxPacketSize() {
return maxPacketSize;
}
@Override
public Transport getTransport() {
return trans;
}
@Override
public void setMaxPacketSize(int maxPacketSize) {
this.maxPacketSize = maxPacketSize;
}
@Override
public int getWindowSize() {
return windowSize;
}
@Override
public void setWindowSize(int windowSize) {
this.windowSize = windowSize;
}
@Override
public void join()
throws InterruptedException {
synchronized (internalSynchronizer) {
@@ -174,10 +186,12 @@ public class ConnectionImpl
}
}
@Override
public int nextID() {
return nextID.getAndIncrement();
}
@Override
public Future<SSHPacket, ConnectionException> sendGlobalRequest(String name, boolean wantReply,
byte[] specifics)
throws TransportException {
@@ -221,6 +235,7 @@ public class ConnectionImpl
}
}
@Override
public void sendOpenFailure(int recipient, Reason reason, String message)
throws TransportException {
trans.write(new SSHPacket(Message.CHANNEL_OPEN_FAILURE)

View File

@@ -78,7 +78,7 @@ public abstract class AbstractChannel
private final Queue<Event<ConnectionException>> chanReqResponseEvents = new LinkedList<Event<ConnectionException>>();
/* The lock used by #newEvent to create open & close events */
/* The lock used by to create the open & close events */
private final ReentrantLock lock = new ReentrantLock();
/** Channel open event */
protected final Event<ConnectionException> open;
@@ -125,46 +125,57 @@ public abstract class AbstractChannel
log.info("Initialized - {}", this);
}
@Override
public boolean getAutoExpand() {
return autoExpand;
}
@Override
public int getID() {
return id;
}
@Override
public InputStream getInputStream() {
return in;
}
@Override
public int getLocalMaxPacketSize() {
return lwin.getMaxPacketSize();
}
@Override
public int getLocalWinSize() {
return lwin.getSize();
}
@Override
public OutputStream getOutputStream() {
return out;
}
@Override
public int getRecipient() {
return recipient;
}
@Override
public int getRemoteMaxPacketSize() {
return rwin.getMaxPacketSize();
}
@Override
public int getRemoteWinSize() {
return rwin.getSize();
}
@Override
public String getType() {
return type;
}
@Override
public void handle(Message msg, SSHPacket buf)
throws ConnectionException, TransportException {
switch (msg) {
@@ -223,6 +234,7 @@ public abstract class AbstractChannel
IOUtils.closeQuietly(in, out);
}
@Override
public void notifyError(SSHException error) {
log.debug("Channel #{} got notified of {}", getID(), error.toString());
@@ -235,10 +247,12 @@ public abstract class AbstractChannel
finishOff();
}
@Override
public void setAutoExpand(boolean autoExpand) {
this.autoExpand = autoExpand;
}
@Override
public void close()
throws ConnectionException, TransportException {
lock.lock();
@@ -267,6 +281,7 @@ public abstract class AbstractChannel
}
}
@Override
public synchronized boolean isOpen() {
lock.lock();
try {
@@ -371,6 +386,7 @@ public abstract class AbstractChannel
in.eof();
}
@Override
public synchronized void sendEOF()
throws TransportException {
try {

View File

@@ -34,13 +34,12 @@ public interface Channel
/**
* Request opening this channel from remote end.
*
* @throws OpenFailException in case the channel open request was rejected
* @throws net.schmizz.sshj.connection.ConnectionException
* other connection-layer error
* @throws TransportException error writing packets etc.
* @throws OpenFailException in case the channel open request was rejected
* @throws ConnectionException other connection-layer error
* @throws TransportException error writing packets etc.
*/
void open()
throws OpenFailException, ConnectionException, TransportException;
throws ConnectionException, TransportException;
}
@@ -77,6 +76,7 @@ public interface Channel
/** Close this channel. */
@Override
void close()
throws TransportException, ConnectionException;

View File

@@ -100,6 +100,7 @@ public final class ChannelInputStream
}
}
@Override
public synchronized void notifyError(SSHException error) {
this.error = error;
eof();
@@ -109,7 +110,7 @@ public final class ChannelInputStream
public int read()
throws IOException {
synchronized (b) {
return read(b, 0, 1) == -1 ? -1 : b[0];
return read(b, 0, 1) == -1 ? -1 : b[0] & 0xff;
}
}

View File

@@ -54,7 +54,7 @@ public final class ChannelOutputStream
implements ErrorNotifiable {
private final Channel chan;
private Transport trans;
private final Transport trans;
private final Window.Remote win;
private final SSHPacket buffer = new SSHPacket();
private final byte[] b = new byte[1];
@@ -102,6 +102,7 @@ public final class ChannelOutputStream
}
}
@Override
public synchronized void notifyError(SSHException error) {
this.error = error;
}

View File

@@ -17,7 +17,6 @@ package net.schmizz.sshj.connection.channel;
import net.schmizz.sshj.common.SSHRuntimeException;
import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.transport.TransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -105,8 +104,7 @@ public abstract class Window {
threshold = Math.min(maxPacketSize * 20, initialSize / 4);
}
public int neededAdjustment()
throws TransportException {
public int neededAdjustment() {
synchronized (lock) {
return (size - threshold <= 0) ? (initialSize - size) : 0;
}

View File

@@ -60,6 +60,7 @@ public abstract class AbstractDirectChannel
conn.attach(this);
}
@Override
public void open()
throws ConnectionException, TransportException {
trans.write(buildOpenReq());

View File

@@ -48,31 +48,32 @@ public class LocalPortForwarder {
final ErrorCallback closer = StreamCopier.closeOnErrorCallback(this,
new Closeable() {
@Override
public void close()
throws IOException {
sock.close();
}
});
new StreamCopier("chan2soc", getInputStream(), sock.getOutputStream()) //
.bufSize(getLocalMaxPacketSize()) //
.errorCallback(closer) //
.daemon(true) //
new StreamCopier("chan2soc", getInputStream(), sock.getOutputStream())
.bufSize(getLocalMaxPacketSize())
.errorCallback(closer)
.daemon(true)
.start();
new StreamCopier("soc2chan", sock.getInputStream(), getOutputStream()) //
.bufSize(getRemoteMaxPacketSize()) //
.errorCallback(closer) //
.daemon(true) //
new StreamCopier("soc2chan", sock.getInputStream(), getOutputStream())
.bufSize(getRemoteMaxPacketSize())
.errorCallback(closer)
.daemon(true)
.start();
}
@Override
protected SSHPacket buildOpenReq() {
return super.buildOpenReq() //
.putString(host) //
.putInt(port) //
.putString(ss.getInetAddress().getHostAddress()) //
return super.buildOpenReq()
.putString(host)
.putInt(port)
.putString(ss.getInetAddress().getHostAddress())
.putInt(ss.getLocalPort());
}
@@ -85,6 +86,19 @@ public class LocalPortForwarder {
private final String host;
private final int port;
/**
* Create a local port forwarder with specified binding ({@code listeningAddr}. It does not, however, start
* listening unless {@link #listen() explicitly told to}. The {@link javax.net.ServerSocketFactory#getDefault()
* default} server socket factory is used.
*
* @param conn {@link Connection} implementation
* @param listeningAddr {@link SocketAddress} this forwarder will listen on, if {@code null} then an ephemeral port
* and valid local address will be picked to bind the server socket
* @param host what host the SSH server will further forward to
* @param port port on {@code toHost}
*
* @throws IOException if there is an error binding on specified {@code listeningAddr}
*/
public LocalPortForwarder(Connection conn, SocketAddress listeningAddr, String host, int port)
throws IOException {
this(ServerSocketFactory.getDefault(), conn, listeningAddr, host, port);
@@ -94,6 +108,7 @@ public class LocalPortForwarder {
* Create a local port forwarder with specified binding ({@code listeningAddr}. It does not, however, start
* listening unless {@link #listen() explicitly told to}.
*
* @param ssf factory to use for creating the server socket
* @param conn {@link Connection} implementation
* @param listeningAddr {@link SocketAddress} this forwarder will listen on, if {@code null} then an ephemeral port
* and valid local address will be picked to bind the server socket
@@ -112,16 +127,21 @@ public class LocalPortForwarder {
ss.bind(listeningAddr);
}
/** @return the address to which this forwarder is bound for listening */
public SocketAddress getListeningAddress() {
return ss.getLocalSocketAddress();
}
/** Start listening for incoming connections and forward to remote host as a channel. */
/**
* Start listening for incoming connections and forward to remote host as a channel.
*
* @throws IOException
*/
public void listen()
throws IOException {
log.info("Listening on {}", ss.getLocalSocketAddress());
Socket sock;
while (true) {
while (!Thread.currentThread().isInterrupted()) {
sock = ss.accept();
log.info("Got connection from {}", sock.getRemoteSocketAddress());
DirectTCPIPChannel chan = new DirectTCPIPChannel(conn, sock);

View File

@@ -46,7 +46,7 @@ import net.schmizz.sshj.transport.TransportException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -56,6 +56,8 @@ public class
extends AbstractDirectChannel
implements Session, Session.Command, Session.Shell, Session.Subsystem {
private final ChannelInputStream err = new ChannelInputStream(this, trans, lwin);
private Integer exitStatus;
private Signal exitSignal;
@@ -64,28 +66,17 @@ public class
private Boolean canDoFlowControl;
private ChannelInputStream err = new ChannelInputStream(this, trans, lwin);
public SessionChannel(Connection conn) {
super(conn, "session");
}
@Override
public void allocateDefaultPTY()
throws ConnectionException, TransportException {
// TODO FIXME (maybe?): These modes were originally copied from what SSHD was doing;
// and then the echo modes were set to 0 to better serve the PTY example.
// Not sure what default PTY modes should be.
final Map<PTYMode, Integer> modes = new HashMap<PTYMode, Integer>();
modes.put(PTYMode.ISIG, 1);
modes.put(PTYMode.ICANON, 1);
modes.put(PTYMode.ECHO, 0);
modes.put(PTYMode.ECHOE, 0);
modes.put(PTYMode.ECHOK, 0);
modes.put(PTYMode.ECHONL, 0);
modes.put(PTYMode.NOFLSH, 0);
allocatePTY("vt100", 0, 0, 0, 0, modes);
allocatePTY("vt100", 80, 24, 0, 0, Collections.<PTYMode, Integer>emptyMap());
}
@Override
public void allocatePTY(String term, int cols, int rows, int width, int height, Map<PTYMode, Integer> modes)
throws ConnectionException, TransportException {
sendChannelRequest(
@@ -101,10 +92,12 @@ public class
).await(conn.getTimeout(), TimeUnit.SECONDS);
}
@Override
public Boolean canDoFlowControl() {
return canDoFlowControl;
}
@Override
public void changeWindowDimensions(int cols, int rows, int width, int height)
throws TransportException {
sendChannelRequest(
@@ -118,6 +111,7 @@ public class
);
}
@Override
public Command exec(String command)
throws ConnectionException, TransportException {
log.info("Will request to exec `{}`", command);
@@ -126,27 +120,33 @@ public class
return this;
}
@Override
public String getErrorAsString()
throws IOException {
return StreamCopier.copyStreamToString(err);
}
@Override
public InputStream getErrorStream() {
return err;
}
@Override
public String getExitErrorMessage() {
return exitErrMsg;
}
@Override
public Signal getExitSignal() {
return exitSignal;
}
@Override
public Integer getExitStatus() {
return exitStatus;
}
@Override
public String getOutputAsString()
throws IOException {
return StreamCopier.copyStreamToString(getInputStream());
@@ -168,6 +168,7 @@ public class
super.handleRequest(req, buf);
}
@Override
public void reqX11Forwarding(String authProto, String authCookie, int screen)
throws ConnectionException,
TransportException {
@@ -182,23 +183,27 @@ public class
).await(conn.getTimeout(), TimeUnit.SECONDS);
}
@Override
public void setEnvVar(String name, String value)
throws ConnectionException, TransportException {
sendChannelRequest("env", true, new Buffer.PlainBuffer().putString(name).putString(value))
.await(conn.getTimeout(), TimeUnit.SECONDS);
}
@Override
public void signal(Signal sig)
throws TransportException {
sendChannelRequest("signal", false, new Buffer.PlainBuffer().putString(sig.toString()));
}
@Override
public Shell startShell()
throws ConnectionException, TransportException {
sendChannelRequest("shell", true, null).await(conn.getTimeout(), TimeUnit.SECONDS);
return this;
}
@Override
public Subsystem startSubsystem(String name)
throws ConnectionException, TransportException {
log.info("Will request `{}` subsystem", name);
@@ -207,6 +212,7 @@ public class
return this;
}
@Override
public Boolean getExitWasCoreDumped() {
return wasCoreDumped;
}

View File

@@ -62,6 +62,7 @@ public abstract class AbstractForwardedChannel
init(recipient, remoteWinSize, remoteMaxPacketSize);
}
@Override
public void confirm()
throws TransportException {
log.info("Confirming `{}` channel #{}", getType(), getID());
@@ -74,16 +75,19 @@ public abstract class AbstractForwardedChannel
open.set();
}
@Override
public void reject(Reason reason, String message)
throws TransportException {
log.info("Rejecting `{}` channel: {}", getType(), message);
conn.sendOpenFailure(getRecipient(), reason, message);
}
@Override
public String getOriginatorIP() {
return origIP;
}
@Override
public int getOriginatorPort() {
return origPort;
}

View File

@@ -40,14 +40,12 @@ public abstract class AbstractForwardedChannelOpener
this.conn = conn;
}
@Override
public String getChannelType() {
return chanType;
}
/*
* Calls the listener with the new channel in a separate thread.
*/
/** Calls the listener with the new channel in a separate thread. */
protected void callListener(final ConnectListener listener, final Channel.Forwarded chan) {
new Thread() {

View File

@@ -128,13 +128,12 @@ public class RemotePortForwarder
private final Forward fwd;
public ForwardedTCPIPChannel(Connection conn, int recipient, int remoteWinSize, int remoteMaxPacketSize,
Forward fwd, String origIP, int origPort)
throws TransportException {
Forward fwd, String origIP, int origPort) {
super(conn, TYPE, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
this.fwd = fwd;
}
/** Returns the forwarding from which this channel originates. */
/** @return the forwarding from which this channel originates. */
public Forward getParentForward() {
return fwd;
}
@@ -209,6 +208,7 @@ public class RemotePortForwarder
* Internal API. Creates a {@link ForwardedTCPIPChannel} from the {@code CHANNEL_OPEN} request and calls associated
* {@code ConnectListener} for that forward in a separate thread.
*/
@Override
public void handleOpen(SSHPacket buf)
throws ConnectionException, TransportException {
final ForwardedTCPIPChannel chan = new ForwardedTCPIPChannel(conn, buf.readInt(), buf.readInt(), buf.readInt(),

View File

@@ -40,6 +40,7 @@ public class SocketForwardingConnectListener
}
/** On connect, confirm the channel and start forwarding. */
@Override
public void gotConnect(Channel.Forwarded chan)
throws IOException {
log.info("New connection from " + chan.getOriginatorIP() + ":" + chan.getOriginatorPort());
@@ -54,6 +55,7 @@ public class SocketForwardingConnectListener
chan.confirm();
final ErrorCallback closer = StreamCopier.closeOnErrorCallback(chan, new Closeable() {
@Override
public void close()
throws IOException {
sock.close();

View File

@@ -52,10 +52,13 @@ public class X11Forwarder
}
/** Internal API */
@Override
public void handleOpen(SSHPacket buf)
throws ConnectionException, TransportException {
callListener(listener, new X11Channel(conn, buf.readInt(), buf.readInt(), buf.readInt(), buf.readString(), buf
.readInt()));
callListener(listener, new X11Channel(conn,
buf.readInt(),
buf.readInt(), buf.readInt(),
buf.readString(), buf.readInt()));
}
/** Stop handling {@code x11} channel open requests. De-registers itself with connection layer. */

View File

@@ -25,6 +25,8 @@ import java.util.Set;
public final class FileAttributes {
public static final FileAttributes EMPTY = new FileAttributes();
public static enum Flag {
SIZE(0x00000001),
@@ -58,7 +60,7 @@ public final class FileAttributes {
private final long mtime;
private final Map<String, String> ext = new HashMap<String, String>();
public FileAttributes() {
private FileAttributes() {
size = atime = mtime = uid = gid = mask = 0;
mode = new FileMode(0);
}

View File

@@ -15,7 +15,7 @@
*/
package net.schmizz.sshj.sftp;
class PathComponents {
public class PathComponents {
public static String adjustForParent(String parent, String path) {
return (path.startsWith("/")) ? path // Absolute path, nothing to adjust

View File

@@ -17,7 +17,7 @@ package net.schmizz.sshj.sftp;
import java.io.IOException;
class PathHelper {
public class PathHelper {
private final SFTPEngine sftp;
private String dotDir;
@@ -49,7 +49,7 @@ class PathHelper {
}
}
private String getDotDir()
private synchronized String getDotDir()
throws IOException {
return (dotDir != null) ? dotDir : (dotDir = canon("."));
}

View File

@@ -61,6 +61,7 @@ public class RandomAccessRemoteFile
return count;
}
@Override
public boolean readBoolean()
throws IOException {
final int ch = read();
@@ -69,6 +70,7 @@ public class RandomAccessRemoteFile
return (ch != 0);
}
@Override
public byte readByte()
throws IOException {
final int ch = this.read();
@@ -77,6 +79,7 @@ public class RandomAccessRemoteFile
return (byte) (ch);
}
@Override
public char readChar()
throws IOException {
final int ch1 = this.read();
@@ -86,21 +89,25 @@ public class RandomAccessRemoteFile
return (char) ((ch1 << 8) + ch2);
}
@Override
public double readDouble()
throws IOException {
return Double.longBitsToDouble(readLong());
}
@Override
public float readFloat()
throws IOException {
return Float.intBitsToFloat(readInt());
}
@Override
public void readFully(byte[] b)
throws IOException {
readFully(b, 0, b.length);
}
@Override
public void readFully(byte[] b, int off, int len)
throws IOException {
int n = 0;
@@ -112,6 +119,7 @@ public class RandomAccessRemoteFile
} while (n < len);
}
@Override
public int readInt()
throws IOException {
final int ch1 = read();
@@ -123,6 +131,7 @@ public class RandomAccessRemoteFile
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4);
}
@Override
public String readLine()
throws IOException {
StringBuffer input = new StringBuffer();
@@ -151,11 +160,13 @@ public class RandomAccessRemoteFile
return input.toString();
}
@Override
public long readLong()
throws IOException {
return ((long) (readInt()) << 32) + (readInt() & 0xFFFFFFFFL);
}
@Override
public short readShort()
throws IOException {
final int ch1 = this.read();
@@ -165,11 +176,13 @@ public class RandomAccessRemoteFile
return (short) ((ch1 << 8) + ch2);
}
@Override
public String readUTF()
throws IOException {
return DataInputStream.readUTF(this);
}
@Override
public int readUnsignedByte()
throws IOException {
final int ch = this.read();
@@ -178,6 +191,7 @@ public class RandomAccessRemoteFile
return ch;
}
@Override
public int readUnsignedShort()
throws IOException {
final int ch1 = this.read();
@@ -187,6 +201,7 @@ public class RandomAccessRemoteFile
return (ch1 << 8) + ch2;
}
@Override
public int skipBytes(int n)
throws IOException {
if (n <= 0)
@@ -202,45 +217,53 @@ public class RandomAccessRemoteFile
return (int) (newpos - pos);
}
@Override
public void write(int i)
throws IOException {
singleByte[0] = (byte) i;
write(singleByte);
}
@Override
public void write(byte[] b)
throws IOException {
write(b, 0, b.length);
}
@Override
public void write(byte[] b, int off, int len)
throws IOException {
rf.write(fp, b, off, len);
fp += (len - off);
}
@Override
public void writeBoolean(boolean v)
throws IOException {
write(v ? 1 : 0);
}
@Override
public void writeByte(int v)
throws IOException {
write(v);
}
@Override
public void writeBytes(String s)
throws IOException {
final byte[] b = s.getBytes();
write(b, 0, b.length);
}
@Override
public void writeChar(int v)
throws IOException {
write((v >>> 8) & 0xFF);
write(v & 0xFF);
}
@Override
public void writeChars(String s)
throws IOException {
final int clen = s.length();
@@ -255,16 +278,19 @@ public class RandomAccessRemoteFile
write(b, 0, blen);
}
@Override
public void writeDouble(double v)
throws IOException {
writeLong(Double.doubleToLongBits(v));
}
@Override
public void writeFloat(float v)
throws IOException {
writeInt(Float.floatToIntBits(v));
}
@Override
public void writeInt(int v)
throws IOException {
write((v >>> 24) & 0xFF);
@@ -273,6 +299,7 @@ public class RandomAccessRemoteFile
write(v & 0xFF);
}
@Override
public void writeLong(long v)
throws IOException {
write((int) (v >>> 56) & 0xFF);
@@ -285,12 +312,14 @@ public class RandomAccessRemoteFile
write((int) v & 0xFF);
}
@Override
public void writeShort(int v)
throws IOException {
write((v >>> 8) & 0xFF);
write(v & 0xFF);
}
@Override
public void writeUTF(String str)
throws IOException {
final DataOutputStream dos = new DataOutputStream(rf.new RemoteFileOutputStream(fp));

View File

@@ -46,7 +46,7 @@ public class RemoteDirectory
if (!(name.equals(".") || name.equals("..")) && (filter == null || filter.accept(inf)))
rri.add(inf);
}
break loop;
break;
case STATUS:
res.ensureStatusIs(StatusCode.EOF);

View File

@@ -38,8 +38,8 @@ public class RemoteFile
public FileAttributes fetchAttributes()
throws IOException {
return requester.doRequest(newRequest(PacketType.FSTAT)) //
.ensurePacketTypeIs(PacketType.ATTRS) //
return requester.doRequest(newRequest(PacketType.FSTAT))
.ensurePacketTypeIs(PacketType.ATTRS)
.readFileAttributes();
}
@@ -73,11 +73,10 @@ public class RemoteFile
public void write(long fileOffset, byte[] data, int off, int len)
throws IOException {
requester.doRequest( //
newRequest(PacketType.WRITE) //
.putUINT64(fileOffset) //
.putInt(len - off) //
.putRawBytes(data, off, len) //
requester.doRequest(newRequest(PacketType.WRITE)
.putUINT64(fileOffset)
.putInt(len - off)
.putRawBytes(data, off, len)
).ensureStatusPacketIsOK();
}
@@ -171,7 +170,7 @@ public class RemoteFile
@Override
public int read()
throws IOException {
return read(b, 0, 1) == -1 ? -1 : b[0];
return read(b, 0, 1) == -1 ? -1 : b[0] & 0xff;
}
@Override

View File

@@ -45,6 +45,7 @@ abstract class RemoteResource
return requester.newRequest(type).putString(handle);
}
@Override
public void close()
throws IOException {
log.info("Closing `{}`", this);

View File

@@ -55,12 +55,7 @@ public class RemoteResourceInfo {
@Override
public boolean equals(Object o) {
if (o instanceof RemoteResourceInfo) {
final RemoteResourceInfo that = (RemoteResourceInfo) o;
if (comps.equals(that.comps))
return true;
}
return false;
return o instanceof RemoteResourceInfo && (comps.equals(((RemoteResourceInfo) o).comps));
}
@Override

View File

@@ -25,11 +25,10 @@ public class Request
private final Future<Response, SFTPException> responseFuture;
public Request(PacketType type, long reqID) {
super();
this.reqID = reqID;
super(type);
this.type = type;
this.reqID = reqID;
responseFuture = new Future<Response, SFTPException>("sftp / " + reqID, SFTPException.chainer);
putByte(type.toByte());
putInt(reqID);
}

View File

@@ -21,7 +21,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Deque;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -32,10 +34,12 @@ public class SFTPClient {
private final SFTPEngine sftp;
private final SFTPFileTransfer xfer;
private final PathHelper pathHelper;
public SFTPClient(SessionFactory ssh)
throws IOException {
this.sftp = new SFTPEngine(ssh).init();
this.pathHelper = new PathHelper(sftp);
this.xfer = new SFTPFileTransfer(sftp);
}
@@ -70,7 +74,7 @@ public class SFTPClient {
public RemoteFile open(String filename, Set<OpenMode> mode)
throws IOException {
return open(filename, mode, new FileAttributes());
return open(filename, mode, FileAttributes.EMPTY);
}
public RemoteFile open(String filename)
@@ -83,6 +87,38 @@ public class SFTPClient {
sftp.makeDir(dirname);
}
public void mkdirs(String path)
throws IOException {
final Deque<String> dirsToMake = new LinkedList<String>();
for (PathComponents current = pathHelper.getComponents(path); ; current = pathHelper
.getComponents(current.getParent())) {
final FileAttributes attrs = statExistence(current.getPath());
if (attrs == null) {
dirsToMake.push(current.getPath());
} else if (attrs.getType() != FileMode.Type.DIRECTORY) {
throw new SFTPException(current.getPath() + " exists but is not a directory");
} else {
break;
}
}
while (!dirsToMake.isEmpty()) {
mkdir(dirsToMake.pop());
}
}
public FileAttributes statExistence(String path)
throws IOException {
try {
return sftp.stat(path);
} catch (SFTPException sftpe) {
if (sftpe.getStatusCode() == Response.StatusCode.NO_SUCH_FILE) {
return null;
} else {
throw sftpe;
}
}
}
public void rename(String oldpath, String newpath)
throws IOException {
sftp.rename(oldpath, newpath);

View File

@@ -87,10 +87,12 @@ public class SFTPEngine
return negotiatedVersion;
}
@Override
public synchronized Request newRequest(PacketType type) {
return new Request(type, reqID = reqID + 1 & 0xffffffffL);
}
@Override
public Response doRequest(Request req)
throws IOException {
reader.expectResponseTo(req);
@@ -112,7 +114,6 @@ public class SFTPEngine
public RemoteFile open(String path, Set<OpenMode> modes, FileAttributes fa)
throws IOException {
final String handle = doRequest(
newRequest(PacketType.OPEN).putString(path).putInt(OpenMode.toMask(modes)).putFileAttributes(fa)
).ensurePacketTypeIs(PacketType.HANDLE).readString();
@@ -121,7 +122,7 @@ public class SFTPEngine
public RemoteFile open(String filename, Set<OpenMode> modes)
throws IOException {
return open(filename, modes, new FileAttributes());
return open(filename, modes, FileAttributes.EMPTY);
}
public RemoteFile open(String filename)
@@ -154,14 +155,12 @@ public class SFTPEngine
public void makeDir(String path, FileAttributes attrs)
throws IOException {
doRequest(
newRequest(PacketType.MKDIR).putString(path).putFileAttributes(attrs)
).ensureStatusPacketIsOK();
doRequest(newRequest(PacketType.MKDIR).putString(path).putFileAttributes(attrs)).ensureStatusPacketIsOK();
}
public void makeDir(String path)
throws IOException {
makeDir(path, new FileAttributes());
makeDir(path, FileAttributes.EMPTY);
}
public void symlink(String linkpath, String targetpath)

View File

@@ -25,6 +25,7 @@ public class SFTPException
public static final ExceptionChainer<SFTPException> chainer = new ExceptionChainer<SFTPException>() {
@Override
public SFTPException chain(Throwable t) {
if (t instanceof SFTPException)
return (SFTPException) t;

View File

@@ -20,6 +20,7 @@ import net.schmizz.sshj.sftp.Response.StatusCode;
import net.schmizz.sshj.xfer.AbstractFileTransfer;
import net.schmizz.sshj.xfer.FileTransfer;
import net.schmizz.sshj.xfer.FileTransferUtil;
import net.schmizz.sshj.xfer.TransferListener;
import java.io.File;
import java.io.FileFilter;
@@ -39,12 +40,14 @@ public class SFTPFileTransfer
private volatile RemoteResourceFilter downloadFilter = defaultRemoteFilter;
private static final FileFilter defaultLocalFilter = new FileFilter() {
@Override
public boolean accept(File pathName) {
return true;
}
};
private static final RemoteResourceFilter defaultRemoteFilter = new RemoteResourceFilter() {
@Override
public boolean accept(RemoteResourceInfo resource) {
return true;
}
@@ -55,11 +58,13 @@ public class SFTPFileTransfer
this.pathHelper = new PathHelper(sftp);
}
@Override
public void upload(String source, String dest)
throws IOException {
new Uploader().upload(new File(source), dest);
}
@Override
public void download(String source, String dest)
throws IOException {
final PathComponents pathComponents = pathHelper.getComponents(source);
@@ -85,7 +90,64 @@ public class SFTPFileTransfer
private class Downloader {
private void setAttributes(final RemoteResourceInfo remote, final File local)
private final TransferListener listener = getTransferListener();
private void download(final RemoteResourceInfo remote, final File local)
throws IOException {
final File adjustedFile;
switch (remote.getAttributes().getType()) {
case DIRECTORY:
listener.startedDir(remote.getName());
adjustedFile = downloadDir(remote, local);
listener.finishedDir();
break;
case UNKNOWN:
log.warn("Server did not supply information about the type of file at `{}` " +
"-- assuming it is a regular file!", remote.getPath());
case REGULAR:
listener.startedFile(remote.getName(), remote.getAttributes().getSize());
adjustedFile = downloadFile(remote, local);
listener.finishedFile();
break;
default:
throw new IOException(remote + " is not a regular file or directory");
}
copyAttributes(remote, adjustedFile);
}
private File downloadDir(final RemoteResourceInfo remote, final File local)
throws IOException {
final File adjusted = FileTransferUtil.getTargetDirectory(local, remote.getName());
final RemoteDirectory rd = sftp.openDir(remote.getPath());
try {
for (RemoteResourceInfo rri : rd.scan(getDownloadFilter()))
download(rri, new File(adjusted.getPath(), rri.getName()));
} finally {
rd.close();
}
return adjusted;
}
private File downloadFile(final RemoteResourceInfo remote, final File local)
throws IOException {
final File adjusted = FileTransferUtil.getTargetFile(local, remote.getName());
final RemoteFile rf = sftp.open(remote.getPath());
try {
final FileOutputStream fos = new FileOutputStream(adjusted);
try {
StreamCopier.copy(rf.getInputStream(), fos, sftp.getSubsystem()
.getLocalMaxPacketSize(), false, listener);
} finally {
fos.close();
}
} finally {
rf.close();
}
return adjusted;
}
private void copyAttributes(final RemoteResourceInfo remote, final File local)
throws IOException {
final FileAttributes attrs = remote.getAttributes();
getModeSetter().setPermissions(local, attrs.getMode().getPermissionsMask());
@@ -95,91 +157,54 @@ public class SFTPFileTransfer
}
}
private void downloadFile(final RemoteResourceInfo remote, final File local)
throws IOException {
final File adjusted = FileTransferUtil.getTargetFile(local, remote.getName());
setAttributes(remote, adjusted);
final RemoteFile rf = sftp.open(remote.getPath());
try {
final FileOutputStream fos = new FileOutputStream(adjusted);
try {
StreamCopier.copy(rf.getInputStream(), fos, sftp.getSubsystem()
.getLocalMaxPacketSize(), false);
} finally {
fos.close();
}
} finally {
rf.close();
}
}
private void downloadDir(final RemoteResourceInfo remote, final File local)
throws IOException {
final File adjusted = FileTransferUtil.getTargetDirectory(local, remote.getName());
setAttributes(remote, adjusted);
final RemoteDirectory rd = sftp.openDir(remote.getPath());
try {
for (RemoteResourceInfo rri : rd.scan(getDownloadFilter()))
download(rri, new File(adjusted.getPath(), rri.getName()));
} finally {
rd.close();
}
}
void download(final RemoteResourceInfo remote, final File local)
throws IOException {
log.info("Downloading [{}] to [{}]", remote, local);
switch (remote.getAttributes().getType()) {
case DIRECTORY:
downloadDir(remote, local);
break;
case UNKNOWN:
log.warn("Server did not supply information about the type of file at `{}` -- assuming it is a regular file!");
case REGULAR:
downloadFile(remote, local);
break;
default:
throw new IOException(remote + " is not a regular file or directory");
}
}
}
private class Uploader {
void upload(File local, String remote)
private final TransferListener listener = getTransferListener();
private void upload(File local, String remote)
throws IOException {
log.info("Uploading [{}] to [{}]", local, remote);
if (local.isDirectory())
uploadDir(local, remote);
else if (local.isFile())
uploadFile(local, remote);
else
final String adjustedPath;
if (local.isDirectory()) {
listener.startedDir(local.getName());
adjustedPath = uploadDir(local, remote);
listener.finishedDir();
} else if (local.isFile()) {
listener.startedFile(local.getName(), local.length());
adjustedPath = uploadFile(local, remote);
listener.finishedFile();
} else
throw new IOException(local + " is not a file or directory");
sftp.setAttributes(adjustedPath, getAttributes(local));
}
private void uploadDir(File local, String remote)
private String uploadDir(File local, String remote)
throws IOException {
final String adjusted = prepareDir(local, remote);
for (File f : local.listFiles(getUploadFilter()))
upload(f, adjusted);
return adjusted;
}
private void uploadFile(File local, String remote)
private String uploadFile(File local, String remote)
throws IOException {
final String adjusted = prepareFile(local, remote);
final RemoteFile rf = sftp.open(adjusted, EnumSet.of(OpenMode.WRITE, OpenMode.CREAT, OpenMode.TRUNC),
getAttributes(local));
final RemoteFile rf = sftp.open(adjusted, EnumSet.of(OpenMode.WRITE,
OpenMode.CREAT,
OpenMode.TRUNC));
try {
final FileInputStream fis = new FileInputStream(local);
try {
StreamCopier.copy(fis, rf.getOutputStream(), sftp.getSubsystem().getRemoteMaxPacketSize()
- rf.getOutgoingPacketOverhead(), false);
final int bufSize = sftp.getSubsystem().getRemoteMaxPacketSize() - rf.getOutgoingPacketOverhead();
StreamCopier.copy(fis, rf.getOutputStream(), bufSize, false, listener);
} finally {
fis.close();
}
} finally {
rf.close();
}
return adjusted;
}
private String prepareDir(File local, String remote)
@@ -190,7 +215,7 @@ public class SFTPFileTransfer
} catch (SFTPException e) {
if (e.getStatusCode() == StatusCode.NO_SUCH_FILE) {
log.debug("probeDir: {} does not exist, creating", remote);
sftp.makeDir(remote, getAttributes(local));
sftp.makeDir(remote);
return remote;
} else
throw e;
@@ -199,11 +224,6 @@ public class SFTPFileTransfer
if (attrs.getMode().getType() == FileMode.Type.DIRECTORY)
if (pathHelper.getComponents(remote).getName().equals(local.getName())) {
log.debug("probeDir: {} already exists", remote);
final FileAttributes localAttrs = getAttributes(local);
if (attrs.getMode().getMask() != localAttrs.getMode().getMask()
|| (getModeGetter().preservesTimes()
&& (attrs.getAtime() != attrs.getAtime() || attrs.getMtime() != localAttrs.getMtime())))
sftp.setAttributes(remote, localAttrs);
return remote;
} else {
log.debug("probeDir: {} already exists, path adjusted for {}", remote, local.getName());
@@ -238,7 +258,6 @@ public class SFTPFileTransfer
private FileAttributes getAttributes(File local)
throws IOException {
final FileAttributes.Builder builder = new FileAttributes.Builder()
.withType(local.isDirectory() ? FileMode.Type.DIRECTORY : FileMode.Type.REGULAR)
.withPermissions(getModeGetter().getPermissions(local));
if (getModeGetter().preservesTimes())
builder.withAtimeMtime(getModeGetter().getLastAccessTime(local), getModeGetter().getLastModifiedTime(local));

View File

@@ -37,8 +37,12 @@ public class StatefulSFTPClient
return PathComponents.adjustForParent(cwd, path);
}
public synchronized void cd(String dirname) {
public synchronized void cd(String dirname)
throws IOException {
cwd = cwdify(dirname);
if (statExistence(cwd) == null) {
throw new SFTPException(cwd + ": does not exist");
}
log.info("CWD = " + cwd);
}
@@ -98,6 +102,18 @@ public class StatefulSFTPClient
super.mkdir(cwdify(dirname));
}
@Override
public void mkdirs(String path)
throws IOException {
super.mkdirs(cwdify(path));
}
@Override
public FileAttributes statExistence(String path)
throws IOException {
return super.statExistence(cwdify(path));
}
@Override
public void rename(String oldpath, String newpath)
throws IOException {

View File

@@ -47,29 +47,32 @@ import java.security.SignatureException;
public abstract class AbstractSignature
implements Signature {
protected final String algorithm;
protected java.security.Signature signature;
protected String algorithm;
protected AbstractSignature(String algorithm) {
this.algorithm = algorithm;
}
public void init(PublicKey pubkey, PrivateKey prvkey) {
@Override
public void init(PublicKey publicKey, PrivateKey privateKey) {
try {
signature = SecurityUtils.getSignature(algorithm);
if (pubkey != null)
signature.initVerify(pubkey);
if (prvkey != null)
signature.initSign(prvkey);
if (publicKey != null)
signature.initVerify(publicKey);
if (privateKey != null)
signature.initSign(privateKey);
} catch (GeneralSecurityException e) {
throw new SSHRuntimeException(e);
}
}
@Override
public void update(byte[] foo) {
update(foo, 0, foo.length);
}
@Override
public void update(byte[] foo, int off, int len) {
try {
signature.update(foo, off, len);
@@ -81,19 +84,18 @@ public abstract class AbstractSignature
protected byte[] extractSig(byte[] sig) {
if (sig[0] == 0 && sig[1] == 0 && sig[2] == 0) {
int i = 0;
int j;
j = sig[i++] << 24 & 0xff000000 //
| sig[i++] << 16 & 0x00ff0000 //
| sig[i++] << 8 & 0x0000ff00 //
| sig[i++] & 0x000000ff;
int j = sig[i++] << 24 & 0xff000000
| sig[i++] << 16 & 0x00ff0000
| sig[i++] << 8 & 0x0000ff00
| sig[i++] & 0x000000ff;
i += j;
j = sig[i++] << 24 & 0xff000000 //
| sig[i++] << 16 & 0x00ff0000 //
| sig[i++] << 8 & 0x0000ff00 //
j = sig[i++] << 24 & 0xff000000
| sig[i++] << 16 & 0x00ff0000
| sig[i++] << 8 & 0x0000ff00
| sig[i++] & 0x000000ff;
byte[] tmp = new byte[j];
System.arraycopy(sig, i, tmp, 0, j);
sig = tmp;
byte[] newSig = new byte[j];
System.arraycopy(sig, i, newSig, 0, j);
sig = newSig;
}
return sig;
}

View File

@@ -48,10 +48,12 @@ public class SignatureDSA
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Signature> {
@Override
public Signature create() {
return new SignatureDSA();
}
@Override
public String getName() {
return KeyType.DSA.toString();
}
@@ -62,6 +64,7 @@ public class SignatureDSA
super("SHA1withDSA");
}
@Override
public byte[] sign() {
byte[] sig;
try {
@@ -72,15 +75,16 @@ public class SignatureDSA
// sig is in ASN.1
// SEQUENCE::={ r INTEGER, s INTEGER }
int len = 0;
int index = 3;
len = sig[index++] & 0xff;
byte[] r = new byte[len];
System.arraycopy(sig, index, r, 0, r.length);
index = index + len + 1;
len = sig[index++] & 0xff;
byte[] s = new byte[len];
System.arraycopy(sig, index, s, 0, s.length);
int rIndex = 3;
int rLen = sig[rIndex++] & 0xff;
byte[] r = new byte[rLen];
System.arraycopy(sig, rIndex, r, 0, r.length);
int sIndex = rIndex + rLen + 1;
int sLen = sig[sIndex++] & 0xff;
byte[] s = new byte[sLen];
System.arraycopy(sig, sIndex, s, 0, s.length);
byte[] result = new byte[40];
@@ -91,6 +95,7 @@ public class SignatureDSA
result,
r.length > 20 ? 0 : 20 - r.length,
r.length > 20 ? 20 : r.length);
System.arraycopy(s,
s.length > 20 ? 1 : 0,
result,
@@ -100,6 +105,7 @@ public class SignatureDSA
return result;
}
@Override
public boolean verify(byte[] sig) {
sig = extractSig(sig);

View File

@@ -48,10 +48,12 @@ public class SignatureRSA
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Signature> {
@Override
public Signature create() {
return new SignatureRSA();
}
@Override
public String getName() {
return KeyType.RSA.toString();
}
@@ -62,6 +64,7 @@ public class SignatureRSA
super("SHA1withRSA");
}
@Override
public byte[] sign() {
try {
return signature.sign();
@@ -70,6 +73,7 @@ public class SignatureRSA
}
}
@Override
public boolean verify(byte[] sig) {
sig = extractSig(sig);
try {

View File

@@ -74,7 +74,7 @@ abstract class Converter {
this.mac = mac;
this.compression = compression;
if (compression != null)
compression.init(getCompressionType(), -1);
compression.init(getCompressionType());
this.cipherSize = cipher.getIVSize();
}
@@ -86,6 +86,6 @@ abstract class Converter {
return compression != null && (authed || !compression.isDelayed());
}
abstract Compression.Type getCompressionType();
abstract Compression.Mode getCompressionType();
}

View File

@@ -199,8 +199,8 @@ final class Decoder
}
@Override
Compression.Type getCompressionType() {
return Compression.Type.Inflater;
Compression.Mode getCompressionType() {
return Compression.Mode.INFLATE;
}
int getMaxPacketLength() {

View File

@@ -160,9 +160,8 @@ final class Encoder
}
@Override
Compression.Type getCompressionType() {
return Compression.Type.Deflater;
Compression.Mode getCompressionType() {
return Compression.Mode.DEFLATE;
}
}

View File

@@ -47,6 +47,7 @@ import net.schmizz.sshj.transport.verification.HostKeyVerifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
import java.util.Arrays;
import java.util.LinkedList;
@@ -228,8 +229,12 @@ final class KeyExchanger
log.debug("Negotiated algorithms: {}", negotiatedAlgs);
kex = Factory.Named.Util.create(transport.getConfig().getKeyExchangeFactories(), negotiatedAlgs
.getKeyExchangeAlgorithm());
kex.init(transport, transport.getServerID().getBytes(), transport.getClientID().getBytes(), buf
.getCompactData(), clientProposal.getPacket().getCompactData());
try {
kex.init(transport, transport.getServerID().getBytes(), transport.getClientID().getBytes(), buf
.getCompactData(), clientProposal.getPacket().getCompactData());
} catch (GeneralSecurityException e) {
throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, e);
}
}
/**
@@ -326,6 +331,7 @@ final class KeyExchanger
transport.getDecoder().setAlgorithms(cipher_S2C, mac_S2C, compression_S2C);
}
@Override
public void handle(Message msg, SSHPacket buf)
throws TransportException {
switch (expected) {
@@ -347,10 +353,14 @@ final class KeyExchanger
case FOLLOWUP:
ensureKexOngoing();
log.info("Received kex followup data");
if (kex.next(msg, buf)) {
verifyHost(kex.getHostKey());
sendNewKeys();
expected = Expected.NEWKEYS;
try {
if (kex.next(msg, buf)) {
verifyHost(kex.getHostKey());
sendNewKeys();
expected = Expected.NEWKEYS;
}
} catch (GeneralSecurityException e) {
throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, e);
}
break;
@@ -369,6 +379,7 @@ final class KeyExchanger
}
}
@Override
public void notifyError(SSHException error) {
log.debug("Got notified of {}", error.toString());
FutureUtils.alertAll(error, kexInitSent, done);

View File

@@ -25,6 +25,7 @@ public class TransportException
/** @see ExceptionChainer */
public static final ExceptionChainer<TransportException> chainer = new ExceptionChainer<TransportException>() {
@Override
public TransportException chain(Throwable t) {
if (t instanceof TransportException)
return (TransportException) t;

View File

@@ -133,6 +133,7 @@ public final class TransportImpl
clientID = "SSH-2.0-" + config.getVersion();
}
@Override
public void init(String remoteHost, int remotePort, InputStream in, OutputStream out)
throws TransportException {
connInfo = new ConnInfo(remoteHost, remotePort, in, out);
@@ -214,10 +215,12 @@ public final class TransportImpl
return ident;
}
@Override
public void addHostKeyVerifier(HostKeyVerifier hkv) {
kexer.addHostKeyVerifier(hkv);
}
@Override
public void doKex()
throws TransportException {
kexer.startKex(true);
@@ -227,50 +230,62 @@ public final class TransportImpl
return kexer.isKexDone();
}
@Override
public int getTimeout() {
return timeout;
}
@Override
public void setTimeout(int timeout) {
this.timeout = timeout;
}
@Override
public int getHeartbeatInterval() {
return heartbeater.getInterval();
}
@Override
public void setHeartbeatInterval(int interval) {
heartbeater.setInterval(interval);
}
@Override
public String getRemoteHost() {
return connInfo.host;
}
@Override
public int getRemotePort() {
return connInfo.port;
}
@Override
public String getClientVersion() {
return clientID.substring(8);
}
@Override
public Config getConfig() {
return config;
}
@Override
public String getServerVersion() {
return serverID == null ? serverID : serverID.substring(8);
}
@Override
public byte[] getSessionID() {
return kexer.getSessionID();
}
@Override
public synchronized Service getService() {
return service;
}
@Override
public synchronized void setService(Service service) {
if (service == null)
service = nullService;
@@ -279,6 +294,7 @@ public final class TransportImpl
this.service = service;
}
@Override
public void reqService(Service service)
throws TransportException {
serviceAccept.lock();
@@ -305,16 +321,19 @@ public final class TransportImpl
write(new SSHPacket(Message.SERVICE_REQUEST).putString(serviceName));
}
@Override
public void setAuthenticated() {
this.authed = true;
encoder.setAuthenticated();
decoder.setAuthenticated();
}
@Override
public boolean isAuthenticated() {
return authed;
}
@Override
public long sendUnimplemented()
throws TransportException {
final long seq = decoder.getSequenceNumber();
@@ -322,23 +341,28 @@ public final class TransportImpl
return write(new SSHPacket(Message.UNIMPLEMENTED).putInt(seq));
}
@Override
public void join()
throws TransportException {
close.await();
}
@Override
public boolean isRunning() {
return reader.isAlive() && !close.isSet();
}
@Override
public void disconnect() {
disconnect(DisconnectReason.BY_APPLICATION);
}
@Override
public void disconnect(DisconnectReason reason) {
disconnect(reason, "");
}
@Override
public void disconnect(DisconnectReason reason, String message) {
close.lock(); // CAS type operation on close
try {
@@ -357,6 +381,7 @@ public final class TransportImpl
}
}
@Override
public long write(SSHPacket payload)
throws TransportException {
writeLock.lock();
@@ -416,6 +441,7 @@ public final class TransportImpl
*
* @throws SSHException if an error occurs during handling (unrecoverable)
*/
@Override
public void handle(Message msg, SSHPacket buf)
throws SSHException {
this.msg = msg;

View File

@@ -42,10 +42,12 @@ public class AES128CBC
/** Named factory for AES128CBC Cipher */
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
@Override
public Cipher create() {
return new AES128CBC();
}
@Override
public String getName() {
return "aes128-cbc";
}

View File

@@ -42,10 +42,12 @@ public class AES128CTR
/** Named factory for AES128CBC Cipher */
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
@Override
public Cipher create() {
return new AES128CTR();
}
@Override
public String getName() {
return "aes128-ctr";
}

View File

@@ -42,10 +42,12 @@ public class AES192CBC
/** Named factory for AES192CBC Cipher */
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
@Override
public Cipher create() {
return new AES192CBC();
}
@Override
public String getName() {
return "aes192-cbc";
}

View File

@@ -42,10 +42,12 @@ public class AES192CTR
/** Named factory for AES192CTR Cipher */
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
@Override
public Cipher create() {
return new AES192CTR();
}
@Override
public String getName() {
return "aes192-ctr";
}

View File

@@ -42,10 +42,12 @@ public class AES256CBC
/** Named factory for AES256CBC Cipher */
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
@Override
public Cipher create() {
return new AES256CBC();
}
@Override
public String getName() {
return "aes256-cbc";
}

View File

@@ -42,10 +42,12 @@ public class AES256CTR
/** Named factory for AES256CBC Cipher */
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
@Override
public Cipher create() {
return new AES256CTR();
}
@Override
public String getName() {
return "aes256-ctr";
}

View File

@@ -70,14 +70,17 @@ public class BaseCipher
this.transformation = transformation;
}
@Override
public int getBlockSize() {
return bsize;
}
@Override
public int getIVSize() {
return ivsize;
}
@Override
public void init(Mode mode, byte[] key, byte[] iv) {
key = BaseCipher.resize(key, bsize);
iv = BaseCipher.resize(iv, ivsize);
@@ -91,6 +94,7 @@ public class BaseCipher
}
}
@Override
public void update(byte[] input, int inputOffset, int inputLen) {
try {
cipher.update(input, inputOffset, inputLen, input, inputOffset);

View File

@@ -42,10 +42,12 @@ public class BlowfishCBC
/** Named factory for BlowfishCBC Cipher */
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
@Override
public Cipher create() {
return new BlowfishCBC();
}
@Override
public String getName() {
return "blowfish-cbc";
}

View File

@@ -42,26 +42,32 @@ public class NoneCipher
/** Named factory for the no-op Cipher */
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
@Override
public Cipher create() {
return new NoneCipher();
}
@Override
public String getName() {
return "none";
}
}
@Override
public int getBlockSize() {
return 8;
}
@Override
public int getIVSize() {
return 8;
}
@Override
public void init(Mode mode, byte[] bytes, byte[] bytes1) {
}
@Override
public void update(byte[] input, int inputOffset, int inputLen) {
}

View File

@@ -42,10 +42,12 @@ public class TripleDESCBC
/** Named factory for TripleDESCBC Cipher */
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
@Override
public Cipher create() {
return new TripleDESCBC();
}
@Override
public String getName() {
return "3des-cbc";
}

View File

@@ -35,34 +35,26 @@
*/
package net.schmizz.sshj.transport.compression;
import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.common.Buffer;
import net.schmizz.sshj.transport.TransportException;
/** Interface used to compress the stream of data between the SSH server and clients. */
public interface Compression {
/** Enum identifying if this object will be used to compress or uncompress data. */
enum Type {
Inflater,
Deflater
enum Mode {
INFLATE,
DEFLATE
}
/**
* Compress the given buffer in place.
*
* @param buffer the buffer containing the data to compress s
*/
void compress(SSHPacket buffer);
/**
* Initialize this object to either compress or uncompress data. This method must be called prior to any calls to
* either <code>compress</code> or <code>uncompress</code>. Once the object has been initialized, only one of
* <code>compress</code> or <code>uncompress</code> method can be called.
*
* @param type
* @param level
* @param mode
*/
void init(Type type, int level);
void init(Mode mode);
/**
* Delayed compression is an Open-SSH specific feature which informs both the client and server to not compress data
@@ -72,13 +64,22 @@ public interface Compression {
*/
boolean isDelayed();
/**
* Compress the given buffer in place.
*
* @param buffer the buffer containing the data to compress s
*/
void compress(Buffer buffer);
/**
* Uncompress the data in a buffer into another buffer.
*
* @param from the buffer containing the data to uncompress
* @param to the buffer receiving the uncompressed data
*
* @throws TransportException
*/
void uncompress(SSHPacket from, SSHPacket to)
void uncompress(Buffer from, Buffer to)
throws TransportException;
}

View File

@@ -46,10 +46,12 @@ public class DelayedZlibCompression
/** Named factory for the ZLib Delayed Compression. */
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Compression> {
@Override
public Compression create() {
return new DelayedZlibCompression();
}
@Override
public String getName() {
return "zlib@openssh.com";
}

View File

@@ -42,10 +42,12 @@ public abstract class NoneCompression
/** Named factory for the no-op <code>Compression</code> */
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Compression> {
@Override
public Compression create() {
return null;
}
@Override
public String getName() {
return "none";
}

View File

@@ -37,8 +37,8 @@ package net.schmizz.sshj.transport.compression;
import com.jcraft.jzlib.JZlib;
import com.jcraft.jzlib.ZStream;
import net.schmizz.sshj.common.Buffer;
import net.schmizz.sshj.common.DisconnectReason;
import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.common.SSHRuntimeException;
import net.schmizz.sshj.transport.TransportException;
@@ -49,73 +49,80 @@ public class ZlibCompression
/** Named factory for the ZLib Compression. */
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Compression> {
@Override
public Compression create() {
return new ZlibCompression();
}
@Override
public String getName() {
return "zlib";
}
}
static private final int BUF_SIZE = 4096;
private static final int BUF_SIZE = 4096;
private final byte[] tempBuf = new byte[BUF_SIZE];
private ZStream stream;
private final byte[] tmpbuf = new byte[BUF_SIZE];
/** Create a new instance of a ZLib base compression */
public ZlibCompression() {
@Override
public void init(Mode mode) {
stream = new ZStream();
switch (mode) {
case DEFLATE:
stream.deflateInit(JZlib.Z_DEFAULT_COMPRESSION);
break;
case INFLATE:
stream.inflateInit();
break;
default:
assert false;
}
}
public void compress(SSHPacket buffer) {
@Override
public boolean isDelayed() {
return false;
}
@Override
public void compress(Buffer buffer) {
stream.next_in = buffer.array();
stream.next_in_index = buffer.rpos();
stream.avail_in = buffer.available();
buffer.wpos(buffer.rpos());
do {
stream.next_out = tmpbuf;
stream.next_out = tempBuf;
stream.next_out_index = 0;
stream.avail_out = BUF_SIZE;
int status = stream.deflate(JZlib.Z_PARTIAL_FLUSH);
switch (status) {
case JZlib.Z_OK:
buffer.putRawBytes(tmpbuf, 0, BUF_SIZE - stream.avail_out);
break;
default:
throw new SSHRuntimeException("compress: deflate returned " + status);
final int status = stream.deflate(JZlib.Z_PARTIAL_FLUSH);
if (status == JZlib.Z_OK) {
buffer.putRawBytes(tempBuf, 0, BUF_SIZE - stream.avail_out);
} else {
throw new SSHRuntimeException("compress: deflate returned " + status);
}
} while (stream.avail_out == 0);
}
public void init(Type type, int level) {
stream = new ZStream();
if (type == Type.Deflater)
stream.deflateInit(level);
else
stream.inflateInit();
}
public boolean isDelayed() {
return false;
}
public void uncompress(SSHPacket from, SSHPacket to)
@Override
public void uncompress(Buffer from, Buffer to)
throws TransportException {
stream.next_in = from.array();
stream.next_in_index = from.rpos();
stream.avail_in = from.available();
while (true) {
stream.next_out = tmpbuf;
stream.next_out = tempBuf;
stream.next_out_index = 0;
stream.avail_out = BUF_SIZE;
int status = stream.inflate(JZlib.Z_PARTIAL_FLUSH);
final int status = stream.inflate(JZlib.Z_PARTIAL_FLUSH);
switch (status) {
case JZlib.Z_OK:
to.putRawBytes(tmpbuf, 0, BUF_SIZE - stream.avail_out);
to.putRawBytes(tempBuf, 0, BUF_SIZE - stream.avail_out);
break;
case JZlib.Z_BUF_ERROR:
return; // wtf.. but this works *head spins*
return;
default:
throw new TransportException(DisconnectReason.COMPRESSION_ERROR, "uncompress: inflate returned "
+ status);

View File

@@ -61,14 +61,17 @@ public class BaseDigest
this.bsize = bsize;
}
@Override
public byte[] digest() {
return md.digest();
}
@Override
public int getBlockSize() {
return bsize;
}
@Override
public void init() {
try {
md = SecurityUtils.getMessageDigest(algorithm);
@@ -77,10 +80,12 @@ public class BaseDigest
}
}
@Override
public void update(byte[] foo) {
update(foo, 0, foo.length);
}
@Override
public void update(byte[] foo, int start, int len) {
md.update(foo, start, len);
}

View File

@@ -43,10 +43,12 @@ public class MD5
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Digest> {
@Override
public Digest create() {
return new MD5();
}
@Override
public String getName() {
return "md5";
}

View File

@@ -43,10 +43,12 @@ public class SHA1
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Digest> {
@Override
public Digest create() {
return new SHA1();
}
@Override
public String getName() {
return "sha1";
}

View File

@@ -50,6 +50,8 @@ import net.schmizz.sshj.transport.digest.SHA1;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
/**
@@ -72,29 +74,33 @@ public abstract class AbstractDHG
private byte[] I_C;
private byte[] e;
private byte[] f;
private byte[] K;
private byte[] H;
private PublicKey hostKey;
@Override
public byte[] getH() {
return ByteArrayUtils.copyOf(H);
}
public Digest getHash() {
return sha;
}
public PublicKey getHostKey() {
return hostKey;
}
@Override
public byte[] getK() {
return ByteArrayUtils.copyOf(K);
}
@Override
public Digest getHash() {
return sha;
}
@Override
public PublicKey getHostKey() {
return hostKey;
}
@Override
public void init(Transport trans, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C)
throws TransportException {
throws GeneralSecurityException, TransportException {
this.trans = trans;
this.V_S = ByteArrayUtils.copyOf(V_S);
this.V_C = ByteArrayUtils.copyOf(V_C);
@@ -108,29 +114,30 @@ public abstract class AbstractDHG
trans.write(new SSHPacket(Message.KEXDH_INIT).putMPInt(e));
}
@Override
public boolean next(Message msg, SSHPacket packet)
throws TransportException {
throws GeneralSecurityException, TransportException {
if (msg != Message.KEXDH_31)
throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, "Unxpected packet: " + msg);
throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, "Unexpected packet: " + msg);
log.info("Received SSH_MSG_KEXDH_REPLY");
final byte[] K_S = packet.readBytes();
f = packet.readMPIntAsBytes();
final byte[] f = packet.readMPIntAsBytes();
final byte[] sig = packet.readBytes(); // signature sent by server
dh.setF(f);
dh.setF(new BigInteger(f));
K = dh.getK();
hostKey = new Buffer.PlainBuffer(K_S).readPublicKey();
final Buffer.PlainBuffer buf = new Buffer.PlainBuffer() // our hash
.putString(V_C) //
.putString(V_S) //
.putString(I_C) //
.putString(I_S) //
.putString(K_S) //
.putMPInt(e) //
.putMPInt(f) //
.putMPInt(K); //
final Buffer.PlainBuffer buf = new Buffer.PlainBuffer()
.putString(V_C)
.putString(V_S)
.putString(I_C)
.putString(I_S)
.putString(K_S)
.putMPInt(e)
.putMPInt(f)
.putMPInt(K);
sha.update(buf.array(), 0, buf.available());
H = sha.digest();
@@ -139,7 +146,8 @@ public abstract class AbstractDHG
signature.init(hostKey, null);
signature.update(H, 0, H.length);
if (!signature.verify(sig))
throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, "KeyExchange signature verification failed");
throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED,
"KeyExchange signature verification failed");
return true;
}

View File

@@ -35,7 +35,6 @@
*/
package net.schmizz.sshj.transport.kex;
import net.schmizz.sshj.common.ByteArrayUtils;
import net.schmizz.sshj.common.SSHRuntimeException;
import net.schmizz.sshj.common.SecurityUtils;
@@ -55,79 +54,53 @@ public class DH {
private BigInteger p;
private BigInteger g;
private BigInteger e; // my public key
private byte[] e_array;
private BigInteger f; // your public key
private BigInteger K; // shared secret key
private byte[] K_array;
private final KeyPairGenerator myKpairGen;
private final KeyAgreement myKeyAgree;
private final KeyPairGenerator generator;
private final KeyAgreement agreement;
public DH() {
try {
myKpairGen = SecurityUtils.getKeyPairGenerator("DH");
myKeyAgree = SecurityUtils.getKeyAgreement("DH");
generator = SecurityUtils.getKeyPairGenerator("DH");
agreement = SecurityUtils.getKeyAgreement("DH");
} catch (GeneralSecurityException e) {
throw new SSHRuntimeException(e);
}
}
public byte[] getE() {
if (e == null) {
DHParameterSpec dhSkipParamSpec = new DHParameterSpec(p, g);
KeyPair myKpair;
try {
myKpairGen.initialize(dhSkipParamSpec);
myKpair = myKpairGen.generateKeyPair();
myKeyAgree.init(myKpair.getPrivate());
} catch (GeneralSecurityException e) {
throw new SSHRuntimeException(e);
}
e = ((javax.crypto.interfaces.DHPublicKey) myKpair.getPublic()).getY();
e_array = e.toByteArray();
}
return ByteArrayUtils.copyOf(e_array);
}
public byte[] getK() {
if (K == null) {
try {
KeyFactory myKeyFac = SecurityUtils.getKeyFactory("DH");
DHPublicKeySpec keySpec = new DHPublicKeySpec(f, p, g);
PublicKey yourPubKey = myKeyFac.generatePublic(keySpec);
myKeyAgree.doPhase(yourPubKey, true);
} catch (GeneralSecurityException e) {
throw new SSHRuntimeException(e);
}
byte[] mySharedSecret = myKeyAgree.generateSecret();
K = new BigInteger(mySharedSecret);
K_array = mySharedSecret;
}
return ByteArrayUtils.copyOf(K_array);
}
public void setF(byte[] f) {
setF(new BigInteger(f));
}
public void setG(byte[] g) {
setG(new BigInteger(g));
}
public void setP(byte[] p) {
setP(new BigInteger(p));
}
void setF(BigInteger f) {
public void setF(BigInteger f) {
this.f = f;
}
void setG(BigInteger g) {
public void setG(BigInteger g) {
this.g = g;
}
void setP(BigInteger p) {
public void setP(BigInteger p) {
this.p = p;
}
public byte[] getE()
throws GeneralSecurityException {
if (e == null) {
generator.initialize(new DHParameterSpec(p, g));
final KeyPair kp = generator.generateKeyPair();
agreement.init(kp.getPrivate());
e = ((javax.crypto.interfaces.DHPublicKey) kp.getPublic()).getY();
}
return e.toByteArray();
}
public byte[] getK()
throws GeneralSecurityException {
if (K == null) {
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("DH");
final DHPublicKeySpec keySpec = new DHPublicKeySpec(f, p, g);
final PublicKey yourPubKey = keyFactory.generatePublic(keySpec);
agreement.doPhase(yourPubKey, true);
K = new BigInteger(agreement.generateSecret());
}
return K.toByteArray();
}
}

View File

@@ -47,10 +47,12 @@ public class DHG1
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<KeyExchange> {
@Override
public KeyExchange create() {
return new DHG1();
}
@Override
public String getName() {
return "diffie-hellman-group1-sha1";
}
@@ -59,8 +61,8 @@ public class DHG1
@Override
protected void initDH(DH dh) {
dh.setG(DHGroupData.getG());
dh.setP(DHGroupData.getP1());
dh.setG(DHGroupData.G);
dh.setP(DHGroupData.P1);
}
}

View File

@@ -48,10 +48,12 @@ public class DHG14
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<KeyExchange> {
@Override
public KeyExchange create() {
return new DHG14();
}
@Override
public String getName() {
return "diffie-hellman-group14-sha1";
}
@@ -60,8 +62,8 @@ public class DHG14
@Override
protected void initDH(DH dh) {
dh.setG(DHGroupData.getG());
dh.setP(DHGroupData.getP14());
dh.setG(DHGroupData.G);
dh.setP(DHGroupData.P14);
}
}

View File

@@ -35,70 +35,28 @@
*/
package net.schmizz.sshj.transport.kex;
import java.math.BigInteger;
/** Simple class holding the data for DH group key exchanges. */
public final class DHGroupData {
public static byte[] getG() {
final byte[] G = {2};
return G;
}
public static final BigInteger G =
new BigInteger("2");
public static byte[] getP1() {
final byte[] P_1 = {(byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
(byte) 0xFF, (byte) 0xFF, (byte) 0xC9, (byte) 0x0F, (byte) 0xDA, (byte) 0xA2, (byte) 0x21, (byte) 0x68,
(byte) 0xC2, (byte) 0x34, (byte) 0xC4, (byte) 0xC6, (byte) 0x62, (byte) 0x8B, (byte) 0x80, (byte) 0xDC,
(byte) 0x1C, (byte) 0xD1, (byte) 0x29, (byte) 0x02, (byte) 0x4E, (byte) 0x08, (byte) 0x8A, (byte) 0x67,
(byte) 0xCC, (byte) 0x74, (byte) 0x02, (byte) 0x0B, (byte) 0xBE, (byte) 0xA6, (byte) 0x3B, (byte) 0x13,
(byte) 0x9B, (byte) 0x22, (byte) 0x51, (byte) 0x4A, (byte) 0x08, (byte) 0x79, (byte) 0x8E, (byte) 0x34,
(byte) 0x04, (byte) 0xDD, (byte) 0xEF, (byte) 0x95, (byte) 0x19, (byte) 0xB3, (byte) 0xCD, (byte) 0x3A,
(byte) 0x43, (byte) 0x1B, (byte) 0x30, (byte) 0x2B, (byte) 0x0A, (byte) 0x6D, (byte) 0xF2, (byte) 0x5F,
(byte) 0x14, (byte) 0x37, (byte) 0x4F, (byte) 0xE1, (byte) 0x35, (byte) 0x6D, (byte) 0x6D, (byte) 0x51,
(byte) 0xC2, (byte) 0x45, (byte) 0xE4, (byte) 0x85, (byte) 0xB5, (byte) 0x76, (byte) 0x62, (byte) 0x5E,
(byte) 0x7E, (byte) 0xC6, (byte) 0xF4, (byte) 0x4C, (byte) 0x42, (byte) 0xE9, (byte) 0xA6, (byte) 0x37,
(byte) 0xED, (byte) 0x6B, (byte) 0x0B, (byte) 0xFF, (byte) 0x5C, (byte) 0xB6, (byte) 0xF4, (byte) 0x06,
(byte) 0xB7, (byte) 0xED, (byte) 0xEE, (byte) 0x38, (byte) 0x6B, (byte) 0xFB, (byte) 0x5A, (byte) 0x89,
(byte) 0x9F, (byte) 0xA5, (byte) 0xAE, (byte) 0x9F, (byte) 0x24, (byte) 0x11, (byte) 0x7C, (byte) 0x4B,
(byte) 0x1F, (byte) 0xE6, (byte) 0x49, (byte) 0x28, (byte) 0x66, (byte) 0x51, (byte) 0xEC, (byte) 0xE6,
(byte) 0x53, (byte) 0x81, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
(byte) 0xFF, (byte) 0xFF};
return P_1;
}
public static final BigInteger P1 =
new BigInteger("1797693134862315907708391567937874531978602960487560117064444236841971802161585193" +
"6894783379586492554150218056548598050364644054819923910005079287700335581663922955" +
"3136239076508735759914822574862575007425302077447712589550957937778424442426617334" +
"727629299387668709205606050270810842907692932019128194467627007");
public static byte[] getP14() {
final byte[] P_14 = {(byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xC9, (byte) 0x0F, (byte) 0xDA, (byte) 0xA2, (byte) 0x21,
(byte) 0x68, (byte) 0xC2, (byte) 0x34, (byte) 0xC4, (byte) 0xC6, (byte) 0x62, (byte) 0x8B, (byte) 0x80,
(byte) 0xDC, (byte) 0x1C, (byte) 0xD1, (byte) 0x29, (byte) 0x02, (byte) 0x4E, (byte) 0x08, (byte) 0x8A,
(byte) 0x67, (byte) 0xCC, (byte) 0x74, (byte) 0x02, (byte) 0x0B, (byte) 0xBE, (byte) 0xA6, (byte) 0x3B,
(byte) 0x13, (byte) 0x9B, (byte) 0x22, (byte) 0x51, (byte) 0x4A, (byte) 0x08, (byte) 0x79, (byte) 0x8E,
(byte) 0x34, (byte) 0x04, (byte) 0xDD, (byte) 0xEF, (byte) 0x95, (byte) 0x19, (byte) 0xB3, (byte) 0xCD,
(byte) 0x3A, (byte) 0x43, (byte) 0x1B, (byte) 0x30, (byte) 0x2B, (byte) 0x0A, (byte) 0x6D, (byte) 0xF2,
(byte) 0x5F, (byte) 0x14, (byte) 0x37, (byte) 0x4F, (byte) 0xE1, (byte) 0x35, (byte) 0x6D, (byte) 0x6D,
(byte) 0x51, (byte) 0xC2, (byte) 0x45, (byte) 0xE4, (byte) 0x85, (byte) 0xB5, (byte) 0x76, (byte) 0x62,
(byte) 0x5E, (byte) 0x7E, (byte) 0xC6, (byte) 0xF4, (byte) 0x4C, (byte) 0x42, (byte) 0xE9, (byte) 0xA6,
(byte) 0x37, (byte) 0xED, (byte) 0x6B, (byte) 0x0B, (byte) 0xFF, (byte) 0x5C, (byte) 0xB6, (byte) 0xF4,
(byte) 0x06, (byte) 0xB7, (byte) 0xED, (byte) 0xEE, (byte) 0x38, (byte) 0x6B, (byte) 0xFB, (byte) 0x5A,
(byte) 0x89, (byte) 0x9F, (byte) 0xA5, (byte) 0xAE, (byte) 0x9F, (byte) 0x24, (byte) 0x11, (byte) 0x7C,
(byte) 0x4B, (byte) 0x1F, (byte) 0xE6, (byte) 0x49, (byte) 0x28, (byte) 0x66, (byte) 0x51, (byte) 0xEC,
(byte) 0xE4, (byte) 0x5B, (byte) 0x3D, (byte) 0xC2, (byte) 0x00, (byte) 0x7C, (byte) 0xB8, (byte) 0xA1,
(byte) 0x63, (byte) 0xBF, (byte) 0x05, (byte) 0x98, (byte) 0xDA, (byte) 0x48, (byte) 0x36, (byte) 0x1C,
(byte) 0x55, (byte) 0xD3, (byte) 0x9A, (byte) 0x69, (byte) 0x16, (byte) 0x3F, (byte) 0xA8, (byte) 0xFD,
(byte) 0x24, (byte) 0xCF, (byte) 0x5F, (byte) 0x83, (byte) 0x65, (byte) 0x5D, (byte) 0x23, (byte) 0xDC,
(byte) 0xA3, (byte) 0xAD, (byte) 0x96, (byte) 0x1C, (byte) 0x62, (byte) 0xF3, (byte) 0x56, (byte) 0x20,
(byte) 0x85, (byte) 0x52, (byte) 0xBB, (byte) 0x9E, (byte) 0xD5, (byte) 0x29, (byte) 0x07, (byte) 0x70,
(byte) 0x96, (byte) 0x96, (byte) 0x6D, (byte) 0x67, (byte) 0x0C, (byte) 0x35, (byte) 0x4E, (byte) 0x4A,
(byte) 0xBC, (byte) 0x98, (byte) 0x04, (byte) 0xF1, (byte) 0x74, (byte) 0x6C, (byte) 0x08, (byte) 0xCA,
(byte) 0x18, (byte) 0x21, (byte) 0x7C, (byte) 0x32, (byte) 0x90, (byte) 0x5E, (byte) 0x46, (byte) 0x2E,
(byte) 0x36, (byte) 0xCE, (byte) 0x3B, (byte) 0xE3, (byte) 0x9E, (byte) 0x77, (byte) 0x2C, (byte) 0x18,
(byte) 0x0E, (byte) 0x86, (byte) 0x03, (byte) 0x9B, (byte) 0x27, (byte) 0x83, (byte) 0xA2, (byte) 0xEC,
(byte) 0x07, (byte) 0xA2, (byte) 0x8F, (byte) 0xB5, (byte) 0xC5, (byte) 0x5D, (byte) 0xF0, (byte) 0x6F,
(byte) 0x4C, (byte) 0x52, (byte) 0xC9, (byte) 0xDE, (byte) 0x2B, (byte) 0xCB, (byte) 0xF6, (byte) 0x95,
(byte) 0x58, (byte) 0x17, (byte) 0x18, (byte) 0x39, (byte) 0x95, (byte) 0x49, (byte) 0x7C, (byte) 0xEA,
(byte) 0x95, (byte) 0x6A, (byte) 0xE5, (byte) 0x15, (byte) 0xD2, (byte) 0x26, (byte) 0x18, (byte) 0x98,
(byte) 0xFA, (byte) 0x05, (byte) 0x10, (byte) 0x15, (byte) 0x72, (byte) 0x8E, (byte) 0x5A, (byte) 0x8A,
(byte) 0xAC, (byte) 0xAA, (byte) 0x68, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
(byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
return P_14;
}
public static final BigInteger P14 =
new BigInteger("3231700607131100730033891392642382824881794124114023911284200975140074170663435422" +
"2619689417363569347117901737909704191754605873209195028853758986185622153212175412" +
"5149017745202702357960782362488842461894775876411059286460994117232454266225221932" +
"3054091903768052423551912567971587011700105805587765103886184728025797605490356973" +
"2561526167081339361799541336476559160368317896729073178384589680639671900977202194" +
"1686472258710314113364293195361934716365332097170774482279885885653692086452966360" +
"7725026895550592836275112117409697299806841055435958486658329164213621823107899099" +
"9448652468262416972035911852507045361090559");
}

View File

@@ -41,14 +41,33 @@ import net.schmizz.sshj.transport.Transport;
import net.schmizz.sshj.transport.TransportException;
import net.schmizz.sshj.transport.digest.Digest;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
/** Key exchange algorithm. */
public interface KeyExchange {
/**
* Initialize the key exchange algorithm.
*
* @param trans the transport
* @param V_S the server identification string
* @param V_C the client identification string
* @param I_S the server key init packet
* @param I_C the client key init packet
*
* @throws GeneralSecurityException
* @throws TransportException if there is an error sending a packet
*/
void init(Transport trans, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C)
throws GeneralSecurityException, TransportException;
/** @return the computed H parameter */
byte[] getH();
/** @return the computed K parameter */
byte[] getK();
/**
* The message digest used by this key exchange algorithm.
*
@@ -59,23 +78,6 @@ public interface KeyExchange {
/** @return the host key determined from server's response packets */
PublicKey getHostKey();
/** @return the computed K parameter */
byte[] getK();
/**
* Initialize the key exchange algorithm.
*
* @param trans the transport
* @param V_S the server identification string
* @param V_C the client identification string
* @param I_S the server key init packet
* @param I_C the client key init packet
*
* @throws TransportException if there is an error sending a packet
*/
void init(Transport trans, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C)
throws TransportException;
/**
* Process the next packet
*
@@ -84,9 +86,10 @@ public interface KeyExchange {
*
* @return a boolean indicating if the processing is complete or if more packets are to be received
*
* @throws TransportException if there is an error sending a packet
* @throws GeneralSecurityException
* @throws TransportException if there is an error sending a packet
*/
boolean next(Message msg, SSHPacket buffer)
throws TransportException;
throws GeneralSecurityException, TransportException;
}

View File

@@ -59,14 +59,17 @@ public class BaseMAC
tmp = new byte[defbsize];
}
@Override
public byte[] doFinal() {
return mac.doFinal();
}
@Override
public byte[] doFinal(byte[] input) {
return mac.doFinal(input);
}
@Override
public void doFinal(byte[] buf, int offset) {
try {
if (bsize != defbsize) {
@@ -79,10 +82,12 @@ public class BaseMAC
}
}
@Override
public int getBlockSize() {
return bsize;
}
@Override
public void init(byte[] key) {
if (key.length > defbsize) {
byte[] tmp = new byte[defbsize];
@@ -99,14 +104,17 @@ public class BaseMAC
}
}
@Override
public void update(byte foo[], int s, int l) {
mac.update(foo, s, l);
}
@Override
public void update(byte[] foo) {
mac.update(foo, 0, foo.length);
}
@Override
public void update(long i) {
tmp[0] = (byte) (i >>> 24);
tmp[1] = (byte) (i >>> 16);

View File

@@ -43,10 +43,12 @@ public class HMACMD5
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<MAC> {
@Override
public MAC create() {
return new HMACMD5();
}
@Override
public String getName() {
return "hmac-md5";
}

View File

@@ -43,10 +43,12 @@ public class HMACMD596
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<MAC> {
@Override
public MAC create() {
return new HMACMD596();
}
@Override
public String getName() {
return "hmac-md5-96";
}

View File

@@ -43,10 +43,12 @@ public class HMACSHA1
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<MAC> {
@Override
public MAC create() {
return new HMACSHA1();
}
@Override
public String getName() {
return "hmac-sha1";
}

View File

@@ -43,10 +43,12 @@ public class HMACSHA196
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<MAC> {
@Override
public MAC create() {
return new HMACSHA196();
}
@Override
public String getName() {
return "hmac-sha1-96";
}

View File

@@ -51,6 +51,7 @@ public class BouncyCastleRandom
public static class Factory
implements net.schmizz.sshj.common.Factory<Random> {
@Override
public Random create() {
return new BouncyCastleRandom();
}
@@ -65,6 +66,7 @@ public class BouncyCastleRandom
random.addSeedMaterial(seed);
}
@Override
public void fill(byte[] bytes, int start, int len) {
random.nextBytes(bytes, start, len);
}

View File

@@ -45,10 +45,12 @@ public class JCERandom
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Random> {
@Override
public Random create() {
return new JCERandom();
}
@Override
public String getName() {
return "default";
}
@@ -69,6 +71,7 @@ public class JCERandom
* @param start the offset to start at
* @param len the number of bytes to fill
*/
@Override
public synchronized void fill(byte[] foo, int start, int len) {
if (start == 0 && len == foo.length)
random.nextBytes(foo);

View File

@@ -46,10 +46,12 @@ public class SingletonRandomFactory
random = factory.create();
}
@Override
public Random create() {
return this;
}
@Override
public void fill(byte[] bytes, int start, int len) {
random.fill(bytes, start, len);
}

View File

@@ -60,8 +60,7 @@ public class ConsoleKnownHostsVerifier
}
@Override
protected boolean hostKeyChangedAction(Entry entry, String hostname, PublicKey key)
throws IOException {
protected boolean hostKeyChangedAction(Entry entry, String hostname, PublicKey key) {
final KeyType type = KeyType.fromKey(key);
final String fp = SecurityUtils.getFingerprint(key);
final String path = getFile().getAbsolutePath();

View File

@@ -131,6 +131,7 @@ public class OpenSSHKnownHosts
init(parts[1], parts[2]);
}
@Override
public boolean appliesTo(String host) {
for (String h : hosts)
if (host.equals(h))
@@ -138,6 +139,7 @@ public class OpenSSHKnownHosts
return false;
}
@Override
protected String getHostPart() {
final StringBuilder sb = new StringBuilder();
for (String host : hosts) {
@@ -185,6 +187,7 @@ public class OpenSSHKnownHosts
init(parts[1], parts[2]);
}
@Override
public boolean appliesTo(String host)
throws IOException {
return hashedHost.equals(hashHost(host));
@@ -204,14 +207,14 @@ public class OpenSSHKnownHosts
return saltyBytes;
}
private String getSalt()
throws IOException {
private String getSalt() {
if (salt == null) {
salt = Base64.encodeBytes(saltyBytes);
}
return salt;
}
@Override
protected String getHostPart() {
return hashedHost;
}
@@ -247,6 +250,7 @@ public class OpenSSHKnownHosts
return khFile;
}
@Override
public boolean verify(final String hostname, final int port, final PublicKey key) {
final KeyType type = KeyType.fromKey(key);
if (type == KeyType.UNKNOWN)
@@ -269,8 +273,7 @@ public class OpenSSHKnownHosts
return false;
}
protected boolean hostKeyChangedAction(Entry entry, String hostname, PublicKey key)
throws IOException {
protected boolean hostKeyChangedAction(Entry entry, String hostname, PublicKey key) {
log.warn("Host key for `{}` has changed!", hostname);
return false;
}

View File

@@ -20,6 +20,7 @@ import java.security.PublicKey;
public final class PromiscuousVerifier
implements HostKeyVerifier {
@Override
public boolean verify(String hostname, int port, PublicKey key) {
return true;
}

View File

@@ -25,6 +25,7 @@ public class UserAuthException
public static final ExceptionChainer<UserAuthException> chainer = new ExceptionChainer<UserAuthException>() {
@Override
public UserAuthException chain(Throwable t) {
if (t instanceof UserAuthException)
return (UserAuthException) t;

View File

@@ -59,6 +59,7 @@ public class UserAuthImpl
// synchronized for mutual exclusion; ensure one authenticate() ever in progress
@Override
public synchronized void authenticate(String username, Service nextService, Iterable<AuthMethod> methods)
throws UserAuthException, TransportException {
clearState();
@@ -108,14 +109,17 @@ public class UserAuthImpl
throw new UserAuthException("Exhausted available authentication methods", savedEx.peek());
}
@Override
public String getBanner() {
return banner;
}
@Override
public String getNextServiceName() {
return nextService.getName();
}
@Override
public Transport getTransport() {
return trans;
}
@@ -126,14 +130,17 @@ public class UserAuthImpl
*
* @return deque of saved exceptions
*/
@Override
public Deque<UserAuthException> getSavedExceptions() {
return savedEx;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean hadPartialSuccess() {
return partialSuccess;
}

View File

@@ -12,26 +12,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file may incorporate work covered by the following copyright and
* permission notice:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package net.schmizz.sshj.userauth.keyprovider;

View File

@@ -12,26 +12,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file may incorporate work covered by the following copyright and
* permission notice:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package net.schmizz.sshj.userauth.keyprovider;
@@ -57,14 +37,17 @@ public class KeyPairWrapper
this(new KeyPair(publicKey, privateKey));
}
@Override
public PrivateKey getPrivate() {
return kp.getPrivate();
}
@Override
public PublicKey getPublic() {
return kp.getPublic();
}
@Override
public KeyType getType() {
return type;
}

View File

@@ -38,10 +38,12 @@ public class OpenSSHKeyFile
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
@Override
public FileKeyProvider create() {
return new OpenSSHKeyFile();
}
@Override
public String getName() {
return "OpenSSH";
}

View File

@@ -20,7 +20,6 @@ import net.schmizz.sshj.common.KeyType;
import net.schmizz.sshj.userauth.password.PasswordFinder;
import net.schmizz.sshj.userauth.password.PasswordUtils;
import net.schmizz.sshj.userauth.password.PrivateKeyFileResource;
import net.schmizz.sshj.userauth.password.Resource;
import org.bouncycastle.openssl.EncryptionException;
import org.bouncycastle.openssl.PEMReader;
import org.slf4j.Logger;
@@ -40,10 +39,12 @@ public class PKCS8KeyFile
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
@Override
public FileKeyProvider create() {
return new PKCS8KeyFile();
}
@Override
public String getName() {
return "PKCS8";
}
@@ -51,35 +52,38 @@ public class PKCS8KeyFile
protected final Logger log = LoggerFactory.getLogger(getClass());
protected PasswordFinder pwdf;
protected File location;
protected Resource resource;
protected PrivateKeyFileResource resource;
protected KeyPair kp;
protected KeyType type;
protected char[] passphrase; // for blanking out
@Override
public PrivateKey getPrivate()
throws IOException {
return kp != null ? kp.getPrivate() : (kp = readKeyPair()).getPrivate();
}
@Override
public PublicKey getPublic()
throws IOException {
return kp != null ? kp.getPublic() : (kp = readKeyPair()).getPublic();
}
@Override
public KeyType getType()
throws IOException {
return type != null ? type : (type = KeyType.fromKey(getPublic()));
}
@Override
public void init(File location) {
assert location != null;
this.location = location;
resource = new PrivateKeyFileResource(location.getAbsolutePath());
resource = new PrivateKeyFileResource(location.getAbsoluteFile());
}
@Override
public void init(File location, PasswordFinder pwdf) {
init(location);
this.pwdf = pwdf;
@@ -90,6 +94,7 @@ public class PKCS8KeyFile
return null;
else
return new org.bouncycastle.openssl.PasswordFinder() {
@Override
public char[] getPassword() {
return passphrase = pwdf.reqPassword(resource);
}
@@ -106,7 +111,7 @@ public class PKCS8KeyFile
for (; ;) {
// while the PasswordFinder tells us we should retry
try {
r = new PEMReader(new InputStreamReader(new FileInputStream(location)), pFinder);
r = new PEMReader(new InputStreamReader(new FileInputStream(resource.getDetail())), pFinder);
o = r.readObject();
} catch (EncryptionException e) {
if (pwdf.shouldRetry(resource))
@@ -123,7 +128,7 @@ public class PKCS8KeyFile
}
if (o == null)
throw new IOException("Could not read key pair from: " + location);
throw new IOException("Could not read key pair from: " + resource);
if (o instanceof KeyPair)
kp = (KeyPair) o;
else
@@ -131,4 +136,8 @@ public class PKCS8KeyFile
return kp;
}
@Override
public String toString() {
return "PKCS8KeyFile{resource=" + resource + "}";
}
}

Some files were not shown because too many files have changed in this diff Show More