How Bash decides it's being invoked through sshd and sources your .bashrc
Under normal circumstances, Bash only sources your .bashrc
when
it's run as an interactive non-login shell; for example, this is
what the Bash manual says about startup files.
Well, it is most of what the manual says, because there is an
important exception, which the Bash manual describes as 'Invoked
by remote shell daemon':
Bash attempts to determine when it is being run with its standard input connected to a network connection, as when executed by the remote shell daemon, usually rshd, or the secure shell daemon sshd. If Bash determines it is being run in this fashion, it reads and executes commands from
~/.bashrc
, [...]
(You can tell how old this paragraph of the manual is because of how much prominence it gives to rshd. Also, note that this specific phrasing about standard input presages my discovery of when bash doesn't do this.)
As the result of recent events, I became
interested in discovering exactly how Bash decides that it's being
run in the form of 'ssh host command
' and sources your .bashrc
.
There turn out to be two parts to this answer, but the summary is
that if this is enabled at all, Bash will always source your
.bashrc
for non-interactive commands if you've logged in to a
machine via SSH.
First, this feature may not even be enabled in your version of Bash, because it's a non-default configuration setting (and has been since Bash 2.05a, which is pretty old). Debian and thus Ubuntu turn this feature on, as does Fedora, but the FreeBSD machine I have access to doesn't in the version of Bash that's in its ports. Unsurprisingly, OmniOS doesn't seem to either. If you compile Bash yourself without manually changing the relevant bit of config-top.h, you'll get a version without this.
(Based on some digging, I think that Arch Linux also builds Bash without enabling this, since they don't seem to patch config-top.h. I will leave it to energetic people to check other Linuxes and other *BSDs.)
Second, how it works is actually very simple. In practice, a
non-interactive Bash decides that it is being invoked by SSHD if
either $SSH_CLIENT
or $SSH2_CLIENT
are defined in the
environment. In a robotic sense this is perfectly
correct, since OpenSSH's sshd
puts $SSH_CLIENT
in the environment
when you do 'ssh host command
'. In practice it is wrong, because
OpenSSH sets $SSH_CLIENT
all the time, including for logins.
So if you use SSH to log in somewhere, $SSH_CLIENT
will be set
in your shell environment, and then any non-interactive Bash will
decide that it should source ~/.bashrc
. This includes, for
example,
the Bash that is run (as 'bash -c ...
') to execute commands when
you have a Makefile that has explicitly set 'SHELL=/bin/bash
', as
Makefiles that are created by the GNU autoconfigure system tend to
do.
As a result, if you have ancient historical things
in a .bashrc
, for example clearing the screen on exit, then
surprise, those things will happen for every command that make
runs. This may not make you happy. For situations like Makefiles
that explicitly set 'SHELL=/bin/bash
', this can happen even if
you don't use Bash as your login shell and haven't had anything to
do with it for years.
(Of course it also happens if you have perfectly modern things there
and expect that they won't get invoked for non-interactive shells,
and you do use Bash as your login shell. But if you use Bash as
your login shell, you're more likely to notice this issue, because
routine ordinary activities like 'ssh host command
' or 'rsync
host:/something .
' are more likely to fail, or at least do additional
odd things.)
PS: This October 2001 comment in variables.c
sort
of suggests why support for this feature is now an opt-in thing.
PPS: If you want to see if your version of Bash has this enabled, the
simple way to tell is to run strings
on the binary and see if the
embedded strings include 'SSH_CLIENT
'. Eg:
; /etc/fedora-release Fedora release 29 (Twenty Nine) ; strings -a /usr/bin/bash | fgrep SSH_CLIENT SSH_CLIENT
So the Fedora 29 version does have this somewhat dubious feature enabled. Perhaps Debian and Fedora feel stuck with it due to very long-going backwards compatibility, where people would be upset if Bash stopped doing this in some new Debian or Fedora release.
Sidebar: The actual code involved
The code for this can currently be found in run_startup_files
in shell.c
:
/* get the rshd/sshd case out of the way first. */ if (interactive_shell == 0 && no_rc == 0 && login_shell == 0 && act_like_sh == 0 && command_execution_string) { #ifdef SSH_SOURCE_BASHRC run_by_ssh = (find_variable ("SSH_CLIENT") != (SHELL_VAR *)0) || (find_variable ("SSH2_CLIENT") != (SHELL_VAR *)0); #else run_by_ssh = 0; #endif [...]
Here we can see that the current Bash source code is entirely aware that no one uses rshd any more, among other things.
|
|