summaryrefslogtreecommitdiff
path: root/src/monkeysphere-ssh-proxycommand
blob: aeea30dcd976dbaef5770e317f41135ef879d7aa (plain)
  1. #!/usr/bin/env bash
  2. # monkeysphere-ssh-proxycommand: MonkeySphere ssh ProxyCommand hook
  3. #
  4. # The monkeysphere scripts are written by:
  5. # Jameson Rollins <jrollins@fifthhorseman.net>
  6. #
  7. # They are Copyright 2008, and are all released under the GPL, version 3
  8. # or later.
  9. # This is meant to be run as an ssh ProxyCommand to initiate a
  10. # monkeysphere known_hosts update before an ssh connection to host is
  11. # established. Can be added to ~/.ssh/config as follows:
  12. # ProxyCommand monkeysphere-ssh-proxycommand %h %p
  13. ########################################################################
  14. PGRM=$(basename $0)
  15. SYSSHAREDIR=${MONKEYSPHERE_SYSSHAREDIR:-"/usr/share/monkeysphere"}
  16. export SYSSHAREDIR
  17. . "${SYSSHAREDIR}/common" || exit 1
  18. ########################################################################
  19. # FUNCTIONS
  20. ########################################################################
  21. usage() {
  22. cat <<EOF >&2
  23. usage: ssh -o ProxyCommand="$(basename $0) %h %p" ...
  24. EOF
  25. }
  26. log() {
  27. echo "$@" >&2
  28. }
  29. output_no_valid_key() {
  30. local sshKeyOffered
  31. local userID
  32. local type
  33. local validity
  34. local keyid
  35. local uidfpr
  36. local usage
  37. local sshKeyGPG
  38. local sshFingerprint
  39. userID="ssh://${HOSTP}"
  40. log "Monkeysphere found only OpenPGP keys for this host with*out* full validity."
  41. log "host: $userID"
  42. log
  43. # retrieve the actual ssh key
  44. sshKeyOffered=$(ssh-keyscan -t rsa -p "$PORT" "$HOST" 2>/dev/null | awk '{ print $2, $3 }')
  45. # FIXME: should we do any checks for failed keyscans, eg host not
  46. # found?
  47. # output gpg info for userid and store
  48. gpgOut=$(gpg --list-key --fixed-list-mode --with-colon \
  49. --with-fingerprint --with-fingerprint \
  50. ="$userID" 2>/dev/null)
  51. # find all 'pub' and 'sub' lines in the gpg output, which each
  52. # represent a retrieved key for the user ID
  53. echo "$gpgOut" | cut -d: -f1,2,5,10,12 | \
  54. while IFS=: read -r type validity keyid uidfpr usage ; do
  55. case $type in
  56. 'pub'|'sub')
  57. # get the ssh key of the gpg key
  58. sshKeyGPG=$(gpg2ssh "$keyid")
  59. # if one of keys found matches the one offered by the
  60. # host, then output info
  61. if [ "$sshKeyGPG" = "$sshKeyOffered" ] ; then
  62. # get the fingerprint of the ssh key
  63. tmpkey=$(mktemp ${TMPDIR:-/tmp}/tmp.XXXXXXXXXX)
  64. echo "$sshKeyGPG" > "$tmpkey"
  65. sshFingerprint=$(ssh-keygen -l -f "$tmpkey" | awk '{ print $2 }')
  66. rm -rf "$tmpkey"
  67. # output gpg info
  68. gpg --check-sigs \
  69. --list-options show-uid-validity \
  70. "$keyid" >&2
  71. # output ssh fingerprint
  72. log "RSA key fingerprint is ${sshFingerprint}."
  73. log "Falling through to standard ssh host checking."
  74. log
  75. fi
  76. ;;
  77. esac
  78. done
  79. }
  80. ########################################################################
  81. # export the monkeysphere log level
  82. export MONKEYSPHERE_LOG_LEVEL
  83. if [ "$1" = '--no-connect' ] ; then
  84. NO_CONNECT='true'
  85. shift 1
  86. fi
  87. HOST="$1"
  88. PORT="$2"
  89. if [ -z "$HOST" ] ; then
  90. log "Host not specified."
  91. usage
  92. exit 255
  93. fi
  94. if [ -z "$PORT" ] ; then
  95. PORT=22
  96. fi
  97. # set the host URI
  98. if [ "$PORT" != '22' ] ; then
  99. HOSTP="${HOST}:${PORT}"
  100. else
  101. HOSTP="${HOST}"
  102. fi
  103. URI="ssh://${HOSTP}"
  104. # specify keyserver checking. the behavior of this proxy command is
  105. # intentionally different than that of running monkeyesphere normally,
  106. # and keyserver checking is intentionally done under certain
  107. # circumstances. This can be overridden by setting the
  108. # MONKEYSPHERE_CHECK_KEYSERVER environment variable.
  109. # if the host is in the gpg keyring...
  110. if gpg --list-key ="${URI}" 2>&1 >/dev/null ; then
  111. # do not check the keyserver
  112. CHECK_KEYSERVER="false"
  113. # if the host is NOT in the keyring...
  114. else
  115. # if the host key is found in the known_hosts file...
  116. # FIXME: this only works for default known_hosts location
  117. hostKey=$(ssh-keygen -F "$HOST" 2>/dev/null)
  118. if [ "$hostKey" ] ; then
  119. # do not check the keyserver
  120. # FIXME: more nuanced checking should be done here to properly
  121. # take into consideration hosts that join monkeysphere by
  122. # converting an existing and known ssh key
  123. CHECK_KEYSERVER="false"
  124. # if the host key is not found in the known_hosts file...
  125. else
  126. # check the keyserver
  127. CHECK_KEYSERVER="true"
  128. fi
  129. fi
  130. # set and export the variable for use by monkeysphere
  131. MONKEYSPHERE_CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:="$CHECK_KEYSERVER"}
  132. export MONKEYSPHERE_CHECK_KEYSERVER
  133. # update the known_hosts file for the host
  134. monkeysphere update-known_hosts "$HOSTP"
  135. # output on depending on the return of the update-known_hosts
  136. # subcommand, which is (ultimately) the return code of the
  137. # update_known_hosts function in common
  138. case $? in
  139. 0)
  140. # acceptable host key found so continue to ssh
  141. true
  142. ;;
  143. 1)
  144. # no hosts at all found so also continue (drop through to
  145. # regular ssh host verification)
  146. true
  147. ;;
  148. 2)
  149. # at least one *bad* host key (and no good host keys) was
  150. # found, so output some usefull information
  151. output_no_valid_key
  152. ;;
  153. *)
  154. # anything else drop through
  155. true
  156. ;;
  157. esac
  158. # exec a netcat passthrough to host for the ssh connection
  159. if [ -z "$NO_CONNECT" ] ; then
  160. if (which nc 2>/dev/null >/dev/null); then
  161. exec nc "$HOST" "$PORT"
  162. elif (which socat 2>/dev/null >/dev/null); then
  163. exec socat STDIO "TCP:$HOST:$PORT"
  164. else
  165. echo "Neither netcat nor socat found -- could not complete monkeysphere-ssh-proxycommand connection to $HOST:$PORT" >&2
  166. exit 255
  167. fi
  168. fi