summaryrefslogtreecommitdiff
path: root/src/monkeysphere-ssh-proxycommand
blob: b03984449316d039ba1d971d221be60a2496ff88 (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. log "OpenPGP keys with*out* full validity found for this host:"
  40. log
  41. # retrieve the actual ssh key
  42. sshKeyOffered=$(ssh-keyscan -t rsa -p "$PORT" "$HOST" 2>/dev/null | awk '{ print $2, $3 }')
  43. userID="ssh://${HOSTP}"
  44. # output gpg info for (exact) userid and store
  45. gpgOut=$(gpg --list-key --fixed-list-mode --with-colon \
  46. --with-fingerprint --with-fingerprint \
  47. ="$userID" 2>/dev/null)
  48. # loop over all lines in the gpg output and process.
  49. echo "$gpgOut" | cut -d: -f1,2,5,10,12 | \
  50. while IFS=: read -r type validity keyid uidfpr usage ; do
  51. case $type in
  52. 'pub'|'sub')
  53. # get the ssh key of the gpg key
  54. sshKeyGPG=$(gpg2ssh "$keyid")
  55. # if one of keys found matches the one offered by the
  56. # host, then output info
  57. if [ "$sshKeyGPG" = "$sshKeyOffered" ] ; then
  58. # get the fingerprint of the ssh key
  59. tmpkey=$(mktemp ${TMPDIR:-/tmp}/tmp.XXXXXXXXXX)
  60. echo "$sshKeyGPG" > "$tmpkey"
  61. sshFingerprint=$(ssh-keygen -l -f "$tmpkey" | awk '{ print $2 }')
  62. rm -rf "$tmpkey"
  63. # output gpg info
  64. gpg --check-sigs \
  65. --list-options show-uid-validity \
  66. "$keyid" >&2
  67. # output ssh fingerprint
  68. log "RSA key fingerprint is ${sshFingerprint}."
  69. log "Falling through to standard ssh host checking."
  70. log
  71. fi
  72. ;;
  73. esac
  74. done
  75. }
  76. ########################################################################
  77. # export the monkeysphere log level
  78. export MONKEYSPHERE_LOG_LEVEL
  79. if [ "$1" = '--no-connect' ] ; then
  80. NO_CONNECT='true'
  81. shift 1
  82. fi
  83. HOST="$1"
  84. PORT="$2"
  85. if [ -z "$HOST" ] ; then
  86. log "Host not specified."
  87. usage
  88. exit 255
  89. fi
  90. if [ -z "$PORT" ] ; then
  91. PORT=22
  92. fi
  93. # set the host URI
  94. if [ "$PORT" != '22' ] ; then
  95. HOSTP="${HOST}:${PORT}"
  96. else
  97. HOSTP="${HOST}"
  98. fi
  99. URI="ssh://${HOSTP}"
  100. # specify keyserver checking. the behavior of this proxy command is
  101. # intentionally different than that of running monkeyesphere normally,
  102. # and keyserver checking is intentionally done under certain
  103. # circumstances. This can be overridden by setting the
  104. # MONKEYSPHERE_CHECK_KEYSERVER environment variable.
  105. # if the host is in the gpg keyring...
  106. if gpg --list-key ="${URI}" 2>&1 >/dev/null ; then
  107. # do not check the keyserver
  108. CHECK_KEYSERVER="false"
  109. # if the host is NOT in the keyring...
  110. else
  111. # if the host key is found in the known_hosts file...
  112. # FIXME: this only works for default known_hosts location
  113. hostKey=$(ssh-keygen -F "$HOST" 2>/dev/null)
  114. if [ "$hostKey" ] ; then
  115. # do not check the keyserver
  116. # FIXME: more nuanced checking should be done here to properly
  117. # take into consideration hosts that join monkeysphere by
  118. # converting an existing and known ssh key
  119. CHECK_KEYSERVER="false"
  120. # if the host key is not found in the known_hosts file...
  121. else
  122. # check the keyserver
  123. CHECK_KEYSERVER="true"
  124. fi
  125. fi
  126. # set and export the variable for use by monkeysphere
  127. MONKEYSPHERE_CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:="$CHECK_KEYSERVER"}
  128. export MONKEYSPHERE_CHECK_KEYSERVER
  129. # update the known_hosts file for the host
  130. monkeysphere update-known_hosts "$HOSTP"
  131. # output on depending on the return of the update-known_hosts
  132. # subcommand, which is (ultimately) the return code of the
  133. # update_known_hosts function in common
  134. case $? in
  135. 0)
  136. # acceptable host key found so continue to ssh
  137. true
  138. ;;
  139. 1)
  140. # no hosts at all found so also continue (drop through to
  141. # regular ssh host verification)
  142. true
  143. ;;
  144. 2)
  145. # at least one *bad* host key (and no good host keys) was
  146. # found, so output some usefull information
  147. output_no_valid_key
  148. ;;
  149. *)
  150. # anything else drop through
  151. true
  152. ;;
  153. esac
  154. # exec a netcat passthrough to host for the ssh connection
  155. if [ -z "$NO_CONNECT" ] ; then
  156. if (which nc 2>/dev/null >/dev/null); then
  157. exec nc "$HOST" "$PORT"
  158. elif (which socat 2>/dev/null >/dev/null); then
  159. exec socat STDIO "TCP:$HOST:$PORT"
  160. else
  161. echo "Neither netcat nor socat found -- could not complete monkeysphere-ssh-proxycommand connection to $HOST:$PORT" >&2
  162. exit 255
  163. fi
  164. fi