ccontavalli / ssh-ident

Different agents and different keys for different projects, with ssh.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ssh config option being passed to rsync incorrectly

mc0e opened this issue · comments

commented

I have a personal $HOME/bin directory atthe start of my $PATH, containing rsync as a symlink to ssh-ident. It's coughing on the UseRoaming option in my $HOME/.ssh/config file:

$ rsync -avz -n {example.net:/path/,}dirname/
All keys already loaded
rsync: -oUseRoaming=no: unknown option
rsync error: syntax or usage error (code 1) at main.c(1572) [client=3.1.0]

That looks to me like -oUseRoaming=no is being passed to rsync, where it should be an option to the ssh sub-process that rsync creates, and it's probably passed on the command line.

There are many other options set in my .ssh/config which aren't creating this problem. It's notable though that it's the last option set in my $HOME/.ssh/config file. Here's the final HOST * stanza from that file:

Host *
ForwardAgent no
ForwardX11 no
GSSAPIAuthentication no
ServerAliveInterval 60
TCPKeepAlive yes

# http://www.revsys.com/writings/quicktips/ssh-faster-connections.html
ControlMaster auto
ControlPath ~/tmp/%r@%h:%p
ControlPersist 3600

Compression yes
# CVE-2016-0777
UseRoaming no
commented

I've also tried using an alias:

$ alias rsync='BINARY_SSH=/usr/bin/rsync $HOME/src/ssh-ident/ssh-ident'

and I've tried using a script at $HOME/bin/rsync:

#!/bin/bash
BINARY_SSH=/usr/bin/rsync /home/mc0e/src/ssh-ident/ssh-ident "$@"

I get the same error as above.

I encountered the same problem. I am using a version of OpenSSH that is not affected by the CVE-2016-0777 vulnerability, so I disabled the use of the UseRoaming option as a workaround.

You can create a ~/.ssh-ident file. Sample contents are shown in the README in the "Config file with multiple identities" section.

Note that the README file has an error. It should be:

SSH_DEFAULT_OPTIONS = "-oUseRoaming=no"

instead of

"SSH_DEFAULT_OPTIONS": "-oUseRoaming=no", 

or

SSH_DEFAULT_OPTIONS = ""

to disable the option altogether.

Did you try using the -e option with rsync? eg, use the original rsync, no changes, but use ssh-ident as a shell?

/usr/bin/rsync -e "ssh-ident" ...

Might work as a workaround, but non ideal.

The only fix I can think of would be to apply SSH_DEFAULT_OPTIONS only when the binary run is actually ssh, or turn SSH_DEFAULT_OPTIONS into a per-command dict. Eg,

DEFAULT_COMMAND_OPTIONS = {
"ssh": ["-oUseRoaming=no"]
}

The main drawback is that UseRoaming would only be disabled for actual ssh, and not rsync - so increasing security risk.

The problem is that with the link or BINARY_SSH trick, it's not ssh-ident running ssh, it's actually rsync. So ssh-ident can't really do much wrt how rsync starts ssh, short of coding explicit support for any such command.

I wonder though if there's a way to pass options via environment variables to ssh? That'd could work across rsync or other binaries.

Thanks for reporting the bug, though!

commented

rsync uses ssh for its transport by default, and that can be configured explicitly using the -e option to rsync.

ssh options should not ever be passed as arguments to rsync, so we don't want:

/path/to/real/rsync -oUseRoaming=no ...

rather we want:

 /path/to/real/rsync -e '/path/to/real/ssh -oUseRoaming=no' ...

or maybe just:

/path/to/real/rsync -e '~/bin/ssh' ...

And in this latter case we ~/bin/ssh is an alias to ssh-ident, and we count on that picking up the required ssh configuration options and passing them to the real ssh.

commented

It appears that the README should not recommend:

alias rsync='BINARY_SSH=rsync /path/to/ssh-ident'

I suspect that should be something along the lines of:

alias rsync='rsync -e "BINARY_SSH=ssh /path/to/ssh-ident"'

