Experiment in wrapping ssh inside a script and passing arbitrary commands to another program

Note: This has been solved. Please see the answer here.

Wrapping ssh inside a script and passing it arbitrary commands is hard. What I am trying to do here is to come up with a generic way to invoke an ssh-wrapper, have it record the $(pwd), perform an ssh to a remote host, and at the remote host, reposition inside $(pwd), and run an arbitrary, possibly interactive, program.

Let’s first start with an ssh-wrapper

$ cat ssh-wrapper
#!/bin/bash
ssh -t localhost "$(pwd)/remote_script '$*'"

Then we define the remote-script

$ cat remote-script
#!/bin/bash
eval $*

Now let’s try some commands, and compare with what bash -c does:

$ ssh-wrapper "echo ' hi'"
hi
$ bash -c "echo ' hi'"
 hi

Notice that bash -c correctly renders the space preceding hi, but ssh-wrapper does not. This indicates potential future problems. Let’s try another case:

$ ssh-wrapper "echo hi && echo hello"
hi
hello
$ bash -c "echo hi && echo hello"
hi
hello

Nothing here. Let’s try another one:

$ bash -c "FOO='a b' && echo ' hi' && echo $FOO"
 hi

$ ssh-wrapper "FOO='a b' && echo ' hi' && echo $FOO"
remote_script: line 4: b: command not found

It starts to hurt here. The bash -c does the correct thing ($FOO is expanded before the value is set, which is correct), but in the ssh-wrapper, things go wrong. However, a different quoting produces a better outcome:

$ ssh-wrapper 'FOO="a b" && echo " hi" && echo $FOO'
 hi
a b
$ bash -c 'FOO="a b" && echo " hi" && echo $FOO'
 hi
a b

This works better, and even the space preceding “hi” is present. However, we can see that ssh-wrapper is not very end user proof. And end users are non-linear: give them that script, and they will break it right away.

Let’s modify the original scripts to position the remote execution in the correct path and add a potentially interactive program:

$ cat ssh-wrapper
#!/bin/bash
ssh -t localhost "$(pwd)/remote_script $(pwd) ./prog '$*'"

$ cat remote-script
#!/bin/bash
cd $1 && $2 $3

$ cat prog
#!/bin/bash
eval "$@"
# This program traps INT and queries the user for input
function process_int {
  echo -n "INT> "
  read LINE
  echo $LINE
  exit 2
}
trap process_int SIGINT
sleep 30

The difference here is that the remote-script will place us in the path where the ssh-wrapper was originally called before calling ./prog. Now we try our command again:

$ ssh-wrapper 'FOO="a b" && echo " hi" && echo $FOO'
 hi
a b
^CINT> it works!
it works!
$

You need to hit ctrl-c to get out here, then type some arbitrary string. It works, but is far from being robust: the way to make it fail is by changing the quoting:

$ ssh-wrapper "FOO='a b' && echo ' hi' && echo $FOO"
Executing FOO=a
^CINT> ^CConnection to localhost closed.
$

We are not better off. The prog did not interpreted the whole command, only FOO=a!

This is annoying, because I may want to allow variables to be expanded on the original command line, and hence it would be very nice to allow users to use double-quotes in their argument to ssh-wrapper. In fact, it is necessary to allow either type of quoting to work, bash -c works with both, so should ssh-wrapper.

Let’s change remote-script to pass all arguments after $2:

$ cat remote-script
#!/bin/bash
cd $1 && $2 ${@:3}

And we try again:

$ ssh-wrapper "FOO='a b' && echo ' hi' && echo $FOO"
./prog: line 6: b: command not found
^CINT> ^CConnection to localhost closed.

This time, the quoting around the variable assignment is gone, so b is interpreted as a command! At this point I have run out of ideas on how to make this work.

This has been solved. Please see the answer here.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: