ssh-keyman 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. #!/bin/sh
  2. ##
  3. ## ssh-keyman -- authentication key agent management
  4. ## Copyright (c) 2002 Ralf S. Engelschall <rse@engelschall.com>
  5. ##
  6. ## Permission to use, copy, modify, and distribute this software for
  7. ## any purpose with or without fee is hereby granted, provided that
  8. ## the above copyright notice and this permission notice appear in all
  9. ## copies.
  10. ##
  11. ## THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  12. ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  13. ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  14. ## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
  15. ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  16. ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  17. ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  18. ## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  19. ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  20. ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  21. ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  22. ## SUCH DAMAGE.
  23. ##
  24. ## ssh-keyman: program implementation (language: Bourne-Shell)
  25. ##
  26. # program information
  27. prog_name="ssh-keyman"
  28. prog_vers="1.0.0"
  29. prog_date="05-May-2002"
  30. # OpenSSH programs
  31. ssh_agent="@l_prefix@/bin/ssh-agent"
  32. ssh_add="@l_prefix@/bin/ssh-add"
  33. # parse command line options
  34. opt_q=no; alias_quiet=q
  35. opt_c=no; alias_cluster=c
  36. opt_e=no; alias_env=e
  37. opt_s=no; alias_start=s
  38. opt_k=no; alias_kill=k
  39. opt_a=no; alias_add=a
  40. opt_d=no; alias_delete=d
  41. opt_l=no; alias_list=l
  42. opt_h=no; alias_help=h
  43. opt_v=no; alias_version=v
  44. if [ $# -eq 0 ]; then
  45. opt_h=yes
  46. fi
  47. while [ $# -gt 0 ]; do
  48. if [ ".$1" = ".--" ]; then
  49. shift
  50. break
  51. fi
  52. case $1 in
  53. --quiet|--cluster|--env|--start|--kill|--add|--delete|--list|--help|--version )
  54. name=`echo x$1 | sed -e 's;^x--;;'`
  55. eval "name=\$alias_${name}"
  56. eval "opt_${name}=yes"
  57. ;;
  58. -[qceskadlhv] )
  59. name=`echo x$1 | sed -e 's;^x-;;'`
  60. eval "opt_${name}=yes"
  61. ;;
  62. -* )
  63. echo "$prog_name:ERROR: unknown option \"$opt\"" 1>&2
  64. exit 1
  65. ;;
  66. * )
  67. break
  68. ;;
  69. esac
  70. shift
  71. done
  72. # stand-alone operation: display help information
  73. if [ ".$opt_h" = .yes ]; then
  74. echo "Usage: $prog_name [-h] [-v] [-q] [-c] [-e] [-s] [-k] [-a] [-d] [-l] [keyfile ...]"
  75. exit 0
  76. fi
  77. # stand-alone operation: display version information
  78. if [ ".$opt_v" = .yes ]; then
  79. echo "$prog_name $prog_vers ($prog_date)"
  80. exit 0
  81. fi
  82. # determine agent information filename
  83. hostname=`hostname`
  84. agentfile="$HOME/.ssh/agent-$hostname"
  85. if [ ".$opt_c" = .no ]; then
  86. if [ ! -f $agentfile ]; then
  87. agentfile="$HOME/.ssh/agent"
  88. fi
  89. fi
  90. # export agent configuration
  91. export SSH_AUTH_SOCK
  92. export SSH_AGENT_PID
  93. # perform agent information sanity check
  94. check_agent_info () {
  95. location="$1"
  96. if [ ".$SSH_AUTH_SOCK" != . -o ".$SSH_AGENT_PID" != . ]; then
  97. invalid=""
  98. if [ ".$SSH_AUTH_SOCK" = . -o ".$SSH_AGENT_PID" = . ]; then
  99. # just one of the two information is not enough
  100. invalid="partial agent information missing"
  101. else
  102. # make sure the agent process is (still) running
  103. kill -0 $SSH_AGENT_PID >/dev/null 2>&1
  104. if [ $? -ne 0 ]; then
  105. invalid="agent process $SSH_AGENT_PID is no longer valid"
  106. else
  107. if [ ! -r $SSH_AUTH_SOCK ]; then
  108. invalid="agent socket $SSH_AUTH_SOCK is no longer existing"
  109. fi
  110. fi
  111. fi
  112. if [ ".$invalid" != . ]; then
  113. echo "$prog_name:WARNING: invalid agent information found in $location." 1>&2
  114. echo "$prog_name:WARNING: reason: $invalid." 1>&2
  115. if [ ".$location" = ".your shell environment" ]; then
  116. echo "$prog_name:HINT: run \"eval \`$prog_name -q -s -e\`\" to fix." 1>&2
  117. fi
  118. unset SSH_AUTH_SOCK
  119. unset SSH_AGENT_PID
  120. fi
  121. fi
  122. }
  123. check_agent_info "your shell environment"
  124. if [ -f $agentfile ]; then
  125. . $agentfile
  126. check_agent_info "in saved agent state"
  127. if [ ".$SSH_AUTH_SOCK" = . -a ".$SSH_AGENT_PID" = . ]; then
  128. rm -f $agentfile
  129. fi
  130. fi
  131. # if (now guarrantied to be correct) agent state is in
  132. # environment, but it is (no longer?) saved, save it now to fix situation.
  133. if [ ! -f $agentfile ]; then
  134. if [ ".$SSH_AUTH_SOCK" != . -a ".$SSH_AGENT_PID" != . ]; then
  135. ( echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK"
  136. echo "SSH_AGENT_PID=$SSH_AGENT_PID"
  137. ) >$agentfile && chmod 700 $agentfile
  138. echo "$prog_name:WARNING: valid agent information in your environment" 1>&2
  139. echo "$prog_name:WARNING: but no saved agent state file -- fixed" 1>&2
  140. fi
  141. fi
  142. # stop the agent
  143. if [ ".$opt_k" = .yes ]; then
  144. # stop the agent
  145. kill=yes
  146. if [ ".$SSH_AUTH_SOCK" = . -a ".$SSH_AGENT_PID" = . ]; then
  147. if [ ".$opt_q" = .no ]; then
  148. echo "$prog_name: agent not running"
  149. fi
  150. else
  151. kill $SSH_AGENT_PID >/dev/null 2>&1 || true
  152. if [ ".$opt_q" = .no ]; then
  153. echo "$prog_name: stopped agent (pid $SSH_AGENT_PID)"
  154. fi
  155. rm -f $agentfile
  156. unset SSH_AUTH_SOCK
  157. unset SSH_AGENT_PID
  158. fi
  159. fi
  160. # start the agent
  161. if [ ".$opt_s" = .yes ]; then
  162. if [ ".$SSH_AUTH_SOCK" != . -a ".$SSH_AGENT_PID" != . ]; then
  163. if [ ".$opt_q" = .no ]; then
  164. echo "$prog_name: agent already running"
  165. fi
  166. else
  167. eval `nohup $ssh_agent -s </dev/null 2>/dev/null | grep -v 'Agent pid'`
  168. if [ ".$opt_q" != .yes ]; then
  169. echo "$prog_name: spawned agent (pid $SSH_AGENT_PID)"
  170. fi
  171. ( echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK"
  172. echo "SSH_AGENT_PID=$SSH_AGENT_PID"
  173. ) >$agentfile && chmod 700 $agentfile
  174. fi
  175. fi
  176. # setup environment
  177. if [ ".$opt_e" = .yes ]; then
  178. if [ ".$SSH_AUTH_SOCK" = . -a ".$SSH_AGENT_PID" = . ]; then
  179. echo "$prog_name:WARNING: agent not running" 1>&2
  180. else
  181. cat $agentfile
  182. echo "export SSH_AUTH_SOCK"
  183. echo "export SSH_AGENT_PID"
  184. fi
  185. fi
  186. # delete key(s) from agent
  187. if [ ".$opt_d" = .yes ]; then
  188. if [ ".$SSH_AUTH_SOCK" = . -a ".$SSH_AGENT_PID" = . ]; then
  189. echo "$prog_name:WARNING: agent not running" 1>&2
  190. else
  191. if [ $# -eq 0 ]; then
  192. if [ ".$opt_q" = .no ]; then
  193. echo "$prog_name: deleting all keys"
  194. fi
  195. $ssh_add -D
  196. else
  197. if [ ".$opt_q" = .no ]; then
  198. for key in "$@"; do
  199. echo "$prog_name: deleting key $key"
  200. done
  201. fi
  202. $ssh_add -d "$@"
  203. fi
  204. fi
  205. fi
  206. # add key(s) into agent
  207. if [ ".$opt_a" = .yes ]; then
  208. if [ ".$SSH_AUTH_SOCK" = . -a ".$SSH_AGENT_PID" = . ]; then
  209. echo "$prog_name:WARNING: agent not running" 1>&2
  210. else
  211. if [ $# -eq 0 ]; then
  212. echo "$prog_name:ERROR: no keys specified on command line" 1>&2
  213. exit 1
  214. fi
  215. key_loaded=`$ssh_add -l | awk '{ print $2; }'`
  216. key_missing=""
  217. for key_file in "$@"; do
  218. if [ -f "${key_file}.pub" ]; then
  219. key_this=`ssh-keygen -l -f ${key_file}.pub 2>&1 | awk '{ print $2; }'`
  220. else
  221. key_this=`ssh-keygen -l -f ${key_file} 2>&1 | awk '{ print $2; }'`
  222. fi
  223. load=yes
  224. for key in $key_loaded; do
  225. if [ ".$key" = ".$key_this" ]; then
  226. load=no
  227. break
  228. fi
  229. done
  230. if [ ".$load" = .yes ]; then
  231. if [ ".$opt_q" = .no ]; then
  232. echo "$prog_name: loading key $key_file"
  233. fi
  234. key_missing="$key_missing $key_file"
  235. else
  236. if [ ".$opt_q" = .no ]; then
  237. echo "$prog_name: skipping key $key_file (already loaded)"
  238. fi
  239. fi
  240. done
  241. if [ ".$key_missing" != . ]; then
  242. $ssh_add $key_missing
  243. fi
  244. fi
  245. fi
  246. # list key(s) available in agent
  247. if [ ".$opt_l" = .yes ]; then
  248. if [ ".$SSH_AUTH_SOCK" = . -a ".$SSH_AGENT_PID" = . ]; then
  249. echo "$prog_name:WARNING: agent not running" 1>&2
  250. else
  251. $ssh_add -l
  252. fi
  253. fi