On Mon, Mar 23, 2009 at 05:47:12PM +0000, Hari Sekhon wrote:
> My shells all use a unified agent which only triggers once the first 
> time I need to ssh (or if the agent is killed/restart or my key was not 
> already loaded for some reason etc..)

I don't see any way to do this that isn't a horrible hack involving
parsing the output of "ps" or your operating system's equivalent (such
as /proc).  ssh-agent is intended to be run as the ancestor of all the
processes of your session (e.g. eval `ssh-agent -s` in your .xsession or
.profile file), so that they all inherit the same environment variables
pointing to the same agent.

If ssh-agent isn't already running at the time your ssh command is
triggered, then you're (potentially) going to have multiple xterms
running around with no SSH_AUTH* variables set.  If you try to detect
the presence or absence of an agent running under your UID using some
ps/pgrep hackery, not only do you get the error-prone-ness of parsing
process names (processes can change their own names, invoke other
processes under pseudonyms, etc.), but you also create a race condition.

Consider something like this (bash syntax):

ssh() {
  if ! pgrep -u $LOGNAME ssh-agent >/dev/null; then
    # Agent is not running
    eval $(ssh-agent -s)
    ssh-add
  else
    ssh-add -L >/dev/null 2>&1
    if [ $? = 1 ]; then
      # Agent running, but no key loaded
      ssh-add
    fi
  fi
  command ssh "$@"
  unset -f ssh
}

Looks good at first glance, right?  But consider two xterms started
without a parent agent, so that they have no SSH_AUTH* variables, etc.
You start an "ssh" command in each one.  Each one runs the pgrep, sees
there's no agent running under your name, and then runs ssh-agent -s to
set one up.  Now you've got two agents, and two shells with different
environment variables pointing to the different agents.  Not to mention
two ssh-add passphrase prompts, which is the thing you were trying to
avoid all along.

I wouldn't recommend anything other than putting eval $(ssh-agent -s) or
its equivalent into your primary login session file (.xinitrc or .xsession
or .profile or .login or whatever makes sense for your login).  You can
then either do an ssh-add at that time (which is what I do, personally),
or you could write an override function like this (again, bash syntax):

ssh() {
  ssh-add -L >/dev/null 2>&1
  [ $? = 1 ] && ssh-add
  command ssh "$@"
  unset -f ssh
}

Since this doesn't involving checking for an agent, you avoid the
multiple-agent race condition I pointed out earlier.  There's still
a race condition when you check whether the key is already loaded,
but the worst you can do here is get an extra passphrase prompt,
which is relatively harmless.

Reply via email to