33

I have a user that has made no modifications to the $PATH in any dot-files: it is exactly the system default setting. From a login shell:

$ ssh example.com
user@example.com:~$ cat /tmp/hello.hs
#!/bin/bash

echo "$SHELL"
echo "$PATH"

user@example.com:~$ /tmp/hello.hs
/bin/bash
/usr/local/bin:/usr/bin:/bin

Exactly as specified in /etc/profile. This I find rather unexpected:

$ ssh example.com '/tmp/hello.sh'
/bin/bash       
/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games

Like I said, there's no modification of $PATH in ~/.bashrc, nor in /etc/bash.bashrc. No ~/.ssh/environment either. The ssh(1) declares that the environment variable PATH is

Set to the default PATH, as specified when compiling ssh.

but this thread from StackOverflow and this mailing list article suggest that I should be able to influence the $PATH for a given command simply by modifying /etc/profile, one of the shell startup files, etc.

What's going on here?

troutwine
  • 1,452
  • 5
  • 18
  • 33

4 Answers4

20

From ssh(1) manual page: "If command is specified, it is executed on the remote host instead of a login shell."

So in short when you actually login to the machine bash is started as a login shell and loads the apropriate files, when you connect remotely and issue a command it is run in the place of bash, which means that these files do NOT load. You can work around it with using su -l -c or similar in the command part of ssh.

In some cases I've seen -t argument to ssh work (allocate tty) too.

Edit 1:
I think the PATH information you found, that the default path (unless we override it) is the one compiled into sshd. I made sure that my /etc/profile, /etc/bash*, local dotfiles, etc. didn't have any PATH information in it, then I logged on and still had a PATH. I searched for this one in sshd and found it there. So its how the manpage says:

ahnberg@remote$ strings /usr/sbin/sshd | grep -i x11 | grep bin
/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games

Then I add PATH=$PATH:/my/test to the very top of my .bashrc file on remote, and check it again:

ahnberg@local$ ssh ahnberg@remote "env | grep PATH"
PATH=/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:/my/test

So I can absolutely influence it, and default PATH is the one compiled into sshd. :)

Mattias Ahnberg
  • 4,139
  • 19
  • 19
  • Hmm, that phrase "executed on the remote host" means a lot more than it says, I think. The more interesting bit, which I missed earlier, comes in the 'ENVIRONMENT' section of the same manpage: "PATH Set to the default PATH, as specified when compiling ssh." Except [this](http://stackoverflow.com/questions/940533/how-do-i-set-path-such-that-ssh-userhost-command-works) suggests that I _should_ be able to influence the PATH of a command. – troutwine Jan 20 '12 at 02:02
  • Well the point is that its not a login shell so it doesn't run/source/include the startup files the same way as for a login shell, hence my suggestions to try out. Putting things in `.bashrc` might work too, but overall I'd work around it if PATH is important. Or why not just specify full pathnames if you have a need for the 'command' way of running ssh? :) – Mattias Ahnberg Jan 20 '12 at 02:12
  • I've edited my post slightly. Now, there's a login shell, a non-login shell and interactive/non-interactive variants thereof. SSH commands are invoked in the user's shell in non-interactive non-login form. The `bash(1)` INVOCATION suggests that no startup files are read in this fashion, but I can't find documentation on _how_ ssh is invoking the shell. This seems counter to the linked sources above, unless others have /etc/ssh/sshrc startup file sourcing that I don't have. (There are workarounds, of course, but the point is understanding exactly how Debian SSHD handles paths by default.) – troutwine Jan 20 '12 at 02:30
  • If I modify PATH in `/etc/profile` on my remote box path updates for me, so `ssh user@remotebox 'env'` shows me the updated PATH. The same thing goes if I add `export PATH=$PATH:/my/testpath` to .bashrc (but in my case in top of the file before checks for interactive shells (`-z "$PS1"`). – Mattias Ahnberg Jan 20 '12 at 02:50
  • Updated with my tests/findings. – Mattias Ahnberg Jan 20 '12 at 02:58
  • Ah ha. SSH is invoking bash as an interactive, non-login shell and my edits to /etc/profile are only picked up by a login shell, according to the INVOCATION documentation. That's the trick, then: I was modifying the wrong startup files. – troutwine Jan 20 '12 at 03:37
  • Can anyone give an example of how to get the user path with `su -l -c` without the need to specify the username? – Dr_Zaszuś Jul 03 '20 at 13:44
7

I was able to get ssh to run commands using the remote path by running:

ssh dist@d6 "bash --login -c 'env'"

Here env can be replaced with what ever command you'd like.

I have authorized keys so didn't need a password to run the command or ssh.

Ian
  • 306
  • 2
  • 4
3

I came up with a different solution to fix the problem. My personal preference is to create new configuration files instead of altering existing ones. This way I can easier destinquish changes from the default configuration.

Here are the contents of /etc/profile.d/ssh_login.sh:

#!/bin/sh
if [ "$SSH_CONNECTION" ]; then
    echo "User '$USER' logged in from '${SSH_CONNECTION%% *}'"
    . /etc/environment
fi

Using dropbear in place of openssh-server (this should also work with openssh), the SSH_CONNECTION variable gets set automatically when I log in remotely. I created a new shell profile configuration to detect SSH logins, display some information on the screen and, most importantly, load the global environment settings from /etc/environment to replace the compiled-in values. Please note that this only affects interactive SSH shells, not remote command execution.

Alternatively, if you use openssh and always want load the global environment, regardless of whether it is an interactive shell, you could place a symlink in ~/.ssh/ like this:

ln -s /etc/environment ~/.ssh/environment

Then you need to enable the PermitUserEnvironment option in /etc/sshd/sshd_config. Only do this for trusted users though, as this could enable them to bypass access restrictions in some configurations using mechanisms such as LD_PRELOAD. Please see man sshd_config for more information, specifically how to use Match blocks to constraint options to specific users/groups.

tachylatus
  • 31
  • 2
1

If you want the profile path to load, try:

#!/bin/bash -i

at the top of the script. That way the shell is in interactive mode when running the script.

When bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. The --noprofile option may be used when the shell is started to inhibit this behavior.

http://linux.die.net/man/1/bash

Adam Brand
  • 6,127
  • 2
  • 30
  • 40