5

I wanted to copy a single file from a remote server to my local machine.

I do not have root privileges on the remote machine but I can successfully SSH into a user given the password.

However the connection was closed, before anything was actually copied.

This is what I tried:

scp -P PORT user@SRC_HOST:/tmp/file /home/k4mp3t/

Using verbose mode I get the following output:

debug1: Next authentication method: password
Authenticated to HOST.IP ([IP]:PORT) using "password".
debug1: channel 0: new [client-session]
debug1: Requesting [email protected]
debug1: Entering interactive session.
debug1: pledge: filesystem
debug1: Sending subsystem: sftp
scp: Connection closed
debug1: client_input_channel_req: channel 0 rtype exit-signal reply 0
debug1: client_input_channel_req: channel 0 rtype [email protected] reply 0
debug1: channel 0: free: client-session, nchannels 1
Transferred: sent 2896, received 3328 bytes, in 0.1 seconds
Bytes per second: sent 36199.5, received 41599.5
debug1: Exit status -1

Why is the scp connection closed?

Information about remote machine:

ssh -V
OpenSSH_5.5p1 Debian-6+squeeze2, OpenSSL 0.9.8o 01 Jun 2010

Information about my machine:

ssh -V
OpenSSH_9.0p1, OpenSSL 1.1.1q  5 Jul 2022

OS: EndeavourOS Linux x86_64
Host: VirtualBox 1.2
Kernel: 5.18.14-arch1-1
Shell: bash 5.1.16

I'd be really thankful for any piece of help or resources that I could look into to solve this problem.

1
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking.
    – Community Bot
    Jul 27, 2022 at 3:01

1 Answer 1

10

tl;dr

Try scp -O, e.g.:

scp -O -P 1234 user@server:/tmp/file /home/k4mp3t/

Analysis

This fragment of the output:

debug1: Sending subsystem: sftp
scp: Connection closed

tells me your local scp tried to use the SFTP protocol. Traditional scp uses the SCP protocol which is different. Your scp is not traditional in this context.


History, SCP and SFTP

For many years scp (the executable) has been using SCP (the protocol) by default, without knowing any other protocol. I like to call SCP "a hack that stuck". To talk to a remote system by SCP, the local scp invokes ssh and passes a command. The command (like any command passed by ssh) is interpreted by the remote user's shell. The command tries to run scp on the remote side, using options not documented in man 1 scp that turn this scp into a server. Names of remote files are embedded in the shell code. If everything works then the local scp and the remote scp will eventually talk to each other and transfer data.

Unfortunately this is fragile; there are things that can easily break or abuse the protocol:

  1. If you need to quote or escape pathnames that are going to be used on the remote side, you need to quote or escape for the local shell and separately for the remote shell; i.e. you need two levels of quoting/escaping. On one hand this allows you to use wildcards on the remote side, e.g. locally quoted * may turn out to be unquoted on the remote side and expanded there. On the other hand if you really need to quote and if you don't know how these things work, you can easily craft a wrong command (example).

  2. If you know how, or if you are unfortunate enough to do it by mistake (maybe because of wrong quoting, see above), you can actually run arbitrary code on the remote side. In other words you can pass a "remote pathname" that will be interpreted by the remote shell as shell code (example). It's not really a security breach, as you can run the same code via ssh anyway (after all it's what your local scp does for you). The problem is in a potential ability to run something as code inadvertently.

  3. The server may give you files you didn't request and your local scp may accept them (depending on the implementation and version you're using, see this answer).

  4. If the remote "shell" is really not a shell (or if it's a shell incompatible with the POSIX shell, sh), even a simple, otherwise safe command may fail. This may include whatever command your local scp created.

  5. The remote shell may run something before it executes the command (example). If this involves printing to stdout (i.e. ultimately to the local scp) or reading from stdin (i.e. ultimately from the local scp) then the local scp will fail (example).

  6. If scp is not recognized as a command on the remote side then SCP is not supported. This will happen if there is no scp executable on the remote side or if $PATH in the remote user's shell does not include the directory of the remote scp.

SFTP is a protocol of better design. It certainly solves (1) and (2), I believe it solves (3). On the server side it may use a separate executable invoked via the remote user's shell, so (4) and (5) are still issues; a proper configuration may make it independent on the user's $PATH though, so (6) is solved. Or it may use Subsystem sftp internal-sftp (in sshd_config) and then (4) and (5) are solved (to a point where you can even fix the remote user's broken startup scripts).

SFTP is better than SCP, but sftp (the executable) is not always better than scp. sftp works well interactively, while the syntax of scp is similar to the syntax of cp (you can even scp a b like cp a b; scp simply falls back to cp for local copying, a misfeature for some). If you want to use one or the other to simply transfer few files non-interactively (e.g. in a script) then you will probably use scp which seems more straightforward.

Nowadays you can use scp with SFTP instead of SCP. Modern scp from OpenSSH uses SFTP by default. From the changelog:

OpenSSH 9.0 was released on 2022-04-08. […]

[…]

This release switches scp(1) from using the legacy scp/rcp protocol to using the SFTP protocol by default.


Back to your case

Your scp apparently is modern and it uses SFTP by default. The server in question does not support the relevant subsystem though. Normally disabling it is as simple as commenting out the Subsystem sftp … line. But then I would expect subsystem request failed; you got connection closed, so it's probably not exactly this. Still for some reason SFTP does not work with this server.


Solution

Force your scp to use SCP. From man 1 scp:

-O
Use the legacy SCP protocol for file transfers instead of the SFTP protocol. Forcing the use of the SCP protocol may be necessary for servers that do not implement SFTP, for backwards-compatibility for particular filename wildcard patterns and for expanding paths with a ~ prefix for older SFTP servers.

The command will be like:

scp -O …

Keep in mind this will use SCP with all its quirks.


Note on compatibility

Even if you know you want SCP, in general you cannot use scp -O … blindly. Implementations or versions of scp that know nothing about SFTP won't recognize -O and thus they will fail. I know your scp can use -O; it tried to use SFTP, so it must support -O. But if you try to do the same transfer from an old system with some old scp then you will have to omit -O.

Your original issue indicates you need to know what protocols the server supports. My point here is you also need to know what protocols and options your local scp supports.

To transfer files to or from the server in question:

  • a modern scp without -O doesn't work (because the server does not support SFTP), it should work with -O;
  • but an old scp cannot work with -O (because it doesn't recognize the option), it should work without -O;
  • and I have encountered scp that uses -O by default (and provides -s to force SFTP); this one should work with -O as well as without explicit -O.

The conclusion is: nowadays there is no universal syntax for scp if you want to use SCP.

1
  • Didnt expect such a detailed and great answer! Thanks a lot, you saved my day!
    – k4mp3t
    Jul 27, 2022 at 19:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .