Running commands via SSH

1,059 views
Skip to first unread message

kbur...@gmail.com

unread,
Nov 26, 2016, 1:35:28 PM11/26/16
to golang-nuts
Hi, I'd like to SSH to a remote host and run an arbitrary command. I found this pretty difficult to do with existing Go libraries.

The first problem I had was around escaping; commands run locally are appropriately escaped but I found it difficult to get the right escaping for commands run remotely. As an example, this hangs, I believe because of the {<& in the middle of the command.

cmd := exec.Command("ssh", "remote-host", "echo", "zdUZUKv{<&MsZG")
bits, err := cmd.CombinedOutput()
if err != nil {
log.Fatal(err)
}
os.Stdout.Write(bits)

Note exec.Command("echo", "{<&") runs just fine.

I then wondered if creating a ssh Session (via golang.org/x/crypto/ssh) and running the command would help. But I wasn't able to get this working that well; when I run exec.Command("ssh", "remote-host"), the ssh command will parse my local .ssh/config and pull the appropriate settings from there, but the Go library doesn't.

- Is there a tool or library for appropriately escaping commands run on a remote machine? I understand this can lead to security problems and am worried about getting this wrong
- Is there a tool or library for parsing SSH configs & returning the appropriate configuration for a host? I found one community library, but the parser was not implemented very well.

Thanks for your help,
Kevin

Shawn Milochik

unread,
Nov 26, 2016, 1:44:03 PM11/26/16
to golang-nuts
It works for me (over ssh) when I run this string as the command:   `echo 'zdUZUKv{<&MsZG'`

Use backticks for the string literal, then enclose your argument string in single-quotes.


Ayan George

unread,
Nov 27, 2016, 12:54:42 AM11/27/16
to kbur...@gmail.com, golang-nuts
kbur...@gmail.com wrote:

> Hi, I'd like to SSH to a remote host and run an arbitrary command. I found
> this pretty difficult to do with existing Go libraries.
>
> The first problem I had was around escaping; commands run locally are
> appropriately escaped but I found it difficult to get the right escaping
> for commands run remotely. As an example, this hangs, I believe because of
> the {<& in the middle of the command.
>
> cmd := exec.Command("ssh", "remote-host", "echo", "zdUZUKv{<&MsZG")
> bits, err := cmd.CombinedOutput()
> if err != nil {
> log.Fatal(err)
> }
> os.Stdout.Write(bits)
>
> Note exec.Command("echo", "{<&") runs just fine.
>

(my previous post didn't seem to make it. this is probably better anyway.)

I think ssh is using your login shell execute the remote command so the
<& is being interpreted as a redirect whereas when you run echo on
your local machine, it is simply being fork()/exec()ed and your
string is passed directly as a parameter without being interpreted
by a shell.

When I try your ssh command my shell (bash) gives the following
complaint:

err: exit status 1
bash: MsZG: ambiguous redirect

I can get it to work by escaping the '<' and '&' individually as well as
putting the entire offending argument in single quotes.

Which characters are special depends on your shell and even which mode
your shell is running in! This is trickier than it seems at first glance
and I think the ultimate solution is that you'll have to be aware of
which shell you're running on the remote machine and how to properly
escape arguments for it.

It'd be interesting to know if there is a way to get ssh to execute a
command without invoking the login shell. After a quick glance of the
man page and source (for FreeBSD at least) I couldn't find a way.

-ayan

Manlio Perillo

unread,
Nov 27, 2016, 9:43:15 AM11/27/16
to golang-nuts, kbur...@gmail.com
Il giorno sabato 26 novembre 2016 19:35:28 UTC+1, kbur...@gmail.com ha scritto:
Hi, I'd like to SSH to a remote host and run an arbitrary command. I found this pretty difficult to do with existing Go libraries.

The first problem I had was around escaping; commands run locally are appropriately escaped but I found it difficult to get the right escaping for commands run remotely. As an example, this hangs, I believe because of the {<& in the middle of the command.

cmd := exec.Command("ssh", "remote-host", "echo", "zdUZUKv{<&MsZG")
bits, err := cmd.CombinedOutput()
if err != nil {
log.Fatal(err)
}
os.Stdout.Write(bits)

Note exec.Command("echo", "{<&") runs just fine.


When using exec.Command, the echo program is executed directly, but when you use ssh, the commands are executed by the shell on the remote system, AFAIK.
The solution is to quote the command arguments.

The standard library does not seem to have support for shell quoting, but you can try to adapt the quoting support from Python:

    cmd := exec.Command("ssh", "remote-host", "echo", `"zdUZUKv{<&MsZG"`)

I have not tested it.


> [...]

Manlio
Reply all
Reply to author
Forward
0 new messages