2

I am trying to transfer a file from local to remote with scp. Local is windows(OpenSSH is running as service) and remote is FreeBSD(rsa key are setup). For this i am using Jsch library.

try {
        if (ses == null) ses = fsaTo.getSession();
        channel = ses.openChannel("exec");
        String cmd = "scp "+ UserHostIdentity.getTransferUser(fsaFrom.getSystem()) + "@" 
                + UserHostIdentity.getTransferHost(fsaFrom.getSystem()) + ":"
                + from + " " 
                + to;
        ((ChannelExec)channel).setCommand(cmd);
        ((ChannelExec)channel).setErrStream(System.err);
        channel.connect();
    } catch (JSchException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

The command cmd I tested it manually executing it and it worked. This is how I start up the session:

JSch jsch = new JSch();
    try {
        sshSession = jsch.getSession(UserHostIdentity.getTransferUser(fs), UserHostIdentity.getTransferHost(fs),22);
        UserInfo lui = UserHostIdentity.getTransferUserInfo(fs);
        sshSession.setUserInfo(lui);
        sshSession.setConfig("StrictHostKeyChecking", "no");
        sshSession.connect();
    } catch (JSchException e) {
        logger.error("Could not access fileserver.");
        throw new RuntimeException(e);
    }

The issue is after calling channel.connect() nothing happens, no error, nothing. In the same context the following code executes "sha256 -q " + filePath and returns correct results:

public String doCommand(String cmd) {
    if (sshSession == null) {
        initiateConnection();
    }

    Channel channel;
    String result = "";
    try {
        channel = sshSession.openChannel("exec");
        ((ChannelExec)channel).setCommand(cmd);
        channel.setInputStream(null);
        ((ChannelExec)channel).setErrStream(System.err);

        InputStream input = channel.getInputStream();
        channel.connect(); 
        InputStreamReader inputReader = new InputStreamReader(input);
        BufferedReader bufferedReader = new BufferedReader(inputReader);
        String line = null;

        while((line = bufferedReader.readLine()) != null){
            result = line;
        }
        bufferedReader.close();
        inputReader.close();
        channel.disconnect();
    } catch (JSchException e) {
        logger.error("Problem with communication to Fileserver.");
        throw new RuntimeException(e);
    } catch (IOException e) {
        logger.error("Problem with command stream.");
        throw new RuntimeException(e);
    }
    return result;
}

My question is, why doesnt it work with the scp command.

3 Answers3

0

The best thing to start with is maybe running scp with the verbose parameter:

scp -v src dest

Or if that does not help see if you can install strace (if you haven't already) and run:

strace scp -v src dest

This should give you a hint as to what might be wrong (although you say you that host keys were set up, did you test it?), e.g.:

  • Host key verification might have failed
  • You might need to enter a passphrase for the private key
  • There might be some security incompatability
  • etc.

Also you forget to keep reading the InputStream, maybe do something like this around the channel.connect() line:

InputStream in = channel.getInputStream();
channel.connect();
in.transferTo(System.out);

Or keep reading the InputStream (the stdout from scp) like with the sha256 command until the process has completed (that way it works on my machine).

JohannesB
  • 2,214
  • 1
  • 11
  • 18
  • Could you discribe what you mean by this "It interleaves the reading from both channels without blocking, another approach would be to use seperate threads that each can block until there is something to read." Also I tried to put out the output according to the post you linked, but the code just hangs. `in` and `err` returns nothing and channel is still open. BTW I am trying to move an empty .txt file. – Kristóf Horváth May 28 '20 at 08:20
  • See also this example https://stackoverflow.com/a/47554723/6250649 – JohannesB May 30 '20 at 17:32
0

OK, so what your code is doing is:

  1. Using SSH to connecting to <fsaTo>.
  2. On <fsaTo> run the command "scp @:/ ".

The scp command will be trying to open another SSH connection back to <fsaFrom> ... which is presumable this host ... and pull the file back over that connection

This could work, but will only work if:

  • <fsaFrom> is listening for incoming SSH connections
  • the <fsaTo> account that you are using has an SSH private key (without a passphrase) that corresponds to one of the public keys registered for logging in to <fsaFrom> as <user>.

There is a better way that doesn't have any preconditions. There are some undocumented command line switches for the scp command that are used on the remote system when you run the scp command as a normal command.

  • scp -f <remote-file> reads from <remote-file> and sending it to the ssh output stream.
  • scp -t <remote-file> reads from the ssh input stream and outputs to <remote-file>.

For more details, see SSH: The Secure Shell, the definitive guide section 3.8.

Or if you just want an example, the JSch ScpTo.java example shows how to do what you are trying to do.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
0

Why not use SFTP if you are already using JSch library?

See the sample code which is uploading file with JSch SFTP:

public void uploadFile(File file, String location) {
    ChannelSftp channelSftp = null;
    try {
        channelSftp = (ChannelSftp)connect();
        if(location.startsWith(ROOT_DIR)) {
            channelSftp.cd(ROOT_DIR);
        }
        final List<String> directories = Splitter.on(File.separatorChar).omitEmptyStrings().splitToList(location);
        for(String dir : directories) {
            try {
                channelSftp.ls(dir);
            } catch (SftpException e) {
                channelSftp.mkdir(dir);
            }
            channelSftp.cd(dir);
        }
        if(LOGGER.isDebugEnabled()) {
            LOGGER.debug("Uploading file " + file.getPath() + " in " + location);
        }
        channelSftp.put(new FileInputStream(file), file.getName());
    } catch(Throwable e) {
        throw new RuntimeException("Upload file " + file.getPath() + " failed.", e);
    } finally {
        disconnect(channelSftp);
    }
}
potatojesz
  • 81
  • 6