Re: Why are the arguments supplied for the command run through ssh interpreted by shell before they are passed to the command on the server side?

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

 



On Sat, Jan 11, 2020 at 2:02 AM Yuri <yuri@xxxxxxxxx> wrote:
>
> On 2020-01-11 01:38, Darren Tucker wrote:
> > The command you give is always handled on the server by your shell in some
> > fashion.  It has to be, because SSH only specifies an opaque string for the
> > remote command, so without doing so you would not be able to specify
> > arguments at all.
>
> It's not obvious why does it have to be this way. ssh sends the command
> as an array of strings. The first string is the command, and the
> subsequent strings are arguments. It can easily call the same command
> with the same arguments on the remote host.

While it's important to understand how local shell processing works
(and this is obviously out-of-scope of the ssh(1) man page), I think
ssh(1) doesn't adequately explain how the "command" is executed on the
remote side, and how a command is formed from multiple command tokens.

>From https://github.com/openssh/openssh-portable/blob/ed3ad71b17adcd1fb4431d145f53cee1c6a1135e/ssh.c#L1069-L1072,
you can see that multiple command tokens are simply joined with spaces
into a single actual "command". That implies that the remote side sees
all of the following variations as exactly equivalent:

$ ssh host 'printargs "foo bar" baz | cat' # ssh sees a single command
token locally
$ ssh host printargs '"foo' 'bar"' baz \| cat # ssh sees 6 command
tokens locally
$ ssh host printargs '"foo bar" baz |' cat # ssh sees 3 command tokens locally

>From https://github.com/openssh/openssh-portable/blob/ed3ad71b17adcd1fb4431d145f53cee1c6a1135e/session.c#L1703-L1711,
you can see that these would all result approximately in running this
command remotely:

$SHELL -c 'printargs "foo bar" baz | cat'

I say "approximately" because for simpler presentation, I used shell
syntax above (as if you were to manually run the command in a remote
shell), but you can see from the source that ssh actually does this
via a fork-and-exec, so there would be no single quotes anywhere, for
example.

The output would look something like this:

argv[0] = {/usr/local/bin/printargs}
argv[1] = {foo bar}
argv[2] = {baz}

Here's a bash implementation of printargs:

#!/bin/bash

for (( i = 0; i <= $#; ++i )); do
    printf 'argv[%d] = {%s}\n' $i "${!i}"
done
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@xxxxxxxxxxx
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev



[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux