You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2018/11/18 09:32:59 UTC

[1/5] mina-sshd git commit: Add more detailed information about file upload/download when using 'get/put' in SftpCommandMain with verbose flag set

Repository: mina-sshd
Updated Branches:
  refs/heads/master a6dffd5ac -> e88a08326


Add more detailed information about file upload/download when using 'get/put' in SftpCommandMain with verbose flag set


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/e88a0832
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/e88a0832
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/e88a0832

Branch: refs/heads/master
Commit: e88a08326716e1ebbe693ede3e4e7258b810ff07
Parents: bd40cd0
Author: Lyor Goldstein <lg...@apache.org>
Authored: Sun Nov 18 11:32:27 2018 +0200
Committer: Lyor Goldstein <lg...@apache.org>
Committed: Sun Nov 18 11:32:53 2018 +0200

----------------------------------------------------------------------
 .../apache/sshd/cli/client/SftpCommandMain.java | 32 +++++++++++++++-----
 1 file changed, 25 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e88a0832/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java
----------------------------------------------------------------------
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java
index 694d937..b147267 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java
@@ -39,6 +39,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.ServiceLoader;
 import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
 import java.util.logging.Level;
 
 import org.apache.sshd.cli.client.helper.SftpFileTransferProgressOutputStream;
@@ -881,7 +882,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
             super();
         }
 
-        protected void createDirectories(SftpClient sftp, String remotePath) throws IOException {
+        protected void createDirectories(
+                SftpClient sftp, String remotePath, PrintStream stdout, boolean verbose)
+                    throws IOException {
             try {
                 Attributes attrs = sftp.stat(remotePath);
                 ValidateUtils.checkTrue(attrs.isDirectory(), "Remote path already exists but is not a directory: %s", remotePath);
@@ -893,7 +896,7 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
 
             int pos = remotePath.lastIndexOf('/');
             ValidateUtils.checkTrue(pos > 0, "No more parents for %s", remotePath);
-            createDirectories(sftp, remotePath.substring(0, pos));
+            createDirectories(sftp, remotePath.substring(0, pos), stdout, verbose);
         }
 
         protected void transferFile(
@@ -903,13 +906,27 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
             if (upload) {
                 int pos = remotePath.lastIndexOf('/');
                 ValidateUtils.checkTrue(pos > 0, "Missing full remote file path: %s", remotePath);
-                createDirectories(sftp, remotePath.substring(0, pos));
+                createDirectories(sftp, remotePath.substring(0, pos), stdout, verbose);
+
+                if (verbose) {
+                    stdout.append("    Uploading ").append(Long.toString(Files.size(localPath)))
+                        .append(" bytes from ").append(localPath.toString())
+                        .append(" to ").println(remotePath);
+                }
             } else {
                 Files.createDirectories(localPath.getParent());
+
+                if (verbose) {
+                    Attributes attrs = sftp.stat(remotePath);
+                    stdout.append("    Downloading ").append(Long.toString(attrs.getSize()))
+                        .append(" bytes from ").append(remotePath)
+                        .append(" to ").println(localPath);
+                }
             }
 
             boolean withProgress = isShowProgress();
             long copySize;
+            long startTime = System.currentTimeMillis();
             try (InputStream input = upload ? Files.newInputStream(localPath) : sftp.read(remotePath);
                  OutputStream target = upload ? sftp.write(remotePath) : Files.newOutputStream(localPath);
                  OutputStream output = withProgress ? new SftpFileTransferProgressOutputStream(target, stdout) : target) {
@@ -925,9 +942,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
             }
 
             if (verbose) {
-                stdout.append("    ")
-                  .append("Copied ").append(Long.toString(copySize)).append(" bytes")
-                  .append(" from ").append(upload ? localPath.toString() : remotePath)
+                stdout.append("    Copied ").append(Long.toString(copySize)).append(" bytes")
+                  .append(" in ").append(Long.toString(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - startTime)))
+                  .append(" seconds from ").append(upload ? localPath.toString() : remotePath)
                   .append(" to ").println(upload ? remotePath : localPath.toString());
             }
         }
@@ -959,7 +976,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
             if (Files.isDirectory(localPath)) {
                 try (DirectoryStream<Path> ds = Files.newDirectoryStream(localPath)) {
                     for (Path entry : ds) {
-                        String name = entry.getFileName().toString();
+                        Path fileName = entry.getFileName();
+                        String name = fileName.toString();
                         transferLocalDir(sftp, localPath.resolve(name), remotePath + "/" + name, stdout, verbose);
                     }
                 }


[4/5] mina-sshd git commit: Added SftpCommandMain upload/download marker progress indication (default=true)

Posted by lg...@apache.org.
Added SftpCommandMain upload/download marker progress indication (default=true)


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/bd40cd0c
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/bd40cd0c
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/bd40cd0c

Branch: refs/heads/master
Commit: bd40cd0c70866ec4543b61cbf87c57296296019b
Parents: 1a8924d
Author: Lyor Goldstein <lg...@apache.org>
Authored: Sun Nov 18 11:12:28 2018 +0200
Committer: Lyor Goldstein <lg...@apache.org>
Committed: Sun Nov 18 11:32:53 2018 +0200

----------------------------------------------------------------------
 CHANGES.md                                      |  14 ++
 .../apache/sshd/cli/client/SftpCommandMain.java | 201 ++++++++++++++-----
 .../SftpFileTransferProgressOutputStream.java   | 129 ++++++++++++
 3 files changed, 297 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/bd40cd0c/CHANGES.md
----------------------------------------------------------------------
diff --git a/CHANGES.md b/CHANGES.md
index e79d215..60f941b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -88,3 +88,17 @@ in order to provide key file(s) location information
 
 * [SSHD-866](https://issues.apache.org/jira/browse/SSHD-866) - Counting empty challenges separately when enforcing
 max. attempts during `keyboard-interactive` authentication
+
+* `SftpCommandMain` shows by default `get/put` command progress using the hash sign (`#`) marker. The marker
+can be enabled/disabled via the `progress` command:
+
+```
+    > progress
+
+    ... reponse is whether it is 'on' or 'off'
+
+    > progress on/off
+
+    ... set the progress marker indicator  ...
+
+```

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/bd40cd0c/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java
----------------------------------------------------------------------
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java
index 99427ff..694d937 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java
@@ -41,6 +41,7 @@ import java.util.ServiceLoader;
 import java.util.TreeMap;
 import java.util.logging.Level;
 
+import org.apache.sshd.cli.client.helper.SftpFileTransferProgressOutputStream;
 import org.apache.sshd.client.ClientFactoryManager;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.client.subsystem.sftp.SftpClient;
@@ -89,6 +90,7 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
     private final Map<String, SftpCommandExecutor> commandsMap;
     private String cwdRemote;
     private String cwdLocal;
+    private boolean showProgress = true;
 
     public SftpCommandMain(SftpClient client) {
         this.client = Objects.requireNonNull(client, "No client");
@@ -113,6 +115,7 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
                 new StatVfsCommandExecutor(),
                 new GetCommandExecutor(),
                 new PutCommandExecutor(),
+                new ProgressCommandExecutor(),
                 new HelpCommandExecutor()
         )) {
             String name = e.getName();
@@ -205,9 +208,11 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
     }
 
-    protected <A extends Appendable> A appendFileAttributes(A stdout, SftpClient sftp, String path, Attributes attrs) throws IOException {
-        stdout.append('\t').append(Long.toString(attrs.getSize()))
-              .append('\t').append(SftpFileSystemProvider.getRWXPermissions(attrs.getPermissions()));
+    protected <A extends Appendable> A appendFileAttributes(
+            A stdout, SftpClient sftp, String path, Attributes attrs)
+                throws IOException {
+        stdout.append("    ").append(Long.toString(attrs.getSize()))
+              .append("    ").append(SftpFileSystemProvider.getRWXPermissions(attrs.getPermissions()));
         if (attrs.isSymbolicLink()) {
             String linkValue = sftp.readLink(path);
             stdout.append(" => ")
@@ -234,6 +239,14 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         cwdLocal = path;
     }
 
+    public boolean isShowProgress() {
+        return showProgress;
+    }
+
+    public void setShowProgress(boolean showProgress) {
+        this.showProgress = showProgress;
+    }
+
     @Override
     public boolean isOpen() {
         return client.isOpen();
@@ -249,7 +262,7 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
     //////////////////////////////////////////////////////////////////////////
 
     public static <A extends Appendable> A appendInfoValue(A sb, CharSequence name, Object value) throws IOException {
-        sb.append('\t').append(name).append(": ").append(Objects.toString(value));
+        sb.append("    ").append(name).append(": ").append(Objects.toString(value));
         return sb;
     }
 
@@ -309,7 +322,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
                 setupLogging(level, stdout, stderr, logStream);
             }
 
-            ClientSession session = (logStream == null) ? null : setupClientSession(SFTP_PORT_OPTION, stdin, stdout, stderr, args);
+            ClientSession session = (logStream == null)
+                ? null
+                : setupClientSession(SFTP_PORT_OPTION, stdin, stdout, stderr, args);
             if (session == null) {
                 System.err.println("usage: sftp [-v[v][v]] [-E logoutput] [-i identity] [-io nio2|mina|netty]"
                         + " [-l login] [" + SFTP_PORT_OPTION + " port] [-o option=value]"
@@ -347,7 +362,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args);
             stdout.println("Exiting");
             return true;
@@ -365,10 +382,12 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args);
-            stdout.append('\t').append("Remote: ").println(getCurrentRemoteDirectory());
-            stdout.append('\t').append("Local: ").println(getCurrentLocalDirectory());
+            stdout.append("    ").append("Remote: ").println(getCurrentRemoteDirectory());
+            stdout.append("    ").append("Local: ").println(getCurrentLocalDirectory());
             return false;
         }
     }
@@ -384,7 +403,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args);
             SftpClient sftp = getClient();
             ClientSession session = sftp.getSession();
@@ -414,7 +435,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args);
             SftpClient sftp = getClient();
             ClientSession session = sftp.getSession();
@@ -442,11 +465,13 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args);
             SftpClient sftp = getClient();
             Session session = sftp.getSession();
-            stdout.append('\t').println(session.getServerVersion());
+            stdout.append("    ").println(session.getServerVersion());
 
             Map<String, byte[]> extensions = sftp.getServerExtensions();
             Map<String, ?> parsed = ParserUtils.parse(extensions);
@@ -457,7 +482,7 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
             extensions.forEach((name, value) -> {
                 Object info = parsed.get(name);
 
-                stdout.append('\t').append(name).append(": ");
+                stdout.append("    ").append(name).append(": ");
                 if (info == null) {
                     stdout.println(BufferUtils.toHex(value));
                 } else {
@@ -480,10 +505,12 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args);
             SftpClient sftp = getClient();
-            stdout.append('\t').println(sftp.getVersion());
+            stdout.append("    ").println(sftp.getVersion());
             return false;
         }
     }
@@ -499,7 +526,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             ValidateUtils.checkNotNullAndNotEmpty(args, "No remote directory specified");
 
             String newPath = resolveRemotePath(args);
@@ -520,7 +549,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             if (GenericUtils.isEmpty(args)) {
                 setCurrentLocalDirectory(System.getProperty("user.home"));
             } else {
@@ -545,7 +576,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             ValidateUtils.checkNotNullAndNotEmpty(args, "No remote directory specified");
 
             String path = resolveRemotePath(args);
@@ -566,7 +599,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             String[] comps = GenericUtils.split(args, ' ');
             int numComps = GenericUtils.length(comps);
             String pathArg = (numComps <= 0) ? null : GenericUtils.trimToEmpty(comps[numComps - 1]);
@@ -584,7 +619,7 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
             for (SftpClient.DirEntry entry : sftp.readDir(path)) {
                 String fileName = entry.getFilename();
                 SftpClient.Attributes attrs = entry.getAttributes();
-                appendFileAttributes(stdout.append('\t').append(fileName), sftp, path + "/" + fileName, attrs).println();
+                appendFileAttributes(stdout.append("    ").append(fileName), sftp, path + "/" + fileName, attrs).println();
                 if (showLongName) {
                     stdout.append("\t\tlong-name: ").println(entry.getLongFilename());
                 }
@@ -605,7 +640,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             String[] comps = GenericUtils.split(args, ' ');
             int numArgs = GenericUtils.length(comps);
             ValidateUtils.checkTrue(numArgs >= 1, "No arguments");
@@ -643,14 +680,16 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
             } else {
                 sftp.remove(path);
                 if (verbose) {
-                    stdout.append('\t').append("Removed ").println(path);
+                    stdout.append("    ").append("Removed ").println(path);
                 }
             }
 
             return false;
         }
 
-        private void removeRecursive(SftpClient sftp, String path, Attributes attrs, PrintStream stdout, boolean verbose) throws IOException {
+        private void removeRecursive(
+                SftpClient sftp, String path, Attributes attrs, PrintStream stdout, boolean verbose)
+                    throws IOException {
             if (attrs.isDirectory()) {
                 for (DirEntry entry : sftp.readDir(path)) {
                     String name = entry.getFilename();
@@ -666,13 +705,13 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
                 sftp.remove(path);
             } else {
                 if (verbose) {
-                    stdout.append('\t').append("Skip special file ").println(path);
+                    stdout.append("    ").append("Skip special file ").println(path);
                     return;
                 }
             }
 
             if (verbose) {
-                stdout.append('\t').append("Removed ").println(path);
+                stdout.append("    ").append("Removed ").println(path);
             }
         }
     }
@@ -688,7 +727,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             ValidateUtils.checkNotNullAndNotEmpty(args, "No remote directory specified");
 
             String path = resolveRemotePath(args);
@@ -709,7 +750,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             String[] comps = GenericUtils.split(args, ' ');
             ValidateUtils.checkTrue(GenericUtils.length(comps) == 2, "Invalid number of arguments: %s", args);
 
@@ -732,7 +775,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             String[] comps = GenericUtils.split(args, ' ');
             int numArgs = GenericUtils.length(comps);
             ValidateUtils.checkTrue(numArgs <= 1, "Invalid number of arguments: %s", args);
@@ -741,7 +786,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
             OpenSSHStatPathExtension ext = sftp.getExtension(OpenSSHStatPathExtension.class);
             ValidateUtils.checkTrue(ext.isSupported(), "Extension not supported by server: %s", ext.getName());
 
-            String remPath = resolveRemotePath((numArgs >= 1) ? GenericUtils.trimToEmpty(comps[0]) :  GenericUtils.trimToEmpty(args));
+            String remPath = resolveRemotePath(
+                (numArgs >= 1) ? GenericUtils.trimToEmpty(comps[0]) :  GenericUtils.trimToEmpty(args));
             OpenSSHStatExtensionInfo info = ext.stat(remPath);
             Field[] fields = info.getClass().getFields();
             for (Field f : fields) {
@@ -752,7 +798,7 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
                 }
 
                 Object value = f.get(info);
-                stdout.append('\t').append(name).append(": ").println(value);
+                stdout.append("    ").append(name).append(": ").println(value);
             }
 
             return false;
@@ -770,7 +816,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             String[] comps = GenericUtils.split(args, ' ');
             ValidateUtils.checkTrue(GenericUtils.length(comps) <= 1, "Invalid number of arguments: %s", args);
 
@@ -800,7 +848,7 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
             String path = GenericUtils.trimToEmpty(resolveRemotePath(args));
             SftpClient client = getClient();
             String linkData = client.readLink(path);
-            stdout.append('\t').println(linkData);
+            stdout.append("    ").println(linkData);
             return false;
         }
     }
@@ -817,10 +865,12 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
 
         @Override
         @SuppressWarnings("synthetic-access")
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args);
             for (String cmd : commandsMap.keySet()) {
-                stdout.append('\t').println(cmd);
+                stdout.append("    ").println(cmd);
             }
             return false;
         }
@@ -846,7 +896,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
             createDirectories(sftp, remotePath.substring(0, pos));
         }
 
-        protected void transferFile(SftpClient sftp, Path localPath, String remotePath, boolean upload, PrintStream stdout, boolean verbose) throws IOException {
+        protected void transferFile(
+                SftpClient sftp, Path localPath, String remotePath, boolean upload, PrintStream stdout, boolean verbose)
+                    throws IOException {
             // Create the file's hierarchy
             if (upload) {
                 int pos = remotePath.lastIndexOf('/');
@@ -856,19 +908,33 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
                 Files.createDirectories(localPath.getParent());
             }
 
+            boolean withProgress = isShowProgress();
+            long copySize;
             try (InputStream input = upload ? Files.newInputStream(localPath) : sftp.read(remotePath);
-                 OutputStream output = upload ? sftp.write(remotePath) : Files.newOutputStream(localPath)) {
-                IoUtils.copy(input, output, SftpClient.IO_BUFFER_SIZE);
+                 OutputStream target = upload ? sftp.write(remotePath) : Files.newOutputStream(localPath);
+                 OutputStream output = withProgress ? new SftpFileTransferProgressOutputStream(target, stdout) : target) {
+                if (withProgress) {
+                    stdout.println();
+                }
+
+                copySize = IoUtils.copy(input, output, SftpClient.IO_BUFFER_SIZE);
+
+                if (withProgress) {
+                    stdout.println();
+                }
             }
 
             if (verbose) {
-                stdout.append('\t')
-                      .append("Copied ").append(upload ? localPath.toString() : remotePath)
-                      .append(" to ").println(upload ? remotePath : localPath.toString());
+                stdout.append("    ")
+                  .append("Copied ").append(Long.toString(copySize)).append(" bytes")
+                  .append(" from ").append(upload ? localPath.toString() : remotePath)
+                  .append(" to ").println(upload ? remotePath : localPath.toString());
             }
         }
 
-        protected void transferRemoteDir(SftpClient sftp, Path localPath, String remotePath, Attributes attrs, PrintStream stdout, boolean verbose) throws IOException {
+        protected void transferRemoteDir(
+                SftpClient sftp, Path localPath, String remotePath, Attributes attrs, PrintStream stdout, boolean verbose)
+                    throws IOException {
             if (attrs.isDirectory()) {
                 for (DirEntry entry : sftp.readDir(remotePath)) {
                     String name = entry.getFilename();
@@ -882,12 +948,14 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
                 transferFile(sftp, localPath, remotePath, false, stdout, verbose);
             } else {
                 if (verbose) {
-                    stdout.append('\t').append("Skip remote special file ").println(remotePath);
+                    stdout.append("    ").append("Skip remote special file ").println(remotePath);
                 }
             }
         }
 
-        protected void transferLocalDir(SftpClient sftp, Path localPath, String remotePath, PrintStream stdout, boolean verbose) throws IOException {
+        protected void transferLocalDir(
+                SftpClient sftp, Path localPath, String remotePath, PrintStream stdout, boolean verbose)
+                    throws IOException {
             if (Files.isDirectory(localPath)) {
                 try (DirectoryStream<Path> ds = Files.newDirectoryStream(localPath)) {
                     for (Path entry : ds) {
@@ -899,7 +967,7 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
                 transferFile(sftp, localPath, remotePath, true, stdout, verbose);
             } else {
                 if (verbose) {
-                    stdout.append('\t').append("Skip local special file ").println(localPath);
+                    stdout.append("    ").append("Skip local special file ").println(localPath);
                 }
             }
         }
@@ -980,7 +1048,9 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             executeCommand(args, false, stdout);
             return false;
         }
@@ -997,9 +1067,46 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
         }
 
         @Override
-        public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
             executeCommand(args, true, stdout);
             return false;
         }
     }
+
+    private class ProgressCommandExecutor implements SftpCommandExecutor {
+        ProgressCommandExecutor() {
+            super();
+        }
+
+        @Override
+        public String getName() {
+            return "progress";
+        }
+
+        @Override
+        public boolean executeCommand(
+                String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+                    throws Exception {
+            String[] comps = GenericUtils.split(args, ' ');
+            int numArgs = GenericUtils.length(comps);
+            if (numArgs <= 0) {
+                stdout.append("    ").append(getName()).append(' ').println(isShowProgress() ? "on" : "off");
+            } else {
+                ValidateUtils.checkTrue(numArgs == 1, "Invalid arguments count: %d", numArgs);
+
+                String argVal = comps[0];
+                if ("on".equalsIgnoreCase(argVal)) {
+                    setShowProgress(true);
+                } else if ("off".equalsIgnoreCase(argVal)) {
+                    setShowProgress(false);
+                } else {
+                    throw new IllegalArgumentException("Unknown value: " + argVal);
+                }
+            }
+
+            return false;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/bd40cd0c/sshd-cli/src/main/java/org/apache/sshd/cli/client/helper/SftpFileTransferProgressOutputStream.java
----------------------------------------------------------------------
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/client/helper/SftpFileTransferProgressOutputStream.java b/sshd-cli/src/main/java/org/apache/sshd/cli/client/helper/SftpFileTransferProgressOutputStream.java
new file mode 100644
index 0000000..26330bc
--- /dev/null
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/client/helper/SftpFileTransferProgressOutputStream.java
@@ -0,0 +1,129 @@
+/*
+ * 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 org.apache.sshd.cli.client.helper;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StreamCorruptedException;
+import java.util.Objects;
+
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SftpFileTransferProgressOutputStream extends FilterOutputStream {
+    public static final char DEFAULT_PROGRESS_CHAR = '#';
+    public static final int DEFAULT_MARKS_PER_LINE = 72;
+    public static final int DEFAULT_MARKER_SIZE = IoUtils.DEFAULT_COPY_SIZE;
+
+    private final int markerSize;
+    private final char markerChar;
+    private final int markersPerLine;
+    private final Appendable stdout;
+    private final byte[] workBuf = {0};
+    private long byteCount;
+    private long lastMarkOffset;
+    private int curMarkersInLine;
+
+    public SftpFileTransferProgressOutputStream(OutputStream out, Appendable stdout) {
+        this(out, DEFAULT_MARKER_SIZE, DEFAULT_PROGRESS_CHAR, DEFAULT_MARKS_PER_LINE, stdout);
+    }
+
+    public SftpFileTransferProgressOutputStream(
+            OutputStream out, int markerSize, char markerChar, int markersPerLine, Appendable stdout) {
+        super(Objects.requireNonNull(out, "No target stream"));
+
+        ValidateUtils.checkTrue(markerSize > 0, "Invalid marker size: %d", markerSize);
+        this.markerSize = markerSize;
+
+        if ((markerChar <= ' ') || (markerChar > 0x7E)) {
+            throw new IllegalArgumentException("Non-printable marker character: 0x" + Integer.toHexString(markerChar));
+        }
+        this.markerChar = markerChar;
+
+        ValidateUtils.checkTrue(markersPerLine > 0, "Invalid markers per line: %d", markersPerLine);
+
+        this.markersPerLine = markersPerLine;
+        this.stdout = Objects.requireNonNull(stdout, "No progress report target");
+    }
+
+    public int getMarkerSize() {
+        return markerSize;
+    }
+
+    public char getMarkerChar() {
+        return markerChar;
+    }
+
+    public int getMarkersPerLine() {
+        return markersPerLine;
+    }
+
+    public Appendable getStdout() {
+        return stdout;
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        workBuf[0] = (byte) (b & 0xFF);
+        write(workBuf, 0, 1);
+    }
+
+    @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 {
+        if ((len < 0) || (off < 0)) {
+            throw new StreamCorruptedException("Invalid offset (" + off + ")/length(" + len + ")");
+        }
+        this.out.write(b, off, len);
+
+        byteCount += len;
+
+        long reportDiff = byteCount - lastMarkOffset;
+        int reportSize = getMarkerSize();
+        long markersCount = reportDiff / reportSize;
+        appendMarkers((int) markersCount);
+        lastMarkOffset += markersCount * reportSize;
+    }
+
+    protected void appendMarkers(int markersCount) throws IOException {
+        if (markersCount <= 0) {
+            return;
+        }
+
+        Appendable target = getStdout();
+        char marker = getMarkerChar();
+        for (int index = 1, limit = getMarkersPerLine(); index <= markersCount; index++) {
+            target.append(marker);
+            curMarkersInLine++;
+            if (curMarkersInLine >= limit) {
+                target.append(System.lineSeparator());
+                curMarkersInLine = 0;
+            }
+        }
+    }
+}


[5/5] mina-sshd git commit: [SSHD-868] Validate SFTP response packet buffer

Posted by lg...@apache.org.
[SSHD-868] Validate SFTP response packet buffer


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/775f3495
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/775f3495
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/775f3495

Branch: refs/heads/master
Commit: 775f34955151d6ec241a1ad3a634c53a87386a64
Parents: db6e5b5
Author: Lyor Goldstein <lg...@apache.org>
Authored: Sun Nov 18 09:12:40 2018 +0200
Committer: Lyor Goldstein <lg...@apache.org>
Committed: Sun Nov 18 11:32:53 2018 +0200

----------------------------------------------------------------------
 .../helpers/AbstractSftpClientExtension.java    | 13 +++++++++
 .../subsystem/sftp/impl/AbstractSftpClient.java | 23 ++++++++++++++++
 .../sshd/client/subsystem/sftp/ClientTest.java  | 29 ++++++++++++++------
 3 files changed, 56 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/775f3495/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/helpers/AbstractSftpClientExtension.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/helpers/AbstractSftpClientExtension.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/helpers/AbstractSftpClientExtension.java
index 6e1f52b..dc9379a 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/helpers/AbstractSftpClientExtension.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/helpers/AbstractSftpClientExtension.java
@@ -175,6 +175,8 @@ public abstract class AbstractSftpClientExtension extends AbstractLoggingBean im
         int length = buffer.getInt();
         int type = buffer.getUByte();
         int id = buffer.getInt();
+        validateIncomingResponse(SftpConstants.SSH_FXP_EXTENDED, id, type, length, buffer);
+
         if (type == SftpConstants.SSH_FXP_STATUS) {
             int substatus = buffer.getInt();
             String msg = buffer.getString();
@@ -196,6 +198,17 @@ public abstract class AbstractSftpClientExtension extends AbstractLoggingBean im
         }
     }
 
+    protected void validateIncomingResponse(
+            int cmd, int id, int type, int length, Buffer buffer)
+                throws IOException {
+        int remaining = buffer.available();
+        if ((length < 0) || (length > (remaining + 5 /* type + id */))) {
+            throw new SshException("Bad length (" + length + ") for remaining data (" + remaining + ")"
+                + " in response to " + SftpConstants.getCommandMessageName(cmd)
+                + ": type=" + SftpConstants.getCommandMessageName(type) + ", id=" + id);
+        }
+    }
+
     protected void throwStatusException(int id, int substatus, String msg, String lang) throws IOException {
         throw new SftpException(substatus, msg);
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/775f3495/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java
index 3d607f3..d7b45a8 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java
@@ -174,6 +174,8 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
         int length = buffer.getInt();
         int type = buffer.getUByte();
         int id = buffer.getInt();
+        validateIncomingResponse(cmd, id, type, length, buffer);
+
         if (type == SftpConstants.SSH_FXP_STATUS) {
             int substatus = buffer.getInt();
             String msg = buffer.getString();
@@ -229,6 +231,8 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
         int length = buffer.getInt();
         int type = buffer.getUByte();
         int id = buffer.getInt();
+        validateIncomingResponse(cmd, id, type, length, buffer);
+
         if (type == SftpConstants.SSH_FXP_HANDLE) {
             return ValidateUtils.checkNotNullAndNotEmpty(buffer.getBytes(), "Null/empty handle in buffer", GenericUtils.EMPTY_OBJECT_ARRAY);
         }
@@ -273,6 +277,8 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
         int length = buffer.getInt();
         int type = buffer.getUByte();
         int id = buffer.getInt();
+        validateIncomingResponse(cmd, id, type, length, buffer);
+
         if (type == SftpConstants.SSH_FXP_ATTRS) {
             return readAttributes(cmd, buffer, new AtomicInteger(0));
         }
@@ -320,6 +326,8 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
         int length = buffer.getInt();
         int type = buffer.getUByte();
         int id = buffer.getInt();
+        validateIncomingResponse(cmd, id, type, length, buffer);
+
         if (type == SftpConstants.SSH_FXP_NAME) {
             int len = buffer.getInt();
             if (len != 1) {
@@ -792,6 +800,8 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
         int length = buffer.getInt();
         int type = buffer.getUByte();
         int id = buffer.getInt();
+        validateIncomingResponse(cmd, id, type, length, buffer);
+
         if (type == SftpConstants.SSH_FXP_DATA) {
             int len = buffer.getInt();
             buffer.getRawBytes(dst, dstoff, len);
@@ -947,6 +957,8 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
         int length = buffer.getInt();
         int type = buffer.getUByte();
         int id = buffer.getInt();
+        validateIncomingResponse(cmd, id, type, length, buffer);
+
         boolean traceEnabled = log.isTraceEnabled();
         if (type == SftpConstants.SSH_FXP_NAME) {
             ClientChannel channel = getClientChannel();
@@ -1011,6 +1023,17 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
         return handleUnknownDirListingPacket(cmd, id, type, length, buffer);
     }
 
+    protected void validateIncomingResponse(
+            int cmd, int id, int type, int length, Buffer buffer)
+                throws IOException {
+        int remaining = buffer.available();
+        if ((length < 0) || (length > (remaining + 5 /* type + id */))) {
+            throw new SshException("Bad length (" + length + ") for remaining data (" + remaining + ")"
+                + " in response to " + SftpConstants.getCommandMessageName(cmd)
+                + ": type=" + SftpConstants.getCommandMessageName(type) + ", id=" + id);
+        }
+    }
+
     protected List<DirEntry> handleUnknownDirListingPacket(
             int cmd, int id, int type, int length, Buffer buffer)
                 throws IOException {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/775f3495/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/ClientTest.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/ClientTest.java b/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/ClientTest.java
index 94c492f..d5238b6 100644
--- a/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/ClientTest.java
+++ b/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/ClientTest.java
@@ -236,7 +236,8 @@ public class ClientTest extends BaseTestSupport {
             });
             testClientListener(channelHolder, SftpClient.class, () -> {
                 try {
-                    return SftpClientFactory.instance().createSftpClient(session);
+                    SftpClientFactory clientFactory = SftpClientFactory.instance();
+                    return clientFactory.createSftpClient(session);
                 } catch (IOException e) {
                     throw new RuntimeException(e);
                 }
@@ -246,7 +247,9 @@ public class ClientTest extends BaseTestSupport {
         }
     }
 
-    private <C extends Closeable> void testClientListener(AtomicReference<Channel> channelHolder, Class<C> channelType, Factory<? extends C> factory) throws Exception {
+    private <C extends Closeable> void testClientListener(
+            AtomicReference<Channel> channelHolder, Class<C> channelType, Factory<? extends C> factory)
+                throws Exception {
         assertNull(channelType.getSimpleName() + ": Unexpected currently active channel", channelHolder.get());
 
         try (C instance = factory.create()) {
@@ -333,29 +336,35 @@ public class ClientTest extends BaseTestSupport {
         assertListenerSizes("ClientStop", clientListeners, 0, 1);
     }
 
-    private static void assertListenerSizes(String phase, Map<String, ? extends TestChannelListener> listeners, int activeSize, int openSize) {
+    private static void assertListenerSizes(
+            String phase, Map<String, ? extends TestChannelListener> listeners, int activeSize, int openSize) {
         assertListenerSizes(phase, listeners.values(), activeSize, openSize);
     }
 
-    private static void assertListenerSizes(String phase, Collection<? extends TestChannelListener> listeners, int activeSize, int openSize) {
+    private static void assertListenerSizes(
+            String phase, Collection<? extends TestChannelListener> listeners, int activeSize, int openSize) {
         if (GenericUtils.isEmpty(listeners)) {
             return;
         }
 
         for (TestChannelListener l : listeners) {
             if (activeSize >= 0) {
-                assertEquals(phase + ": mismatched active channels size for " + l.getName() + " listener", activeSize, GenericUtils.size(l.getActiveChannels()));
+                assertEquals(phase + ": mismatched active channels size for " + l.getName() + " listener",
+                    activeSize, GenericUtils.size(l.getActiveChannels()));
             }
 
             if (openSize >= 0) {
-                assertEquals(phase + ": mismatched open channels size for " + l.getName() + " listener", openSize, GenericUtils.size(l.getOpenChannels()));
+                assertEquals(phase + ": mismatched open channels size for " + l.getName() + " listener",
+                    openSize, GenericUtils.size(l.getOpenChannels()));
             }
 
-            assertEquals(phase + ": unexpected failed channels size for " + l.getName() + " listener", 0, GenericUtils.size(l.getFailedChannels()));
+            assertEquals(phase + ": unexpected failed channels size for " + l.getName() + " listener",
+                0, GenericUtils.size(l.getFailedChannels()));
         }
     }
 
-    private static <L extends ChannelListener & NamedResource> void addChannelListener(Map<String, L> listeners, ChannelListenerManager manager, L listener) {
+    private static <L extends ChannelListener & NamedResource> void addChannelListener(
+            Map<String, L> listeners, ChannelListenerManager manager, L listener) {
         String name = listener.getName();
         assertNull("Duplicate listener named " + name, listeners.put(name, listener));
         manager.addChannelListener(listener);
@@ -378,7 +387,9 @@ public class ClientTest extends BaseTestSupport {
     }
 
     private ClientSession createTestClientSession(String host) throws IOException {
-        ClientSession session = client.connect(getCurrentTestName(), host, port).verify(7L, TimeUnit.SECONDS).getSession();
+        ClientSession session = client.connect(getCurrentTestName(), host, port)
+            .verify(7L, TimeUnit.SECONDS)
+            .getSession();
         try {
             assertNotNull("Client session creation not signalled", clientSessionHolder.get());
             session.addPasswordIdentity(getCurrentTestName());


[2/5] mina-sshd git commit: Fixed behavior of AbstractSftpClient#handleUnexpectedPacket to match its signature

Posted by lg...@apache.org.
Fixed behavior of AbstractSftpClient#handleUnexpectedPacket to match its signature


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/1a8924db
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/1a8924db
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/1a8924db

Branch: refs/heads/master
Commit: 1a8924db097928b4be51dd73a9a1311813d1b417
Parents: 775f349
Author: Lyor Goldstein <lg...@apache.org>
Authored: Sun Nov 18 09:27:51 2018 +0200
Committer: Lyor Goldstein <lg...@apache.org>
Committed: Sun Nov 18 11:32:53 2018 +0200

----------------------------------------------------------------------
 .../subsystem/sftp/impl/AbstractSftpClient.java | 26 +++++++++++++++++---
 .../subsystem/sftp/impl/DefaultSftpClient.java  |  7 +++++-
 2 files changed, 28 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1a8924db/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java
index d7b45a8..e10b466 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java
@@ -182,8 +182,10 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
             String lang = buffer.getString();
             checkResponseStatus(cmd, id, substatus, msg, lang);
         } else {
-            //noinspection ThrowableResultOfMethodCallIgnored
-            handleUnexpectedPacket(cmd, SftpConstants.SSH_FXP_STATUS, id, type, length, buffer);
+            IOException err = handleUnexpectedPacket(cmd, SftpConstants.SSH_FXP_STATUS, id, type, length, buffer);
+            if (err != null) {
+                throw err;
+            }
         }
     }
 
@@ -253,7 +255,11 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
     }
 
     protected byte[] handleUnexpectedHandlePacket(int cmd, int id, int type, int length, Buffer buffer) throws IOException {
-        handleUnexpectedPacket(cmd, SftpConstants.SSH_FXP_HANDLE, id, type, length, buffer);
+        IOException err = handleUnexpectedPacket(cmd, SftpConstants.SSH_FXP_HANDLE, id, type, length, buffer);
+        if (err != null) {
+            throw err;
+        }
+
         throw new SshException("No handling for unexpected handle packet id=" + id
                  + ", type=" + SftpConstants.getCommandMessageName(type) + ", length=" + length);
     }
@@ -1044,10 +1050,22 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
         return Collections.emptyList();
     }
 
+    /**
+     * @param cmd The initial command sent
+     * @param expected The expected packet type
+     * @param id The reported identifier
+     * @param type The reported SFTP response type
+     * @param length The packet length
+     * @param buffer The {@link Buffer} after reading from it whatever data
+     * led to this call
+     * @return The exception to throw - if {@code null} then implementor assumed
+     * to handle the exception internal. Otherwise, the exception is re-thrown
+     * @throws IOException If failed to handle the exception internally
+     */
     protected IOException handleUnexpectedPacket(
             int cmd, int expected, int id, int type, int length, Buffer buffer)
                 throws IOException {
-        throw new SshException("Unexpected SFTP packet received while awaiting " + SftpConstants.getCommandMessageName(expected)
+        return new SshException("Unexpected SFTP packet received while awaiting " + SftpConstants.getCommandMessageName(expected)
                 + " response to " + SftpConstants.getCommandMessageName(cmd)
                 + ": type=" + SftpConstants.getCommandMessageName(type) + ", id=" + id + ", length=" + length);
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1a8924db/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/DefaultSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/DefaultSftpClient.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/DefaultSftpClient.java
index 197809e..b1d095d 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/DefaultSftpClient.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/DefaultSftpClient.java
@@ -413,7 +413,12 @@ public class DefaultSftpClient extends AbstractSftpClient {
 
             throwStatusException(SftpConstants.SSH_FXP_INIT, id, substatus, msg, lang);
         } else {
-            handleUnexpectedPacket(SftpConstants.SSH_FXP_INIT, SftpConstants.SSH_FXP_VERSION, id, type, length, buffer);
+            IOException err = handleUnexpectedPacket(
+                SftpConstants.SSH_FXP_INIT, SftpConstants.SSH_FXP_VERSION, id, type, length, buffer);
+            if (err != null) {
+                throw err;
+            }
+
         }
     }
 


[3/5] mina-sshd git commit: [SSHD-868] Added validations for length and/or count data extracted for packet buffers

Posted by lg...@apache.org.
[SSHD-868] Added validations for length and/or count data extracted for packet buffers


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/db6e5b53
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/db6e5b53
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/db6e5b53

Branch: refs/heads/master
Commit: db6e5b5344dcf687ad01a6d7bc94cfa531809d37
Parents: a6dffd5
Author: Lyor Goldstein <lg...@apache.org>
Authored: Sun Nov 18 08:41:05 2018 +0200
Committer: Lyor Goldstein <lg...@apache.org>
Committed: Sun Nov 18 11:32:53 2018 +0200

----------------------------------------------------------------------
 .../org/apache/sshd/common/SshConstants.java    |  9 +++
 .../apache/sshd/common/util/buffer/Buffer.java  | 31 +++++++--
 .../common/util/buffer/ByteArrayBuffer.java     | 15 ++--
 .../sshd/agent/common/AbstractAgentClient.java  |  7 +-
 .../sshd/agent/common/AbstractAgentProxy.java   |  6 +-
 .../org/apache/sshd/agent/unix/AgentClient.java |  7 +-
 .../keyboard/UserAuthKeyboardInteractive.java   | 20 ++++--
 .../common/session/helpers/AbstractSession.java |  8 ++-
 .../sshd/server/auth/gss/UserAuthGSS.java       | 72 +++++++++++---------
 .../auth/hostbased/UserAuthHostBased.java       | 12 +++-
 .../keyboard/UserAuthKeyboardInteractive.java   | 16 +++--
 .../server/auth/pubkey/UserAuthPublicKey.java   | 12 +++-
 .../org/apache/sshd/server/kex/DHGEXServer.java |  4 +-
 .../deprecated/UserAuthKeyboardInteractive.java | 19 ++++--
 .../helpers/AbstractSftpClientExtension.java    | 14 ++--
 .../subsystem/sftp/impl/AbstractSftpClient.java | 37 +++++++---
 .../subsystem/sftp/impl/DefaultSftpClient.java  |  4 ++
 .../sshd/common/subsystem/sftp/SftpHelper.java  | 51 +++++++++-----
 .../sftp/extensions/AclSupportedParser.java     |  5 ++
 .../server/subsystem/sftp/SftpSubsystem.java    |  3 +-
 20 files changed, 240 insertions(+), 112 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-common/src/main/java/org/apache/sshd/common/SshConstants.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/SshConstants.java b/sshd-common/src/main/java/org/apache/sshd/common/SshConstants.java
index ee8ae63..57f3c17 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/SshConstants.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/SshConstants.java
@@ -122,6 +122,15 @@ public final class SshConstants {
     // Some more constants
     public static final int SSH_EXTENDED_DATA_STDERR = 1;   // see RFC4254 section 5.2
     public static final int SSH_PACKET_HEADER_LEN = 5;  // 32-bit length + 8-bit pad length
+    /*
+     * See https://tools.ietf.org/html/rfc4253#section-6.1:
+     *
+     *      All implementations MUST be able to process packets with an
+     *      uncompressed payload length of 32768 bytes or less and a total packet
+     *      size of 35000 bytes or less
+     */
+    public static final int SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT = 32768;
+    public static final int SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT = 35000;
 
     private SshConstants() {
         throw new UnsupportedOperationException("No instance allowed");

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
index dd61473..8b950d5 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
@@ -56,6 +56,7 @@ import java.util.function.IntUnaryOperator;
 import java.util.logging.Level;
 
 import org.apache.sshd.common.PropertyResolver;
+import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.cipher.ECCurves;
 import org.apache.sshd.common.config.keys.KeyUtils;
@@ -313,12 +314,15 @@ public abstract class Buffer implements Readable {
      * @see #getString(Charset)
      */
     public List<String> getStringList(int count, Charset charset) {
+        if ((count < 0) || (count > SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT)) {
+            throw new IndexOutOfBoundsException("Illogical string list length: " + count);
+        }
         if (count == 0) {
             return Collections.emptyList();
         }
 
         List<String> list = new ArrayList<>(count);
-        for (int index = 0; index < count; index++) {
+        for (int index = 1; index <= count; index++) {
             String s = getString(charset);
             list.add(s);
         }
@@ -337,11 +341,7 @@ public abstract class Buffer implements Readable {
     }
 
     public byte[] getBytes() {
-        int len = getInt();
-        if (len < 0) {
-            throw new BufferException("Bad item length: " + len);
-        }
-        ensureAvailable(len);
+        int len = ensureAvailable(getInt());
         byte[] b = new byte[len];
         getRawBytes(b);
         return b;
@@ -365,6 +365,10 @@ public abstract class Buffer implements Readable {
     public PublicKey getPublicKey(BufferPublicKeyParser<? extends PublicKey> parser) throws SshException {
         int ow = wpos();
         int len = getInt();
+        if (len < 0) {
+            throw new SshException("Illogical public key length: " + len);
+        }
+
         wpos(rpos() + len);
         try {
             return getRawPublicKey(parser);
@@ -470,11 +474,24 @@ public abstract class Buffer implements Readable {
         return new KeyPair(pubKey, privKey);
     }
 
-    public void ensureAvailable(int reqLen) throws BufferException {
+    /**
+     * Makes sure the buffer contains enough data to accommodate the requested length
+     *
+     * @param reqLen Requested data in bytes
+     * @return Same as input if validation successful
+     * @throws BufferException If negative length or beyond available requested
+     */
+    public int ensureAvailable(int reqLen) throws BufferException {
+        if (reqLen < 0) {
+            throw new BufferException("Bad item length: " + reqLen);
+        }
+
         int availLen = available();
         if (availLen < reqLen) {
             throw new BufferException("Underflow: requested=" + reqLen + ", available=" + availLen);
         }
+
+        return reqLen;
     }
 
     /*======================

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
index 6655ec1..49fef32 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
@@ -68,6 +68,9 @@ public class ByteArrayBuffer extends Buffer {
     }
 
     public ByteArrayBuffer(byte[] data, int off, int len, boolean read) {
+        if ((off < 0) || (len < 0)) {
+            throw new IndexOutOfBoundsException("Invalid offset(" + off + ")/length(" + len + ")");
+        }
         this.data = data;
         this.rpos = off;
         this.wpos = (read ? len : 0) + off;
@@ -171,13 +174,9 @@ public class ByteArrayBuffer extends Buffer {
 
     @Override
     public String getString(Charset charset) {
-        int len = getInt();
-        if (len < 0) {
-            throw new BufferException("Bad item length: " + len);
-        }
-        ensureAvailable(len);
-
         Objects.requireNonNull(charset, "No charset specified");
+
+        int len = ensureAvailable(getInt());
         String s = new String(data, rpos, len, charset);
         rpos += len;
         return s;
@@ -192,6 +191,10 @@ public class ByteArrayBuffer extends Buffer {
 
     @Override
     protected void copyRawBytes(int offset, byte[] buf, int pos, int len) {
+        if ((offset < 0) || (pos < 0) || (len < 0)) {
+            throw new IndexOutOfBoundsException(
+                "Invalid offset(" + offset + ")/position(" + pos + ")/length(" + len + ") required");
+        }
         System.arraycopy(data, rpos + offset, buf, pos, len);
     }
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
index 07d04ce..c614494 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
@@ -19,6 +19,7 @@
 package org.apache.sshd.agent.common;
 
 import java.io.IOException;
+import java.io.StreamCorruptedException;
 import java.security.KeyPair;
 import java.security.PublicKey;
 import java.util.Collection;
@@ -55,6 +56,10 @@ public abstract class AbstractAgentClient extends AbstractLoggingBean {
 
         int rpos = buffer.rpos();
         int len = buffer.getInt();
+        // Protect against malicious or corrupted packets
+        if (len < 0) {
+            throw new StreamCorruptedException("Illogical message length: " + len);
+        }
         buffer.rpos(rpos);
 
         avail = buffer.available();
@@ -77,7 +82,7 @@ public abstract class AbstractAgentClient extends AbstractLoggingBean {
         } catch (Exception e) {
             if (log.isDebugEnabled()) {
                 log.debug("Failed ({}) to handle command={}: {}",
-                          e.getClass().getSimpleName(), cmd, e.getMessage());
+                      e.getClass().getSimpleName(), cmd, e.getMessage());
             }
             if (log.isTraceEnabled()) {
                 log.trace("Received command=" + cmd + " handling failure details", e);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java
index 717569d..27c2112 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java
@@ -83,8 +83,8 @@ public abstract class AbstractAgentProxy extends AbstractLoggingBean implements
         }
 
         int nbIdentities = buffer.getInt();
-        if (nbIdentities > 1024) {
-            throw new SshException("Bad identities count: " + nbIdentities);
+        if ((nbIdentities < 0) || (nbIdentities > 1024)) {
+            throw new SshException("Illogical identities count: " + nbIdentities);
         }
 
         List<SimpleImmutableEntry<PublicKey, String>> keys = new ArrayList<>(nbIdentities);
@@ -94,7 +94,7 @@ public abstract class AbstractAgentProxy extends AbstractLoggingBean implements
             String comment = buffer.getString();
             if (debugEnabled) {
                 log.debug("getIdentities() key type={}, comment={}, fingerprint={}",
-                          KeyUtils.getKeyType(key), comment, KeyUtils.getFingerPrint(key));
+                      KeyUtils.getKeyType(key), comment, KeyUtils.getFingerPrint(key));
             }
             keys.add(new SimpleImmutableEntry<>(key, comment));
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentClient.java b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentClient.java
index 3291092..c6d3585 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentClient.java
@@ -20,6 +20,7 @@ package org.apache.sshd.agent.unix;
 
 import java.io.IOException;
 import java.io.InterruptedIOException;
+import java.io.StreamCorruptedException;
 import java.util.Queue;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.Future;
@@ -118,8 +119,12 @@ public class AgentClient extends AbstractAgentProxy implements Runnable {
             if (receiveBuffer.available() >= 4) {
                 int rpos = receiveBuffer.rpos();
                 int len = receiveBuffer.getInt();
+                // Protect against malicious or corrupted packets
+                if (len < 0) {
+                    throw new StreamCorruptedException("Illogical message length: " + len);
+                }
                 receiveBuffer.rpos(rpos);
-                if (receiveBuffer.available() >= 4 + len) {
+                if (receiveBuffer.available() >= (4 + len)) {
                     message = new ByteArrayBuffer(receiveBuffer.getBytes());
                     receiveBuffer.compact();
                 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractive.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractive.java
index c27a4c4..96a204f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractive.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractive.java
@@ -18,7 +18,6 @@
  */
 package org.apache.sshd.client.auth.keyboard;
 
-import java.util.Arrays;
 import java.util.Iterator;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -145,6 +144,13 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
         String instruction = buffer.getString();
         String lang = buffer.getString();
         int num = buffer.getInt();
+        // Protect against malicious or corrupted packets
+        if ((num < 0) || (num > SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT)) {
+            log.error("processAuthDataRequest({})[{}] illogical challenges count ({}) for name={}, instruction={}",
+                    session, service, num, name, instruction);
+            throw new IndexOutOfBoundsException("Illogical challenges count: " + num);
+        }
+
         boolean debugEnabled = log.isDebugEnabled();
         if (debugEnabled) {
             log.debug("processAuthDataRequest({})[{}] SSH_MSG_USERAUTH_INFO_REQUEST name={}, instruction={}, language={}, num-prompts={}",
@@ -159,16 +165,16 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
 
         String[] prompt = (num > 0) ? new String[num] : GenericUtils.EMPTY_STRING_ARRAY;
         boolean[] echo =  (num > 0) ? new boolean[num] : GenericUtils.EMPTY_BOOLEAN_ARRAY;
+        boolean traceEnabled = log.isTraceEnabled();
         for (int i = 0; i < num; i++) {
-            // according to RFC4256: "The prompt field(s) MUST NOT be empty strings."
+            // TODO according to RFC4256: "The prompt field(s) MUST NOT be empty strings."
             prompt[i] = buffer.getString();
             echo[i] = buffer.getBoolean();
-        }
 
-        boolean traceEnabled = log.isTraceEnabled();
-        if (traceEnabled) {
-            log.trace("processAuthDataRequest({})[{}] Prompt: {}", session, service, Arrays.toString(prompt));
-            log.trace("processAuthDataRequest({})[{}] Echo: {}", session, service, Arrays.toString(echo));
+            if (traceEnabled) {
+                log.trace("processAuthDataRequest({})[{}]({}) {}/{}: echo={}, prompt={}",
+                    session, service, name, i + 1, num, echo[i], prompt[i]);
+            }
         }
 
         String[] rep = getUserResponses(name, instruction, lang, prompt, echo);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java b/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
index fc9958f..738a1a4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java
@@ -1014,8 +1014,12 @@ public abstract class AbstractSession extends SessionHelper {
                     }
                     // Read packet length
                     decoderLength = decoderBuffer.getInt();
-                    // Check packet length validity
-                    if ((decoderLength < SshConstants.SSH_PACKET_HEADER_LEN) || (decoderLength > (256 * 1024))) {
+                    /*
+                     * Check packet length validity - we allow 8 times the minimum required packet length support
+                     * in order to be aligned with some OpenSSH versions that allow up to 256k
+                     */
+                    if ((decoderLength < SshConstants.SSH_PACKET_HEADER_LEN)
+                            || (decoderLength > (8 * SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT))) {
                         log.warn("decode({}) Error decoding packet(invalid length): {}", this, decoderLength);
                         decoderBuffer.dumpHex(getSimplifiedLogger(), "decode(" + this + ") invalid length packet", this);
                         throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR,

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
index db1256f..38bfd4f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
@@ -32,6 +32,7 @@ import org.ietf.jgss.GSSContext;
 import org.ietf.jgss.GSSCredential;
 import org.ietf.jgss.GSSException;
 import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
 import org.ietf.jgss.MessageProp;
 import org.ietf.jgss.Oid;
 
@@ -62,60 +63,66 @@ public class UserAuthGSS extends AbstractUserAuth {
     protected Boolean doAuth(Buffer buffer, boolean initial) throws Exception {
         ServerSession session = getServerSession();
         GSSAuthenticator auth = Objects.requireNonNull(session.getGSSAuthenticator(), "No GSSAuthenticator configured");
-
+        String user = getUsername();
         boolean debugEnabled = log.isDebugEnabled();
+
         if (initial) {
             // Get mechanism count from buffer and look for Kerberos 5.
-
             int num = buffer.getInt();
+            // Protect against malicious or corrupted packets
+            if ((num < 0) || (num > SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT)) {
+                log.error("doAuth({}@{}) Illogical OID entries count: {}", user, session, num);
+                throw new IndexOutOfBoundsException("Illogical OID entries count: " + num);
+            }
 
-            for (int i = 0; i < num; i++) {
+            boolean traceEnabled = log.isTraceEnabled();
+            for (int i = 1; i <= num; i++) {
                 Oid oid = new Oid(buffer.getBytes());
-
-                if (oid.equals(KRB5_MECH)) {
-                    if (debugEnabled) {
-                        log.debug("doAuth({}@{}) found Kerberos 5", getUsername(), session);
-                    }
-
-                    // Validate initial user before proceeding
-
-                    if (!auth.validateInitialUser(session, getUsername())) {
-                        return Boolean.FALSE;
+                if (!oid.equals(KRB5_MECH)) {
+                    if (traceEnabled) {
+                        log.trace("doAuth({}@{}) skip OID {}/{}: {}", user, session, i, num, oid);
                     }
+                    continue;
+                }
+                if (debugEnabled) {
+                    log.debug("doAuth({}@{}) found Kerberos 5 after {}/{} OID(s)", user, session, i, num);
+                }
 
-                    GSSManager mgr = auth.getGSSManager();
-                    GSSCredential creds = auth.getGSSCredential(mgr);
+                // Validate initial user before proceeding
+                if (!auth.validateInitialUser(session, user)) {
+                    return Boolean.FALSE;
+                }
 
-                    if (creds == null) {
-                        return Boolean.FALSE;
-                    }
+                GSSManager mgr = auth.getGSSManager();
+                GSSCredential creds = auth.getGSSCredential(mgr);
+                if (creds == null) {
+                    return Boolean.FALSE;
+                }
 
-                    context = mgr.createContext(creds);
+                context = mgr.createContext(creds);
 
-                    // Send the matching mechanism back to the client
+                // Send the matching mechanism back to the client
 
-                    byte[] out = oid.getDER();
-                    Buffer b = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST, out.length + Integer.SIZE);
-                    b.putBytes(out);
-                    session.writePacket(b);
+                byte[] out = oid.getDER();
+                Buffer b = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST, out.length + Integer.SIZE);
+                b.putBytes(out);
+                session.writePacket(b);
 
-                    return null;
-                }
+                return null;
             }
 
             // No matching mechanism found
-
             return Boolean.FALSE;
         } else {
             int msg = buffer.getUByte();
             if (!((msg == SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE)
                     || ((msg == SshConstants.SSH_MSG_USERAUTH_GSSAPI_MIC)) && context.isEstablished())) {
                 throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR,
-                        "Packet not supported by user authentication method: " + SshConstants.getCommandMessageName(msg));
+                    "Packet not supported by user authentication method: " + SshConstants.getCommandMessageName(msg));
             }
 
             if (debugEnabled) {
-                log.debug("doAuth({}@{}) In krb5.next: msg = {}", getUsername(), session, SshConstants.getCommandMessageName(msg));
+                log.debug("doAuth({}@{}) In krb5.next: msg = {}", user, session, SshConstants.getCommandMessageName(msg));
             }
 
             // If the context is established, this must be a MIC message
@@ -145,7 +152,7 @@ public class UserAuthGSS extends AbstractUserAuth {
                 } catch (GSSException e) {
                     if (debugEnabled) {
                         log.debug("doAuth({}@{}) GSS verification {} error: {}",
-                                  getUsername(), session, e.getClass().getSimpleName(), e.getMessage());
+                            user, session, e.getClass().getSimpleName(), e.getMessage());
                     }
                     return Boolean.FALSE;
                 }
@@ -157,9 +164,10 @@ public class UserAuthGSS extends AbstractUserAuth {
 
                 // Validate identity if context is now established
                 if (established && (identity == null)) {
-                    identity = context.getSrcName().toString();
+                    GSSName srcName = context.getSrcName();
+                    identity = srcName.toString();
                     if (debugEnabled) {
-                        log.debug("doAuth({}@{}) GSS identity is {}", getUsername(), session, identity);
+                        log.debug("doAuth({}@{}) GSS identity is {}", user, session, identity);
                     }
 
                     if (!auth.validateIdentity(session, identity)) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBased.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBased.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBased.java
index c191876..d724af4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBased.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBased.java
@@ -81,14 +81,22 @@ public class UserAuthHostBased extends AbstractUserAuth implements SignatureFact
         String keyType = buffer.getString();
         int keyLen = buffer.getInt();
         int keyOffset = buffer.rpos();
+        int remaining = buffer.available();
+        // Protect against malicious or corrupted packets
+        if ((keyLen < 0) || (keyLen > remaining)) {
+            log.error("doAuth({}@{}) Illogical {} key length={} (max. available={})",
+                username, session, keyType, keyLen, remaining);
+            throw new IndexOutOfBoundsException("Illogical " + keyType + " key length: " + keyLen);
+        }
 
         Buffer buf = new ByteArrayBuffer(buffer.array(), keyOffset, keyLen, true);
         PublicKey clientKey = buf.getRawPublicKey();
         List<X509Certificate> certs = Collections.emptyList();
-        if (buf.available() > 0) {
+        remaining = buf.available();
+        if (remaining > 0) {
             CertificateFactory cf = SecurityUtils.getCertificateFactory("X.509");
             certs = new ArrayList<>();
-            try (ByteArrayInputStream bais = new ByteArrayInputStream(buf.array(), buf.rpos(), buf.available())) {
+            try (ByteArrayInputStream bais = new ByteArrayInputStream(buf.array(), buf.rpos(), remaining)) {
                 X509Certificate c = (X509Certificate) cf.generateCertificate(bais);
                 certs.add(c);
             }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractive.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractive.java
index f73cd5d..e7b9b63 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractive.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractive.java
@@ -111,12 +111,18 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
         }
 
         int num = buffer.getInt();
+        // Protect against malicious or corrupted packets
+        if ((num < 0) || (num > SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT)) {
+            log.error("doValidateAuthResponse({}@{}) illogical response count: {}", username, session, num);
+            throw new IndexOutOfBoundsException("Illogical response count: " + num);
+        }
+
         List<String> responses = (num <= 0) ? Collections.emptyList() : new ArrayList<>(num);
         boolean traceEnabled = log.isTraceEnabled();
-        for (int index = 0; index < num; index++) {
+        for (int index = 1; index <= num; index++) {
             String value = buffer.getString();
             if (traceEnabled) {
-                log.trace("doAuth({}@{}) response #{}: {}", username, session, index + 1, value);
+                log.trace("doAuth({}@{}) response {}/{}: {}", username, session, index, num, value);
             }
             responses.add(value);
         }
@@ -125,7 +131,7 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
         if (auth == null) {
             if (debugEnabled) {
                 log.debug("doAuth({}@{}) no interactive authenticator to validate {} responses",
-                          username, session, num);
+                      username, session, num);
             }
             return false;
         }
@@ -135,7 +141,7 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
             authed = auth.authenticate(session, username, responses);
         } catch (Error e) {
             log.warn("doAuth({}@{}) failed ({}) to consult authenticator: {}",
-                     username, session, e.getClass().getSimpleName(), e.getMessage());
+                 username, session, e.getClass().getSimpleName(), e.getMessage());
             if (debugEnabled) {
                 log.debug("doAuth(" + username + "@" + session + ") authenticator consultation failure details", e);
             }
@@ -144,7 +150,7 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
 
         if (debugEnabled) {
             log.debug("doAuth({}@{}) authenticate {} responses result: {}",
-                      username, session, num, authed);
+                  username, session, num, authed);
         }
 
         return authed;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKey.java
index 0ea0dfa..29c3f5f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKey.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKey.java
@@ -70,16 +70,24 @@ public class UserAuthPublicKey extends AbstractUserAuth implements SignatureFact
     @Override
     public Boolean doAuth(Buffer buffer, boolean init) throws Exception {
         ValidateUtils.checkTrue(init, "Instance not initialized");
+        ServerSession session = getServerSession();
+        String username = getUsername();
 
         boolean hasSig = buffer.getBoolean();
         String alg = buffer.getString();
         int oldLim = buffer.wpos();
         int oldPos = buffer.rpos();
         int len = buffer.getInt();
+        int remaining = buffer.available();
+        // Protect against malicious or corrupted packets
+        if ((len < 0) || (len > remaining)) {
+            log.error("doAuth({}@{}) illogical algorithm={} signature length ({}) when remaining={}",
+                username, session, alg, len, remaining);
+            throw new IndexOutOfBoundsException("Illogical signature length (" + len + ") for algorithm=" + alg);
+        }
+
         buffer.wpos(buffer.rpos() + len);
 
-        ServerSession session = getServerSession();
-        String username = getUsername();
         PublicKey key = buffer.getRawPublicKey();
         Collection<NamedFactory<Signature>> factories =
             ValidateUtils.checkNotNullAndNotEmpty(

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java
index 404059f..914c5b0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java
@@ -114,7 +114,7 @@ public class DHGEXServer extends AbstractDHServerKeyExchange {
             prf = buffer.getInt();
             max = SecurityUtils.getMaxDHGroupExchangeKeySize();
 
-            if (max < min || prf < min || max < prf) {
+            if ((max < min) || (prf < min) || (max < prf)) {
                 throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
                         "Protocol error: bad parameters " + min + " !< " + prf + " !< " + max);
             }
@@ -140,7 +140,7 @@ public class DHGEXServer extends AbstractDHServerKeyExchange {
             min = buffer.getInt();
             prf = buffer.getInt();
             max = buffer.getInt();
-            if (prf < min || max < prf) {
+            if ((prf < min) || (max < prf)) {
                 throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
                         "Protocol error: bad parameters " + min + " !< " + prf + " !< " + max);
             }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
index f02f619..6236e05 100644
--- a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
+++ b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
@@ -24,6 +24,7 @@ import java.util.Arrays;
 import org.apache.sshd.client.auth.keyboard.UserInteraction;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.buffer.Buffer;
 
 /**
@@ -69,11 +70,18 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
                     String language_tag = buffer.getString();
                     if (debugEnabled) {
                         log.debug("next({}) Received SSH_MSG_USERAUTH_INFO_REQUEST - name={}, instruction={}, lang={}",
-                                 session, name, instruction, language_tag);
+                             session, name, instruction, language_tag);
                     }
                     int num = buffer.getInt();
-                    String[] prompt = new String[num];
-                    boolean[] echo = new boolean[num];
+                    // Protect against malicious or corrupted packets
+                    if ((num < 0) || (num > SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT)) {
+                        log.error("next({}) illogical challenges count ({}) for name={}, instruction={}",
+                            session, num, name, instruction);
+                        throw new IndexOutOfBoundsException("Illogical challenges count: " + num);
+                    }
+
+                    String[] prompt = (num <= 0) ? GenericUtils.EMPTY_STRING_ARRAY : new String[num];
+                    boolean[] echo = (num <= 0) ? GenericUtils.EMPTY_BOOLEAN_ARRAY : new boolean[num];
                     for (int i = 0; i < num; i++) {
                         prompt[i] = buffer.getString();
                         echo[i] = buffer.getBoolean();
@@ -85,8 +93,9 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
 
                     String[] rep = null;
                     if (num == 0) {
-                        rep = new String[0];
-                    } else if (num == 1 && password != null && !echo[0] && prompt[0].toLowerCase().startsWith("password:")) {
+                        rep = GenericUtils.EMPTY_STRING_ARRAY;
+                    } else if ((num == 1) && (password != null) && (!echo[0])
+                            && prompt[0].toLowerCase().startsWith("password:")) {
                         rep = new String[]{password};
                     } else {
                         UserInteraction ui = session.getUserInteraction();

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/helpers/AbstractSftpClientExtension.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/helpers/AbstractSftpClientExtension.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/helpers/AbstractSftpClientExtension.java
index 6b179c9..6e1f52b 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/helpers/AbstractSftpClientExtension.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/helpers/AbstractSftpClientExtension.java
@@ -107,11 +107,9 @@ public abstract class AbstractSftpClientExtension extends AbstractLoggingBean im
 
     /**
      * @param buffer The {@link Buffer}
-     * @param target A target path {@link String} or {@link Handle} or {@code byte[]}
-     *               to be encoded in the buffer
+     * @param target A target path {@link String} or {@link Handle} or {@code byte[]} to be encoded in the buffer
      * @return The updated buffer
-     * @throws UnsupportedOperationException If target is not one of the above
-     *                                       supported types
+     * @throws UnsupportedOperationException If target is not one of the above supported types
      */
     public Buffer putTarget(Buffer buffer, Object target) {
         if (target instanceof CharSequence) {
@@ -128,8 +126,7 @@ public abstract class AbstractSftpClientExtension extends AbstractLoggingBean im
     }
 
     /**
-     * @param target A target path {@link String} or {@link Handle} or {@code byte[]}
-     *               to be encoded in the buffer
+     * @param target A target path {@link String} or {@link Handle} or {@code byte[]} to be encoded in the buffer
      * @return A {@link Buffer} with the extension name set
      * @see #getCommandBuffer(Object, int)
      */
@@ -138,8 +135,7 @@ public abstract class AbstractSftpClientExtension extends AbstractLoggingBean im
     }
 
     /**
-     * @param target    A target path {@link String} or {@link Handle} or {@code byte[]}
-     *                  to be encoded in the buffer
+     * @param target A target path {@link String} or {@link Handle} or {@code byte[]} to be encoded in the buffer
      * @param extraSize Extra size - beyond the path/handle to be allocated
      * @return A {@link Buffer} with the extension name set
      * @see #getCommandBuffer(int)
@@ -173,7 +169,7 @@ public abstract class AbstractSftpClientExtension extends AbstractLoggingBean im
      * or {@code null} if this is a {@link SftpConstants#SSH_FXP_STATUS} carrying
      * an {@link SftpConstants#SSH_FX_OK} result
      * @throws IOException If a non-{@link SftpConstants#SSH_FX_OK} result or
-     *                     not a {@link SftpConstants#SSH_FXP_EXTENDED_REPLY} buffer
+     * not a {@link SftpConstants#SSH_FXP_EXTENDED_REPLY} buffer
      */
     protected Buffer checkExtendedReplyBuffer(Buffer buffer) throws IOException {
         int length = buffer.getInt();

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java
index 2ef5039..3d607f3 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/AbstractSftpClient.java
@@ -38,6 +38,7 @@ import org.apache.sshd.client.subsystem.sftp.SftpClient;
 import org.apache.sshd.client.subsystem.sftp.extensions.BuiltinSftpClientExtensions;
 import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtension;
 import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtensionFactory;
+import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.channel.Channel;
 import org.apache.sshd.common.subsystem.sftp.SftpConstants;
@@ -770,7 +771,9 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
         return checkData(SftpConstants.SSH_FXP_READ, buffer, dstOffset, dst, eofSignalled);
     }
 
-    protected int checkData(int cmd, Buffer request, int dstOffset, byte[] dst, AtomicReference<Boolean> eofSignalled) throws IOException {
+    protected int checkData(
+            int cmd, Buffer request, int dstOffset, byte[] dst, AtomicReference<Boolean> eofSignalled)
+                throws IOException {
         if (eofSignalled != null) {
             eofSignalled.set(null);
         }
@@ -779,7 +782,9 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
         return checkDataResponse(cmd, response, dstOffset, dst, eofSignalled);
     }
 
-    protected int checkDataResponse(int cmd, Buffer buffer, int dstoff, byte[] dst, AtomicReference<Boolean> eofSignalled) throws IOException {
+    protected int checkDataResponse(
+            int cmd, Buffer buffer, int dstoff, byte[] dst, AtomicReference<Boolean> eofSignalled)
+                throws IOException {
         if (eofSignalled != null) {
             eofSignalled.set(null);
         }
@@ -944,17 +949,23 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
         int id = buffer.getInt();
         boolean traceEnabled = log.isTraceEnabled();
         if (type == SftpConstants.SSH_FXP_NAME) {
-            int len = buffer.getInt();
-            int version = getVersion();
             ClientChannel channel = getClientChannel();
+            int count = buffer.getInt();
+            int version = getVersion();
+            // Protect against malicious or corrupted packets
+            if ((count < 0) || (count > SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT)) {
+                log.error("checkDirResponse({})[id={}] illogical dir entries count: {}", channel, id, count);
+                throw new SshException("Illogical dir entries count: " + count);
+            }
+
             boolean debugEnabled = log.isDebugEnabled();
             if (debugEnabled) {
-                log.debug("checkDirResponse({}}[id={}] reading {} entries", channel, id, len);
+                log.debug("checkDirResponse({}}[id={}] reading {} entries", channel, id, count);
             }
 
-            List<DirEntry> entries = new ArrayList<>(len);
+            List<DirEntry> entries = new ArrayList<>(count);
             AtomicInteger nameIndex = new AtomicInteger(0);
-            for (int i = 0; i < len; i++) {
+            for (int index = 1; index <= count; index++) {
                 String name = getReferencedName(cmd, buffer, nameIndex.getAndIncrement());
                 String longName = null;
                 if (version == SftpConstants.SFTP_V3) {
@@ -963,8 +974,8 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
 
                 Attributes attrs = readAttributes(cmd, buffer, nameIndex);
                 if (traceEnabled) {
-                    log.trace("checkDirResponse({})[id={}][{}] ({})[{}]: {}",
-                          channel, id, i, name, longName, attrs);
+                    log.trace("checkDirResponse({})[id={}][{}/{}] ({})[{}]: {}",
+                          channel, id, index, count, name, longName, attrs);
                 }
 
                 entries.add(new DirEntry(name, longName, attrs));
@@ -1000,7 +1011,9 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
         return handleUnknownDirListingPacket(cmd, id, type, length, buffer);
     }
 
-    protected List<DirEntry> handleUnknownDirListingPacket(int cmd, int id, int type, int length, Buffer buffer) throws IOException {
+    protected List<DirEntry> handleUnknownDirListingPacket(
+            int cmd, int id, int type, int length, Buffer buffer)
+                throws IOException {
         IOException err = handleUnexpectedPacket(cmd, SftpConstants.SSH_FXP_NAME, id, type, length, buffer);
         if (err != null) {
             throw err;
@@ -1008,7 +1021,9 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
         return Collections.emptyList();
     }
 
-    protected IOException handleUnexpectedPacket(int cmd, int expected, int id, int type, int length, Buffer buffer) throws IOException {
+    protected IOException handleUnexpectedPacket(
+            int cmd, int expected, int id, int type, int length, Buffer buffer)
+                throws IOException {
         throw new SshException("Unexpected SFTP packet received while awaiting " + SftpConstants.getCommandMessageName(expected)
                 + " response to " + SftpConstants.getCommandMessageName(cmd)
                 + ": type=" + SftpConstants.getCommandMessageName(type) + ", id=" + id + ", length=" + length);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/DefaultSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/DefaultSftpClient.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/DefaultSftpClient.java
index 2ac227c..197809e 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/DefaultSftpClient.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/DefaultSftpClient.java
@@ -46,6 +46,7 @@ import org.apache.sshd.client.channel.ClientChannel;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.client.subsystem.sftp.SftpVersionSelector;
 import org.apache.sshd.common.PropertyResolverUtils;
+import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.subsystem.sftp.SftpConstants;
 import org.apache.sshd.common.subsystem.sftp.extensions.ParserUtils;
@@ -215,6 +216,9 @@ public class DefaultSftpClient extends AbstractSftpClient {
             if (length < 5) {
                 throw new IOException("Illegal sftp packet length: " + length);
             }
+            if (length > (8 * SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT)) {
+                throw new StreamCorruptedException("Illogical sftp packet length: " + length);
+            }
             if ((wpos - rpos) >= (length + 4)) {
                 incoming.rpos(rpos);
                 incoming.wpos(rpos + 4 + length);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpHelper.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpHelper.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpHelper.java
index 8a6f9a3..ee43ab3 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpHelper.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpHelper.java
@@ -54,6 +54,7 @@ import java.util.TreeMap;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.sshd.common.PropertyResolver;
+import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.OsUtils;
 import org.apache.sshd.common.util.ValidateUtils;
@@ -640,9 +641,14 @@ public final class SftpHelper {
 
     public static NavigableMap<String, byte[]> readExtensions(Buffer buffer) {
         int count = buffer.getInt();
+        // Protect against malicious or malformed packets
+        if ((count < 0) || (count > SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT)) {
+            throw new IndexOutOfBoundsException("Illogical extensions count: " + count);
+        }
+
         // NOTE
         NavigableMap<String, byte[]> extended = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-        for (int i = 0; i < count; i++) {
+        for (int i = 1; i <= count; i++) {
             String key = buffer.getString();
             byte[] val = buffer.getBytes();
             byte[] prev = extended.put(key, val);
@@ -659,16 +665,16 @@ public final class SftpHelper {
             return buffer;
         }
 
-        extensions.forEach((key, value) -> {
-            Objects.requireNonNull(key, "No extension type");
-            Objects.requireNonNull(value, "No extension value");
+        for (Map.Entry<?, ?> ee : extensions.entrySet()) {
+            Object key = Objects.requireNonNull(ee.getKey(), "No extension type");
+            Object value = Objects.requireNonNull(ee.getValue(), "No extension value");
             buffer.putString(key.toString());
             if (value instanceof byte[]) {
                 buffer.putBytes((byte[]) value);
             } else {
                 buffer.putString(value.toString());
             }
-        });
+        }
 
         return buffer;
     }
@@ -680,11 +686,12 @@ public final class SftpHelper {
 
         // NOTE: even though extensions are probably case sensitive we do not allow duplicate name that differs only in case
         NavigableMap<String, String> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-        extensions.forEach((key, value) -> {
-            ValidateUtils.checkNotNull(value, "No value for extension=%s", key);
-            String prev = map.put(key, (value instanceof byte[]) ? new String((byte[]) value, StandardCharsets.UTF_8) : value.toString());
+        for (Map.Entry<?, ?> ee : extensions.entrySet()) {
+            Object key = Objects.requireNonNull(ee.getKey(), "No extension type");
+            Object value = ValidateUtils.checkNotNull(ee.getValue(), "No value for extension=%s", key);
+            String prev = map.put(key.toString(), (value instanceof byte[]) ? new String((byte[]) value, StandardCharsets.UTF_8) : value.toString());
             ValidateUtils.checkTrue(prev == null, "Multiple values for extension=%s", key);
-        });
+        }
 
         return map;
     }
@@ -709,6 +716,11 @@ public final class SftpHelper {
     // for v6 see https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#page-21
     public static List<AclEntry> readACLs(Buffer buffer, int version) {
         int aclSize = buffer.getInt();
+        // Protect against malicious or malformed packets
+        if ((aclSize < 0) || (aclSize > (2 * SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT))) {
+            throw new IndexOutOfBoundsException("Illogical ACL entries size: " + aclSize);
+        }
+
         int startPos = buffer.rpos();
         Buffer aclBuffer = new ByteArrayBuffer(buffer.array(), startPos, aclSize, true);
         List<AclEntry> acl = decodeACLs(aclBuffer, version);
@@ -724,14 +736,21 @@ public final class SftpHelper {
         }
 
         int count = buffer.getInt();
-        // NOTE: although the value is defined as UINT32 we do not expected a count greater than Integer.MAX_VALUE
+        /*
+         * NOTE: although the value is defined as UINT32 we do not expected a count greater
+         * than several hundreds + protect against malicious or corrupted packets
+         */
+        if ((count < 0) || (count > SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT)) {
+            throw new IndexOutOfBoundsException("Illogical ACL entries count: " + count);
+        }
+
         ValidateUtils.checkTrue(count >= 0, "Invalid ACL entries count: %d", count);
         if (count == 0) {
             return Collections.emptyList();
         }
 
         List<AclEntry> acls = new ArrayList<>(count);
-        for (int i = 0; i < count; i++) {
+        for (int i = 1; i <= count; i++) {
             int aclType = buffer.getInt();
             int aclFlag = buffer.getInt();
             int aclMask = buffer.getInt();
@@ -745,11 +764,11 @@ public final class SftpHelper {
     public static AclEntry buildAclEntry(int aclType, int aclFlag, int aclMask, String aclWho) {
         UserPrincipal who = new DefaultGroupPrincipal(aclWho);
         return AclEntry.newBuilder()
-                .setType(ValidateUtils.checkNotNull(decodeAclEntryType(aclType), "Unknown ACL type: %d", aclType))
-                .setFlags(decodeAclFlags(aclFlag))
-                .setPermissions(decodeAclMask(aclMask))
-                .setPrincipal(who)
-                .build();
+            .setType(ValidateUtils.checkNotNull(decodeAclEntryType(aclType), "Unknown ACL type: %d", aclType))
+            .setFlags(decodeAclFlags(aclFlag))
+            .setPermissions(decodeAclMask(aclMask))
+            .setPrincipal(who)
+            .build();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AclSupportedParser.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AclSupportedParser.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AclSupportedParser.java
index a724507..b796ab7 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AclSupportedParser.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AclSupportedParser.java
@@ -29,9 +29,11 @@ import java.util.Objects;
 import java.util.Set;
 import java.util.TreeSet;
 
+import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.subsystem.sftp.SftpConstants;
 import org.apache.sshd.common.subsystem.sftp.extensions.AclSupportedParser.AclCapabilities;
 import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
 import org.apache.sshd.common.util.logging.LoggingUtils;
@@ -55,6 +57,9 @@ public class AclSupportedParser extends AbstractParser<AclCapabilities> {
         }
 
         public AclCapabilities(int capabilities) {
+            // Protect against malicious or malformed packets
+            ValidateUtils.checkTrue((capabilities >= 0) && (capabilities < SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT),
+                "Illogical ACL capabilities count: %d", capabilities);
             this.capabilities = capabilities;
         }
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/db6e5b53/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java b/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
index b17405a..361fd11 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
@@ -791,7 +791,8 @@ public class SftpSubsystem
         }
 
         if (remaining < length) {
-            throw new IllegalStateException("Not enough buffer data for writing to " + fh + ": required=" + length + ", available=" + remaining);
+            throw new IllegalStateException("Not enough buffer data for writing to " + fh
+                + ": required=" + length + ", available=" + remaining);
         }
 
         SftpEventListener listener = getSftpEventListenerProxy();