SCP path handling: escape path argument to scp command, handle spaces in messages from remote SCP command

This commit is contained in:
Shikhar Bhushan
2011-04-10 14:24:14 +01:00
parent d1043ea288
commit d8cc271cd3
2 changed files with 44 additions and 27 deletions

View File

@@ -15,15 +15,17 @@
*/ */
package net.schmizz.sshj.xfer.scp; package net.schmizz.sshj.xfer.scp;
import java.io.IOException;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;
import net.schmizz.sshj.common.IOUtils; import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.xfer.LocalDestFile; import net.schmizz.sshj.xfer.LocalDestFile;
import net.schmizz.sshj.xfer.scp.SCPEngine.Arg; import net.schmizz.sshj.xfer.scp.SCPEngine.Arg;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
/** Support for uploading files over a connected link using SCP. */ /** Support for uploading files over a connected link using SCP. */
public final class SCPDownloadClient { public final class SCPDownloadClient {
@@ -119,7 +121,7 @@ public final class SCPDownloadClient {
throw new SCPException("Remote SCP command returned error: " + msg.substring(1)); throw new SCPException("Remote SCP command returned error: " + msg.substring(1));
default: default:
String err = "Unrecognized message: `" + msg + "`"; final String err = "Unrecognized message: `" + msg + "`";
engine.sendMessage((char) 2 + err); engine.sendMessage((char) 2 + err);
throw new SCPException(err); throw new SCPException(err);
} }
@@ -129,9 +131,9 @@ public final class SCPDownloadClient {
private void processDirectory(String dMsg, String tMsg, LocalDestFile f) private void processDirectory(String dMsg, String tMsg, LocalDestFile f)
throws IOException { throws IOException {
final String[] dMsgParts = tokenize(dMsg, 3); // D<perms> 0 <dirname> final List<String> dMsgParts = tokenize(dMsg, 3, true); // D<perms> 0 <dirname>
final long length = parseLong(dMsgParts[1], "dir length"); final long length = parseLong(dMsgParts.get(1), "dir length");
final String dirname = dMsgParts[2]; final String dirname = dMsgParts.get(2);
if (length != 0) if (length != 0)
throw new IOException("Remote SCP command sent strange directory length: " + length); throw new IOException("Remote SCP command sent strange directory length: " + length);
engine.startedDir(dirname); engine.startedDir(dirname);
@@ -140,7 +142,7 @@ public final class SCPDownloadClient {
engine.signal("ACK: D"); engine.signal("ACK: D");
do { do {
} while (!process(null, engine.readMessage(), f)); } while (!process(null, engine.readMessage(), f));
setAttributes(f, parsePermissions(dMsgParts[0]), tMsg); setAttributes(f, parsePermissions(dMsgParts.get(0)), tMsg);
engine.signal("ACK: E"); engine.signal("ACK: E");
} }
engine.finishedDir(); engine.finishedDir();
@@ -148,9 +150,9 @@ public final class SCPDownloadClient {
private void processFile(String cMsg, String tMsg, LocalDestFile f) private void processFile(String cMsg, String tMsg, LocalDestFile f)
throws IOException { throws IOException {
final String[] cMsgParts = tokenize(cMsg, 3); // C<perms> <size> <filename> final List<String> cMsgParts = tokenize(cMsg, 3, true); // C<perms> <size> <filename>
final long length = parseLong(cMsgParts[1], "length"); final long length = parseLong(cMsgParts.get(1), "length");
final String filename = cMsgParts[2]; final String filename = cMsgParts.get(2);
engine.startedFile(filename, length); engine.startedFile(filename, length);
{ {
f = f.getTargetFile(filename); f = f.getTargetFile(filename);
@@ -162,7 +164,7 @@ public final class SCPDownloadClient {
IOUtils.closeQuietly(dest); IOUtils.closeQuietly(dest);
} }
engine.check("Remote agrees transfer done"); engine.check("Remote agrees transfer done");
setAttributes(f, parsePermissions(cMsgParts[0]), tMsg); setAttributes(f, parsePermissions(cMsgParts.get(0)), tMsg);
engine.signal("Transfer done"); engine.signal("Transfer done");
} }
engine.finishedFile(); engine.finishedFile();
@@ -172,17 +174,28 @@ public final class SCPDownloadClient {
throws IOException { throws IOException {
f.setPermissions(perms); f.setPermissions(perms);
if (tMsg != null) { if (tMsg != null) {
String[] tMsgParts = tokenize(tMsg, 4); // e.g. T<mtime> 0 <atime> 0 List<String> tMsgParts = tokenize(tMsg, 4, false); // e.g. T<mtime> 0 <atime> 0
f.setLastModifiedTime(parseLong(tMsgParts[0].substring(1), "last modified time")); f.setLastModifiedTime(parseLong(tMsgParts.get(0).substring(1), "last modified time"));
f.setLastAccessedTime(parseLong(tMsgParts[2], "last access time")); f.setLastAccessedTime(parseLong(tMsgParts.get(2), "last access time"));
} }
} }
private String[] tokenize(String msg, int numPartsExpected) private static List<String> tokenize(String msg, int totalParts, boolean consolidateTail)
throws IOException { throws IOException {
String[] parts = msg.split(" "); List<String> parts = Arrays.asList(msg.split(" "));
if (parts.length != numPartsExpected) if (parts.size() < totalParts ||
(!consolidateTail && parts.size() != totalParts))
throw new IOException("Could not parse message received from remote SCP: " + msg); throw new IOException("Could not parse message received from remote SCP: " + msg);
if (consolidateTail && totalParts < parts.size()) {
final StringBuilder sb = new StringBuilder(parts.get(totalParts - 1));
for (int i = totalParts; i < parts.size(); i++) {
sb.append(" ").append(parts.get(i));
}
parts = new ArrayList<String>(parts.subList(0, totalParts - 1));
parts.add(sb.toString());
}
return parts; return parts;
} }

View File

@@ -101,7 +101,11 @@ class SCPEngine {
StringBuilder cmd = new StringBuilder(SCP_COMMAND); StringBuilder cmd = new StringBuilder(SCP_COMMAND);
for (Arg arg : args) for (Arg arg : args)
cmd.append(" ").append(arg); cmd.append(" ").append(arg);
cmd.append(" ").append((path == null || path.equals("")) ? "." : path); cmd.append(" ");
if (path == null || path.isEmpty())
cmd.append(".");
else
cmd.append("'").append(path.replaceAll("'", "\\'")).append("'");
scp = host.startSession().exec(cmd.toString()); scp = host.startSession().exec(cmd.toString());
} }