Linux – “protocol version mismatch — is your shell clean?” rsync error when the shell IS clean

linuxrsyncsshUbuntu

I'm trying to download files using rsync with rsync running in daemon mode over SSH on the server and get the following error on the client:

rsync -a myserver:/remote/path/ localdestdir/
protocol version mismatch -- is your shell clean?
(see the rsync man page for an explanation)
rsync error: protocol incompatibility (code 2) at compat.c(176) [Receiver=3.1.1]

The server has this in .ssh/authorized_keys for the user:

command="rsync --config=/path/to/engine-rsyncd.conf --server --daemon ." ssh-rsa ...

I've read all I could find about this problem and, as everyone suggests, checked that the shell is clean and IT IS CLEAN:

ssh myserver false >out.tmp

creates a zero-length file out.tmp (if I remove the "command=…" from authorized_keys on the server).

I also tried setting the user's shell to rssh instead of bash on the server – same thing.

Both client and server are running Ubuntu 16.04, so they have the same version of rsync (3.3.1, protocol 31).

What else could it be? I tried enabling verbose logging in rsync and SSH and the logs don't give me any clue. The rsync daemon doesn't log anything more than

2018/02/12 15:14:24 [6215] connect from clienthostname

Best Answer

You problem in this case is not that the shell is not clean, but that the client rsync can execute the command it needs to execute on the server. If you use the command="rsync..." in authorized_keys, then that is the command that sshd will execute, regardless of the command that is passed by the client.

The client rsync will call ssh with these arguments:

ssh myserver rsync --server --sender -de.LsfxC . /remote/path/`.

Note that --sender is part of these options, because you want the server to send you files. It is not present if the server should receive files. Note also that --daemon is not present in the options to rsync. As the option --config is only relevant together with --daemon, it can also be removed from your command entry.

Is I already mentioned, the command will be executed exactly as it is in the authorized_keys file. That means that all arguments that are passed from the client will be ignored. So if you really want to use command in authorized_keys, you have to specify the exact options that rsync would supply to the ssh client, and that means you can use rsync only to receive files from exactly the path the is specified in authorized_keys. If you supply different options to the rsync on the client, they will not be effective on the server and therefor may or may not work depending on whether the effect of these options is implemented on the client or on the server side of rsync. So you should consider whether you really want that.

Edit You can use a script as the command and examine the SSH_ORIGINAL_COMMAND environment variable to call rsync as needed. As the remote path is the last argument, you might just want to check whether it starts with the right prefix and doesn't contain any "/.." that would go to the parent directory.