sshd and .bashrc
mark at cacr.caltech.edu
Fri Jul 1 07:34:55 EST 2011
The short version: There's a "#define USE_PIPES"
in the middle of session.c; it would be better if
it were in (e.g.) defines.h or some other .h file.
(If in fact it needs to be defined at all; I'm not
convinced that it does.) Here's the (much) longer
I recently installed the latest OpenSSH on some of
our servers (RHEL5, which provides the 4.3 release)
and soon afterward we received a complaint from one
of our users, reporting that his .bashrc file was no
longer being sourced when he ran remote commands via
a non-interactive single-command connection. He was
right. The problem stemmed from the fact that bash
contains the following in run_startup_files(), which
gets called to determine which dotfiles (if any) to
if (interactive_shell == 0 && no_rc == 0 && login_shell == 0 &&
act_like_sh == 0 && command_execution_string)
run_by_ssh = (find_variable ("SSH_CLIENT") != (SHELL_VAR *)0) ||
(find_variable ("SSH2_CLIENT") != (SHELL_VAR *)0);
run_by_ssh = 0;
/* If we were run by sshd or we think we were run by rshd, execute
~/.bashrc if we are a top-level shell. */
if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)
... and RedHat's bash is built with SSH_SOURCE_BASHRC
not defined, so everything depends on isnetconn(); in
fact, that seems to be bash's default, since one finds
this in a (very old) entry in their CHANGES file:
This document details the changes between this version, bash-2.05a-release,
and the previous version, bash-2.05a-rc1.
[ ... ]
z. Bash no longer attempts to discover if it's being run by sshd in order to
run the startup files. If the SSH_SOURCE_BASHRC is uncommented in
config-top.h it will attempt to do so as previously, but that's commented
out in the distributed version.
But it turns out that bash's isnetconn() function was
returning 0, which in turn was caused by getpeername()
failing (errno == ENOTSOCK) when it was being used to
get information about stdin.
And sure enough, the child process spawned by Redhat's
sshd showed the following for standard input (reported
by "lsof") ...
0u unix 0xffff81033fec2b80 10237328 socket
... whereas the same child process spawned by the sshd
which I'd just built had this ...
0r FIFO 0,6 3093574 pipe
So what was responsible for this difference? It turns
out that there's some code in session.c (specifically,
in the do_exec_no_pty() function) conditionalized with ...
[ ... ]
[ ... ]
... so this might lead one to believe that there would be
something in one of the .h files that would govern which
of those chunks of code would get used, particularly in
light of the fact that defines.h contains ...
* Define this to use pipes instead of socketpairs for communicating with the
* client program. Socketpairs do not seem to work on all systems.
* configure.ac sets this for a few OS's which are known to have problems
* but you may need to set it yourself
/* #define USE_PIPES 1 */
... and the configure script creates a config.h with ...
/* Use PIPES instead of a socketpair() */
/* #undef USE_PIPES */
... both of which would lead one to infer that USE_PIPES
is _not_ defined by default. But back in session.c, more
then four hundred lines from the beginning of the file, we
find this ...
... just before the start of the do_exec_no_pty() function!
This wasn't always there; it appeared for the first time in
the 5.1p1 release (it's not in 5.0p1).
So first, I'm curious as to why it was felt necessary to make
USE_PIPES the default; and secondly, even if there is a good
reason for it to be the default, shouldn't the "#define" be
in a .h file, so that it will be obvious what the setting is
for people who might want to change it?
Burying it down in the middle of session.c just seems like an
unwise decision ...
Center for Advanced Computing Research
California Institute of Technology
Pasadena, California 91125
626 395 2522
626 584 5917 fax
626 628 3994 e-fax
mark at cacr.caltech.edu
More information about the openssh-unix-dev