| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- #!/bin/sh
- ##
- ## ssh-keyman -- authentication key agent management
- ## Copyright (c) 2002-2003 Ralf S. Engelschall <rse@engelschall.com>
- ##
- ## Permission to use, copy, modify, and distribute this software for
- ## any purpose with or without fee is hereby granted, provided that
- ## the above copyright notice and this permission notice appear in all
- ## copies.
- ##
- ## THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- ## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
- ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- ## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- ## SUCH DAMAGE.
- ##
- ## ssh-keyman: program implementation (language: Bourne-Shell)
- ##
- # program information
- prog_name="ssh-keyman"
- prog_vers="1.0.1"
- prog_date="31-May-2002"
- # OpenSSH programs
- ssh_agent="@l_prefix@/bin/ssh-agent"
- ssh_add="@l_prefix@/bin/ssh-add"
- ssh="@l_prefix@/bin/ssh"
- # parse command line options
- opt_q=no; alias_quiet=q
- opt_c=no; alias_cluster=c
- opt_e=no; alias_env=e
- opt_s=no; alias_start=s
- opt_k=no; alias_kill=k
- opt_a=no; alias_add=a
- opt_d=no; alias_delete=d
- opt_l=no; alias_list=l
- opt_i=no; alias_install=i
- opt_h=no; alias_help=h
- opt_v=no; alias_version=v
- if [ $# -eq 0 ]; then
- opt_h=yes
- fi
- while [ $# -gt 0 ]; do
- if [ ".$1" = ".--" ]; then
- shift
- break
- fi
- case $1 in
- --quiet|--cluster|--env|--start|--kill|--add|--delete|--list|--help|--version )
- name=`echo x$1 | sed -e 's;^x--;;'`
- eval "name=\$alias_${name}"
- eval "opt_${name}=yes"
- ;;
- -[qceskadlihv] )
- name=`echo x$1 | sed -e 's;^x-;;'`
- eval "opt_${name}=yes"
- ;;
- -* )
- echo "$prog_name:ERROR: unknown option \"$opt\"" 1>&2
- exit 1
- ;;
- * )
- break
- ;;
- esac
- shift
- done
- # stand-alone operation: display help information
- if [ ".$opt_h" = .yes ]; then
- echo "Usage: $prog_name [-h] [-v] [-q] [-c] [-e] [-s] [-k] [-a] [-d] [-l] [-i] [keyfile ...]"
- exit 0
- fi
- # stand-alone operation: display version information
- if [ ".$opt_v" = .yes ]; then
- echo "$prog_name $prog_vers ($prog_date)"
- exit 0
- fi
- # determine agent information filename
- hostname=`hostname`
- agentfile="$HOME/.ssh/agent-$hostname"
- if [ ".$opt_c" = .no ]; then
- if [ ! -f $agentfile ]; then
- agentfile="$HOME/.ssh/agent"
- fi
- fi
- # export agent configuration
- export SSH_AUTH_SOCK
- export SSH_AGENT_PID
- # perform agent information sanity check
- check_agent_info () {
- context="$1"
- invalid1=""
- invalid2=""
- if [ ".$SSH_AUTH_SOCK" != . ]; then
- # make sure the agent socket is (still) working
- if [ ! -r $SSH_AUTH_SOCK ]; then
- invalid1="agent socket $SSH_AUTH_SOCK no longer exists"
- else
- $ssh_add -l >/dev/null 2>&1
- if [ $? -eq 2 ]; then
- invalid1="agent socket $SSH_AUTH_SOCK no longer valid"
- fi
- fi
- fi
- if [ ".$SSH_AGENT_PID" != . ]; then
- # make sure the agent process is (still) running
- kill -0 $SSH_AGENT_PID >/dev/null 2>&1
- if [ $? -ne 0 ]; then
- invalid2="agent process $SSH_AGENT_PID no longer exists"
- fi
- fi
- if [ ".$invalid1" != . -o ".$invalid2" != . ]; then
- if [ ".$opt_e" = .no ]; then
- echo "$prog_name:WARNING: invalid agent setup found in $context." 1>&2
- if [ ".$invalid1" != . ]; then
- echo "$prog_name:WARNING: reason: $invalid1." 1>&2
- fi
- if [ ".$invalid2" != . ]; then
- echo "$prog_name:WARNING: reason: $invalid2." 1>&2
- fi
- if [ ".$context" = ".your shell environment" ]; then
- echo "$prog_name:HINT: run \"eval \`$prog_name -q -s -e\`\" to fix." 1>&2
- fi
- fi
- unset SSH_AUTH_SOCK
- unset SSH_AGENT_PID
- fi
- }
- check_agent_info "your shell environment"
- if [ -f $agentfile ]; then
- . $agentfile
- check_agent_info "in saved agent state"
- if [ ".$SSH_AUTH_SOCK" = . -o ".$SSH_AGENT_PID" = . ]; then
- rm -f $agentfile
- fi
- fi
- # if (now guarrantied to be correct) agent state is in
- # environment, but it is (no longer?) saved, save it now to fix situation.
- if [ ! -f $agentfile ]; then
- if [ ".$SSH_AUTH_SOCK" != . -a ".$SSH_AGENT_PID" != . ]; then
- ( echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK"
- echo "SSH_AGENT_PID=$SSH_AGENT_PID"
- ) >$agentfile && chmod 600 $agentfile
- echo "$prog_name:WARNING: valid agent information in your environment" 1>&2
- echo "$prog_name:WARNING: but no saved agent state file -- fixed" 1>&2
- fi
- fi
- # stop the agent
- if [ ".$opt_k" = .yes ]; then
- # stop the agent
- kill=yes
- if [ ".$SSH_AUTH_SOCK" != . -a ".$SSH_AGENT_PID" != . ]; then
- kill $SSH_AGENT_PID >/dev/null 2>&1 || true
- if [ ".$opt_q" = .no ]; then
- echo "$prog_name: stopped agent (pid $SSH_AGENT_PID)" 1>&2
- fi
- rm -f $agentfile
- unset SSH_AUTH_SOCK
- unset SSH_AGENT_PID
- elif [ ".$SSH_AUTH_SOCK" != . -a ".$SSH_AGENT_PID" = . ]; then
- if [ ".$opt_q" = .no ]; then
- echo "$prog_name: agent running remotely - cannot kill locally" 1>&2
- fi
- else
- if [ ".$opt_q" = .no ]; then
- echo "$prog_name: agent not running" 1>&2
- fi
- fi
- fi
- # start the agent
- if [ ".$opt_s" = .yes ]; then
- if [ ".$SSH_AUTH_SOCK" = . -a ".$SSH_AGENT_PID" = . ]; then
- eval `nohup $ssh_agent -s </dev/null 2>/dev/null | grep -v 'Agent pid'`
- if [ ".$opt_q" != .yes ]; then
- echo "$prog_name: spawned agent (pid $SSH_AGENT_PID)" 1>&2
- fi
- ( echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK"
- echo "SSH_AGENT_PID=$SSH_AGENT_PID"
- ) >$agentfile && chmod 600 $agentfile
- elif [ ".$SSH_AUTH_SOCK" != . -a ".$SSH_AGENT_PID" = . ]; then
- if [ ".$opt_q" = .no ]; then
- echo "$prog_name: agent already running remotely - no need to start locally" 1>&2
- fi
- else
- if [ ".$opt_q" = .no ]; then
- echo "$prog_name: agent already running" 1>&2
- fi
- fi
- fi
- # setup environment
- if [ ".$opt_e" = .yes ]; then
- if [ -r $agentfile ]; then
- sed -e 's/$/;/g' <$agentfile
- echo "export SSH_AUTH_SOCK;"
- echo "export SSH_AGENT_PID;"
- else
- echo "$prog_name:WARNING: agent not (or no longer) available" 1>&2
- echo "unset SSH_AUTH_SOCK;"
- echo "unset SSH_AGENT_PID;"
- fi
- fi
- # delete key(s) from agent
- if [ ".$opt_d" = .yes ]; then
- if [ ".$SSH_AUTH_SOCK" = . ]; then
- echo "$prog_name:WARNING: agent not available" 1>&2
- else
- if [ $# -eq 0 ]; then
- if [ ".$opt_q" = .no ]; then
- echo "$prog_name: deleting all keys" 1>&2
- fi
- $ssh_add -D
- else
- if [ ".$opt_q" = .no ]; then
- for key in "$@"; do
- echo "$prog_name: deleting key $key" 1>&2
- done
- fi
- $ssh_add -d "$@"
- fi
- fi
- fi
- # add key(s) into agent
- if [ ".$opt_a" = .yes ]; then
- if [ ".$SSH_AUTH_SOCK" = . ]; then
- echo "$prog_name:WARNING: agent not available" 1>&2
- else
- if [ $# -eq 0 ]; then
- echo "$prog_name:ERROR: no keys specified on command line" 1>&2
- exit 1
- fi
- key_loaded=`$ssh_add -l | awk '{ print $2; }'`
- key_missing=""
- for key_file in "$@"; do
- if [ -f "${key_file}.pub" ]; then
- key_this=`ssh-keygen -l -f ${key_file}.pub 2>&1 | awk '{ print $2; }'`
- else
- key_this=`ssh-keygen -l -f ${key_file} 2>&1 | awk '{ print $2; }'`
- fi
- load=yes
- for key in $key_loaded; do
- if [ ".$key" = ".$key_this" ]; then
- load=no
- break
- fi
- done
- if [ ".$load" = .yes ]; then
- if [ ".$opt_q" = .no ]; then
- echo "$prog_name: loading key $key_file" 1>&2
- fi
- key_missing="$key_missing $key_file"
- else
- if [ ".$opt_q" = .no ]; then
- echo "$prog_name: skipping key $key_file (already loaded)" 1>&2
- fi
- fi
- done
- if [ ".$key_missing" != . ]; then
- $ssh_add $key_missing
- fi
- fi
- fi
- # list key(s) available in agent
- if [ ".$opt_l" = .yes ]; then
- if [ ".$SSH_AUTH_SOCK" = . ]; then
- echo "$prog_name:WARNING: agent not available" 1>&2
- else
- $ssh_add -l
- fi
- fi
- # install key(s) into remote account
- if [ ".$opt_i" = .yes ]; then
- if [ ".$SSH_AUTH_SOCK" = . ]; then
- echo "$prog_name:WARNING: agent not available" 1>&2
- else
- for remote in "$@"; do
- echo "$prog_name: installing public keys into $remote"
- $ssh_add -L |\
- $ssh $remote "umask 077; test -d ~/.ssh || mkdir ~/.ssh; cat >>~/.ssh/authorized_keys"
- done
- fi
- fi
|