though that doesn't actually work:

rsync: Failed to exec BINARY_SSH=ssh: No such file or directory (2)

maybe aliases are just not a good approach with rsync?

$ cat ~/bin/rsync
#!/bin/bash
/usr/bin/rsync -e "/home/mc0e/bin/ssh" "$@"

OK, so that seems to work for what I've tried so far.

Maybe there's no reason

I think that

alias rsync='rsync -e "/path/to/ssh-ident"'

might work.

My solution has been to use the RSYNC_RSH environment variable, which I set to ~/bin/ssh, where ~/bin/ssh is actually ssh-ident. From rsync(1):

RSYNC_RSH
The RSYNC_RSH environment variable allows you to override the default shell used as the transport for rsync. Command line options are permitted after the command name, just as in the -e option.

commented

That's not enough to make it work:

$ alias rsync='rsync -e "/home/mc0e/src/ssh-ident/ssh-ident"'
$ rsync /tmp/foo example.org:/tmp/foo
ssh-ident found '/home/mc0e/bin/ssh' as the next command to run.
Based on argv[0] (/home/mc0e/src/ssh-ident/ssh-ident), it seems like this will create a
loop. 

Please use BINARY_SSH, BINARY_DIR, or change the way
ssh-ident is invoked (eg, a different argv[0]) to make
it work correctly.
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.0]

Is /home/mc0e/bin/ssh symlinked to (or a renamed version of) 'ssh-ident'? If so, my suggestion should work if amended to be one of:

alias rsync='rsync -e /home/mc0e/bin/ssh'
alias rsync='BINARY_SSH=ssh rsync -e /home/mc0e/src/ssh-ident/ssh-ident'

I forgot ssh-ident doesn't work if invoked directly, without some indication of which binary to invoke after setting up the keys.

$ alias rsync='BINARY_SSH=ssh rsync -e /cygdrive/c/Users/aglauser/tools/ssh-ident/ssh-ident'
$ rsync -avzn --itemize-changes example.com:/path/to/some/files/ /local/path/to/some/files
Loading keys:
    /home/aglauser/.ssh/id_rsa
Enter passphrase for /home/aglauser/.ssh/id_rsa:
Identity added: /home/aglauser/.ssh/id_rsa (/home/aglauser/.ssh/id_rsa)
Lifetime set to 7200 seconds
receiving incremental file list
[...]

I ran into the same problem with scp just being symlinked, because scp takes some of the same options that SSH takes, but not all of them.
How I got it to work now is by making stub executables for scp/sftp/rsync like this:

~/bin/scp:
/usr/bin/scp -S $(which ssh) $@

~/bin/sftp:
/usr/bin/sftp -S $(which ssh) $@

~/bin/rsync:
/usr/bin/rsync -e $(which ssh) $@

This way ssh-ident gets invoked as ssh, and handles the parameters correctly.
Maybe ssh-ident could detect if it's being invoked as scp/sftp/rsync and then recursively call itself as ssh through the -S or -e parameter?

Regarding aliases, they are almost always a bad idea. Even the bash man page explicitly states that "for almost every purpose, aliases are superseded by shell functions".

Regarding the attempt at incorporating rsync that was posted previously:

alias rsync='rsync -e "BINARY_SSH=ssh /path/to/ssh-ident"'

This could instead be written as:

rsync() { BINARY_SSH=ssh command rsync -e "/path/to/ssh-ident" "$@"; }

Such will work as was intended under both bash and sh (POSIX).

Granted, this trivial example could also have been made to work as an alias. Still, I would recommend against documenting the use of aliases because they are subject to various pitfalls - too many to describe here - and will fail as soon as the user attempts to contort them so as to handle all but the simplest of requirements.

An additional advantage of functions is that, under bash, they can be exported into the environment of subsequently executed shells, which is sometimes useful.

Have a look at my fork at https://github.com/maddes-b/ssh-ident
There I extended SSH_OPTIONS to specify parameters per identiy and/or binary.