Getting a “Sink” error when using an SCP command

command linescpssh

I am trying to copy a file from my local host to remote host using SCP command:

scp -v user@xxx.xxx.xxx.xxx:/local/file/path /destination/path

Surprisingly the SCP command fails at the end after password authentication. I am able to do SSH to remote system but SCP fails. Here is the error which I got at the end.

debug1: rekey after 4294967296 blocks
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: rekey after 4294967296 blocks
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: password
debug1: Next authentication method: password
admin@192.168.1.12's password:
debug1: Authentication succeeded (password).
Authenticated to 192.168.1.12 ([192.168.1.12]:22).
debug1: channel 0: new [client-session]
debug1: Entering interactive session.
debug1: pledge: network
debug1: Sending command: scp -v -f /home/random/sample.txt
Sink: C0777 630 /home/random/sample.txt
error: unexpected filename: /home/random/sample.txt

What is the cause of failure, I have verified that the source file exists. I am not able to understand what's this error message Sink: C0777 630

Best Answer

Your remote side implements the SCP "protocol" in a way, which is not compatible to the OpenSSH implementation of scp which you will find typically on a Linux or BSD machine.

After reading through code from OpenSSH scp, BSD rcp and Putty pscp (see below) it seems it is normal that one has to wade through the sources to understand SCP. This archived web page says:

Have you ever wondered how the scp and rcp commands worked? The first time I did I haven't found any documentation on the subject. There is no RFC, no draft, not even README file describing it. After reading the source code I tried again and realized that old version of rcp.c might be really the only original documentation available.

(Jan Pechanec's weblog: "How the SCP protocol works", copy from Februay 15, 2017)

Using the explanation from above's page and your command

scp -v user@xxx.xxx.xxx.xxx:/local/file/path /destination/path

It means you copy stuff from the remote system (InterNiche scp, which is in "source" mode) to your system (likely OpenSSH scp, in "sink" mode).

However the remote system gives you paths over several directories during the exchange under SCP protocol:

C0777 630 /home/random/sample.txt
<data of sample.txt>

while your scp can only deal with something like:

D0755 0 home
D0755 0 random
C0777 630 sample.txt
<data of sample.txt>
E
E

The solution is to check for a different scp implementation on your local system, or try sftp instead:

sftp -q user@xxx.xxx.xxx.xxx:/remote/file/path /local/destination/path

My inital answer, updated later:

Sink: C0777 630 /home/random/sample.txt

It seems to originate from scp.

E.g. you can have a look at line 969, which is a recent version of OpenSSH used by FreeBSD.

if (verbose_mode)
    fmprintf(stderr, "Sink: %s", buf);

Translation: If in verbose mode then display the "Sink:" message, with the string pointed to by buf You provided the -v option.

It seems to display the remaining buffer. C0777 seems to be a BSD rcp command, see the header

 * scp - secure remote copy.  This is basically patched BSD rcp which
 * uses ssh to do the data transfer (instead of using rcmd).

and line 1023.

This one

error: unexpected filename: /home/random/sample.txt

is written by line 1051:

if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) {
    run_err("error: unexpected filename: %s", cp);
    exit(1);

Translation: if the string pointed to by cp contains a slash (/) character or is equal to the string .. then print the error message. Your string features a slash.

It seems that scp is not getting what it expects from its conversation with the remote ssh instance.

Update:

Sink is the counter part to the Source call. Here we have the other side from the OpenSSH implementation:

    snprintf(buf, sizeof buf, "C%04o %lld %s\n",
        (u_int) (stb.st_mode & FILEMODEMASK),
        (long long)stb.st_size, last);

From the code before it is clear that these three arguments are the file mode (permission bits), file size and file name. Again the file name is not allowed to contain a slash, otherwise it is ignored.

It looks like a directory tree is recursively walked and only the name of the walked level is handled.

By the way, the code in OpenSSH scp seems really old, the cited stuff is already in the BSD 4.x rcp implementation. See here.

Having a look at the pscp implementation (Putty scp) here we can recognize the BSD stuff (see around line 1524), but the filename handling is different. That is why it works.

Related Question