Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SCP upload to Windows 11 Open SSH fails with no such file or directory error #929

Open
robertpatrick opened this issue Feb 15, 2024 · 3 comments

Comments

@robertpatrick
Copy link

robertpatrick commented Feb 15, 2024

We are using SSHJ to add remoting capabilities to our app. We are currently testing cross-platform capabilities where the client is running on Linux connecting to a Windows 11 Enterprise server using the OpenSSH server provided by the Windows distribution. SSH is working fine. SCP download is working fine. SCP upload is failing with:

Exception in thread "main" net.schmizz.sshj.xfer.scp.SCPRemoteException: Remote SCP command had error: scp: 'c:\Temp\model.yaml': No such file or directory
        at net.schmizz.sshj.xfer.scp.SCPEngine.check(SCPEngine.java:73)
        at net.schmizz.sshj.xfer.scp.SCPEngine.sendMessage(SCPEngine.java:133)
        at net.schmizz.sshj.xfer.scp.SCPUploadClient.sendFile(SCPUploadClient.java:105)
        at net.schmizz.sshj.xfer.scp.SCPUploadClient.process(SCPUploadClient.java:84)
        at net.schmizz.sshj.xfer.scp.SCPUploadClient.startCopy(SCPUploadClient.java:76)
        at net.schmizz.sshj.xfer.scp.SCPUploadClient.copy(SCPUploadClient.java:54)
        at net.schmizz.sshj.xfer.scp.SCPUploadClient.copy(SCPUploadClient.java:47)
        at net.schmizz.sshj.xfer.scp.SCPUploadClient.copy(SCPUploadClient.java:43)
        at net.schmizz.sshj.xfer.scp.SCPFileTransfer.upload(SCPFileTransfer.java:98)
        at net.schmizz.sshj.xfer.scp.SCPFileTransfer.upload(SCPFileTransfer.java:61)
        at net.schmizz.sshj.xfer.scp.SCPFileTransfer.upload(SCPFileTransfer.java:55)
        at com.oracle.test.SSHTest.main(SSHTest.java:36)

The odd thing is that scp from the command-line works fine.

[rpatrick@rpatrick-1 ssh-test]$ scp ./model.yaml rpatrick@<internal-hostname-redacted>:c:\\Temp\\model.yaml
model.yaml                                                                                                                                                                                100%  486   238.1KB/s   00:00
[rpatrick@rpatrick-1 ssh-test]$

My code is just a little sample that I created trying to debug this problem. As you can see, it isn't doing anything fancy and is allowing SSHJ to get the default username and SSH private key (from ~/.ssh/id_rsa).

package com.oracle.test;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.connection.channel.direct.Session.Command;
import net.schmizz.sshj.xfer.scp.SCPFileTransfer;


public class SSHTest {
    public static void main(String[] args) throws Exception {
        try (SSHClient sshClient = new SSHClient()) {
            sshClient.loadKnownHosts();
            sshClient.connect("<internal-hostname-redacted>");
            Session session = null;
            try {
                sshClient.authPublickey(System.getProperty("user.name"));
                session = sshClient.startSession();
                final Command cmd = session.exec("wmic os get caption");
                System.out.print(IOUtils.readFully(cmd.getInputStream()));
                cmd.join(5, TimeUnit.SECONDS);
                System.out.println("\n** exit status: " + cmd.getExitStatus() + "\n\n");

                SCPFileTransfer scpFileTransfer = sshClient.newSCPFileTransfer();
                scpFileTransfer.download("c:\\Temp\\ssh\\model.yaml", "./model.yaml");
                System.out.println("Downloaded file\n\n");

                scpFileTransfer = sshClient.newSCPFileTransfer();
                scpFileTransfer.upload("./model.yaml", "c:\\Temp\\model.yaml");
                System.out.println("Uploaded file\n\n");
            } finally {
                if (session != null) {
                    try { session.close(); } catch (IOException ex) { /* ignore */ }
                }
                sshClient.disconnect();
            }
        }
    }
}

In the output from this program, I see the following before the stack trace:

Caption
Microsoft Windows 11 Enterprise


** exit status: 0


Downloaded file


Exception in thread "main" net.schmizz.sshj.xfer.scp.SCPRemoteException: Remote SCP command had error: scp: 'c:\Temp\model.yaml': No such file or directory
...
@robertpatrick
Copy link
Author

Here is the relevant snippet from the OpenSSH server log:

7588 2024-02-16 08:20:33.372 Starting session: command for oradev\\\\rpatrick from 10.89.201.18 port 57849 id 0
7588 2024-02-16 08:20:33.373 debug2: fd 10 setting O_NONBLOCK
7588 2024-02-16 08:20:33.373 debug2: fd 11 setting O_NONBLOCK
7588 2024-02-16 08:20:33.373 debug2: fd 12 setting O_NONBLOCK
7588 2024-02-16 08:20:33.373 debug2: fd 13 setting O_NONBLOCK
7588 2024-02-16 08:20:33.373 debug2: fd 14 setting O_NONBLOCK
7588 2024-02-16 08:20:33.373 debug2: fd 15 setting O_NONBLOCK
7588 2024-02-16 08:20:33.373 debug3: shell: "c:\\\\windows\\\\system32\\\\cmd.exe"
7588 2024-02-16 08:20:33.373 debug3: shell_option: /c
7588 2024-02-16 08:20:33.374 debug3: exec_command: scp.exe -t -r -p 'c://Temp//'
7588 2024-02-16 08:20:33.374 debug3: arg escape option: TRUE
7588 2024-02-16 08:20:33.374 debug3: spawn_argv[0]: "c:\\\\windows\\\\system32\\\\cmd.exe" /c "scp.exe -t -r -p 'c://Temp//'"
7588 2024-02-16 08:20:33.374 debug3: spawning "c:\\\\windows\\\\system32\\\\cmd.exe" /c "scp.exe -t -r -p 'c://Temp//'" as subprocess
7588 2024-02-16 08:20:33.383 debug3: fd 12 is O_NONBLOCK
7588 2024-02-16 08:20:33.383 debug3: fd 11 is O_NONBLOCK
7588 2024-02-16 08:20:33.383 debug3: fd 14 is O_NONBLOCK
7588 2024-02-16 08:20:33.383 debug3: send packet: type 99
7588 2024-02-16 08:20:33.707 debug3: receive packet: type 97
7588 2024-02-16 08:20:33.707 debug2: channel 0: rcvd close
7588 2024-02-16 08:20:33.707 debug2: channel 0: output open -> drain
7588 2024-02-16 08:20:33.707 debug2: chan_shutdown_read: channel 0: (i0 o1 sock -1 wfd 12 efd 14 [read])
7588 2024-02-16 08:20:33.707 debug1: chan_shutdown_extended_read: channel 0: (i0 o1 sock -1 wfd -1 efd 14 [read])
7588 2024-02-16 08:20:33.707 debug2: channel 0: input open -> closed
7588 2024-02-16 08:20:33.707 debug3: channel 0: will not send data after close
7588 2024-02-16 08:20:33.707 debug2: channel 0: obuf empty
7588 2024-02-16 08:20:33.707 debug2: chan_shutdown_write: channel 0: (i3 o1 sock -1 wfd 11 efd -1 [closed])
7588 2024-02-16 08:20:33.707 debug2: channel 0: output drain -> closed
7588 2024-02-16 08:20:33.707 debug2: channel 0: almost dead
7588 2024-02-16 08:20:33.707 debug2: channel 0: gc: notify user
7588 2024-02-16 08:20:33.707 debug1: session_by_channel: session 0 channel 0
7588 2024-02-16 08:20:33.708 debug1: session_close_by_channel: channel 0 child 2520
7588 2024-02-16 08:20:33.708 debug1: session_close_by_channel: channel 0: has child, ttyfd -1
7588 2024-02-16 08:20:33.718 debug1: Received SIGCHLD.
7588 2024-02-16 08:20:33.718 debug1: session_by_pid: pid 2520
7588 2024-02-16 08:20:33.718 debug1: session_exit_message: session 0 channel 0 pid 2520
7588 2024-02-16 08:20:33.718 debug2: channel 0: request exit-status confirm 0
7588 2024-02-16 08:20:33.718 debug3: send packet: type 98
7588 2024-02-16 08:20:33.719 debug1: session_exit_message: release channel 0
7588 2024-02-16 08:20:33.719 debug2: channel 0: send close
7588 2024-02-16 08:20:33.719 debug3: send packet: type 97
7588 2024-02-16 08:20:33.719 debug2: channel 0: is dead
7588 2024-02-16 08:20:33.719 debug2: channel 0: gc: notify user
7588 2024-02-16 08:20:33.719 debug1: session_by_channel: session 0 channel 0
7588 2024-02-16 08:20:33.719 debug1: session_close_by_channel: channel 0 child 0
7588 2024-02-16 08:20:33.719 Close session: user oradev\\\\rpatrick from 10.89.201.18 port 57849 id 0

@robertpatrick
Copy link
Author

It appears that the escaping/path conversion is different between download and upload. Notice how the Windows path has // in the failing upload case and / in the successful download case. My input paths in both cases use \\ separators. Maybe this is the cause of the "No such file or directory" error?

Upload snippet from SSH server log:

4276 2024-02-16 09:31:16.488 debug3: shell: "c:\\\\windows\\\\system32\\\\cmd.exe"
4276 2024-02-16 09:31:16.488 debug3: shell_option: /c
4276 2024-02-16 09:31:16.488 debug3: exec_command: scp.exe -t -r -p 'c://Temp'
4276 2024-02-16 09:31:16.488 debug3: arg escape option: TRUE
4276 2024-02-16 09:31:16.488 debug3: spawn_argv[0]: "c:\\\\windows\\\\system32\\\\cmd.exe" /c "scp.exe -t -r -p 'c://Temp'"
4276 2024-02-16 09:31:16.488 debug3: spawning "c:\\\\windows\\\\system32\\\\cmd.exe" /c "scp.exe -t -r -p 'c://Temp'" as subprocess

Download snippet from SSH server log:

4724 2024-02-16 09:26:34.519 debug3: shell: "c:\\\\windows\\\\system32\\\\cmd.exe"
4724 2024-02-16 09:26:34.519 debug3: shell_option: /c
4724 2024-02-16 09:26:34.519 debug3: exec_command: scp.exe -f -q -p -r c:/Temp/ssh/model.yaml
4724 2024-02-16 09:26:34.519 debug3: arg escape option: TRUE
4724 2024-02-16 09:26:34.519 debug3: spawn_argv[0]: "c:\\\\windows\\\\system32\\\\cmd.exe" /c "scp.exe -f -q -p -r c:/Temp/ssh/model.yaml"
4724 2024-02-16 09:26:34.519 debug3: spawning "c:\\\\windows\\\\system32\\\\cmd.exe" /c "scp.exe -f -q -p -r c:/Temp/ssh/model.yaml" as subprocess

I'm not sure where exactly the code is that is converting the upload path. I tried changing it in a couple of different places and rebuilding the JAR as a test but it seems to have no effect.

@robertpatrick
Copy link
Author

@hierynomus Any thoughts on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant