Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Is zsh buggy in connection with screen?



On 2005-11-08 17:09:42 -0500, Ian Langworth wrote:
> I have a similar problem with ssh-agent. New screen windows
> automatically get the updated environment when I've shelled freshly
> into the machine, but existing shells in windows need to run
> "latestssh."
[...]

I have my own solution for ssh, which is not related to screen,
since I sometimes have several shells on a machine, but without
necessarily using screen. This solution also supports connection
sharing. See the attached message.

-- 
Vincent Lefèvre <vincent@xxxxxxxxxx> - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA
--- Begin Message ---
This isn't a command, but a set of zsh scripts I've written.
I've attached them. If you want to use them, you basically
need to put these files somewhere in your $fpath, autoload
the corresponding functions with

  autoload -U _call_sshagent _call_sshadd kill_sshmasters

call _call_sshagent from your .zlogin and add the following
to your .zlogout:

# Unregister from ssh-agent and kill it if need be.
if [[ -n $SSH_AUTH_SOCK ]] then
  if [[ `whence -w _call_sshagent` == '_call_sshagent: function' ]] then
    _call_sshagent -r
  elif [[ -n $SSH_AGENT_PID ]] then
    eval `ssh-agent -k`
  fi
fi

and use the following wrappers:

ssh()
{
  _call_sshadd "$@"
  command ssh "$@"
}

slogin()
{
  _call_sshadd "$@"
  command slogin "$@"
}

scp()
{
  _call_sshadd "$@"
  command scp "$@"
}

sftp()
{
  _call_sshadd "$@"
  command sftp "$@"
}

Note: here, these wrappers are defined in .zalias (so is the autoload
line I've mentioned above), sourced by my .zshrc file. Also, I've set
SVN_SSH to $HOME/scripts/ssh; this script contains:

source ~/.zshenv
source ~/.zalias
unset DISPLAY
ssh -C "$@"

Note that $HOME/scripts must not be in $path to avoid an infinite
recursion. In fact, it would be more robust to dynamically remove
$HOME/scripts from $path before calling ssh, after resolving hard
and symbolic links. But there should be no problem if you do not
have '.' in your $path or if you have it at the end (having '.'
earlier in $path is a security problem anyway).

This way, one no longer needs to call ssh-agent and/or ssh-add
manually. The passphrase is automatically asked at the first
connection attempt and remembered until the last login shell
exits. However, one still needs to execute

  ssh -fMN <host>

manually for ssh connection caching. You can add lines to some ssh
wrapper to do that automatically, but you need to check for the
corresponding ControlSocket file first, otherwise there will be no
benefit; unfortunately this is not easy... About these problems,
you can see my bug report and followup here:

  http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=335697

Also, note that lsof is used to find the ssh master connection.
If you do not have lsof, the ssh master connection will not be
killed. The kill_sshmasters script has an echo line to let you
know that this connection is killed. So, you know what happens.

Standard disclaimer: use these scripts at your own risks. I've written
them with security in mind, but they haven't be reviewed by anyone
else. Also, I've written them for my config on various machines, and
I'm not sure they work correctly everywhere. You can still check that
ssh-agent is killed when you completely logout with a

  ssh host ps -aef | grep ssh-agent
              ^^^^
or other options depending on your system, and things like that.

-- 
Vincent Lefèvre <vincent@xxxxxxxxxx> - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA
#!/usr/bin/env zsh

emulate -LR zsh

ssh-add -l >& /dev/null
local err=$?

if [[ $err -eq 2 ]] then
  _call_sshagent -l
  ssh-add -l >& /dev/null
  err=$?
fi

if [[ $err -eq 1 ]] then
  local file i
  file=()
  for i in id_rsa id_rsa-internal identity
  do
    [[ -f $HOME/.ssh/$i ]] && file=($file $HOME/.ssh/$i)
  done
  ssh-add $file
fi

true

# $Id: _call_sshadd 2770 2004-03-17 22:39:32Z lefevre $
#!/usr/bin/env zsh

# Usage: _call_sshagent [ -l | -r ]
#   -l: try to use an existing ssh-agent and change SSH_AUTH_SOCK
#       accordingly. This is useful for some non-login shells (no
#       possible clean-up by the .zlogout).
#   -r: remove the socket associated with the current process and
#       kill ssh-agent if there are no sockets any longer.

emulate -LR zsh

local link=/tmp/ssh-agent-$USER

local i=0
until (ln -s /dev/null $link.lock 2> /dev/null)
do
  [[ $i -eq 0 ]] && echo "$0: waiting for lock"
  if [[ $((++i)) -eq 4 ]] then
    echo "$0: can't lock $link"
    return
  fi
  sleep 2
done

local dir=`readlink $link`

if [[ $1 == -r ]] then

  if [[ -O $link && -d $dir && -O $dir && $SSH_AUTH_SOCK == $link/* ]] then
    local others
    rm -f $SSH_AUTH_SOCK
    unset SSH_AUTH_SOCK
    others=($dir/agent.*(N=))
    if [[ -z $others ]] then
      local pid=$(<$dir/ssh-agent.pid)
      rm -f $link $dir/ssh-agent.pid
      kill -TERM $pid
      kill_sshmasters
    fi
  else
    # Inconsistent data, try to kill ssh-agent in the standard way
    eval `ssh-agent -k`
  fi

elif [[ $1 == -l ]] then

  if [[ -O $link && -d $dir && -O $dir ]] then
    local old
    old=($link/agent.*(N=[1]))
    if [[ -S $old ]] then
      SSH_AUTH_SOCK=$old ssh-add -l >& /dev/null
      if [[ $? -ne 2 ]] then
        export SSH_AUTH_SOCK=$old
        unset SSH_AGENT_PID
      fi
    else
      echo "$0: $old isn't a socket"
    fi
  fi

else

  if [[ -O $link && -d $dir && -O $dir ]] then
    local old
    old=($link/agent.*(N=[1]))
    if [[ -S $old ]] then
      SSH_AUTH_SOCK=$old ssh-add -l >& /dev/null
      if [[ $? -eq 2 ]] then
        # The agent could not be contacted, assume that it has died
        rm -f $dir/agent.*(N) $dir/ssh-agent.pid && rmdir $dir
        rm -f $link
        rm -f $link.lock
        $0
        return
      fi
      local new=$link/agent.$$
      if [[ $new == $old ]] || ln -f $old $new; then
        export SSH_AUTH_SOCK=$new
        unset SSH_AGENT_PID
      else
        echo "$0: can't link $new -> $old"
      fi
    else
      echo "$0: $old isn't a socket"
    fi
  elif eval `ssh-agent`; then
    if ln -fs $SSH_AUTH_SOCK:h $link; then
      local old=$SSH_AUTH_SOCK
      echo $SSH_AGENT_PID > $link/ssh-agent.pid
      rm -f $link.lock
      $0 && rm -f $old
      return
    else
      echo "$0: can't symlink $dir -> $SSH_AUTH_SOCK:h"
    fi
  else
    echo "$0: can't call ssh-agent"
  fi

fi

rm -f $link.lock

# $Id: _call_sshagent 9482 2005-10-25 15:49:48Z lefevre $
#!/usr/bin/env zsh

# Kill the ssh master connections having no slaves.

emulate -LR zsh
local file pid pids

for file in /tmp/ssh-*(=N)
do
  pids=($(lsof -F f -U -a -c ssh -a "$file" 2>/dev/null))
  if [[ $#pids == 2 ]] then
    pid=${pids[1]#p}
    echo "kill $pid (socket $file)"
    kill -TERM $pid
  fi
done

# Never fail.
true

# $Id: kill_sshmasters 9485 2005-10-25 16:08:12Z lefevre $

--- End Message ---


Messages sorted by: Reverse Date, Date, Thread, Author