summaryrefslogtreecommitdiff
path: root/src/monkeysphere-host
blob: 32d843b134e606585a5a50064ff2f8598771b3a7 (plain)
  1. #!/usr/bin/env bash
  2. # monkeysphere-host: Monkeysphere host admin tool
  3. #
  4. # The monkeysphere scripts are written by:
  5. # Jameson Rollins <jrollins@finestructure.net>
  6. # Jamie McClelland <jm@mayfirst.org>
  7. # Daniel Kahn Gillmor <dkg@fifthhorseman.net>
  8. # Micah Anderson <micah@riseup.net>
  9. #
  10. # They are Copyright 2008-2009, and are all released under the GPL,
  11. # version 3 or later.
  12. ########################################################################
  13. set -e
  14. # set the pipefail option so pipelines fail on first command failure
  15. set -o pipefail
  16. PGRM=$(basename $0)
  17. SYSSHAREDIR=${MONKEYSPHERE_SYSSHAREDIR:-"/usr/share/monkeysphere"}
  18. export SYSSHAREDIR
  19. . "${SYSSHAREDIR}/common" || exit 1
  20. SYSDATADIR=${MONKEYSPHERE_SYSDATADIR:-"/var/lib/monkeysphere"}
  21. export SYSDATADIR
  22. # sharedir for host functions
  23. MHSHAREDIR="${SYSSHAREDIR}/mh"
  24. # datadir for host functions
  25. MHDATADIR="${SYSDATADIR}/host"
  26. # host pub key files
  27. HOST_KEY_PUB="${SYSDATADIR}/ssh_host_rsa_key.pub"
  28. HOST_KEY_PUB_GPG="${SYSDATADIR}/ssh_host_rsa_key.pub.gpg"
  29. # UTC date in ISO 8601 format if needed
  30. DATE=$(date -u '+%FT%T')
  31. # unset some environment variables that could screw things up
  32. unset GREP_OPTIONS
  33. # default return code
  34. RETURN=0
  35. ########################################################################
  36. # FUNCTIONS
  37. ########################################################################
  38. usage() {
  39. cat <<EOF >&2
  40. usage: $PGRM <subcommand> [options] [args]
  41. Monkeysphere host admin tool.
  42. subcommands:
  43. show-key (s) output all host key information
  44. set-expire (e) EXPIRE set host key expiration
  45. add-hostname (n+) NAME[:PORT] add hostname user ID to host key
  46. revoke-hostname (n-) NAME[:PORT] revoke hostname user ID
  47. add-revoker (o) FINGERPRINT add a revoker to the host key
  48. revoke-key (r) revoke host key
  49. publish-key (p) publish host key to keyserver
  50. expert <expert-subcommand> run expert command
  51. expert help expert command help
  52. version (v) show version number
  53. help (h,?) this help
  54. EOF
  55. }
  56. # function to interact with the gpg keyring
  57. gpg_host() {
  58. GNUPGHOME="$GNUPGHOME_HOST" gpg "$@"
  59. }
  60. # command to list the info about the host key, in colon format
  61. gpg_host_list() {
  62. gpg_host --list-keys --with-colons --fixed-list-mode \
  63. --with-fingerprint --with-fingerprint \
  64. "0x${HOST_FINGERPRINT}!"
  65. }
  66. # command for edit key scripts, takes scripts on stdin
  67. gpg_host_edit() {
  68. gpg_host --quiet --command-fd 0 --edit-key \
  69. "0x${HOST_FINGERPRINT}!" "$@"
  70. }
  71. # export the host key to stdout
  72. gpg_host_export() {
  73. gpg_host --export --armor --export-options export-minimal \
  74. "0x${HOST_FINGERPRINT}!"
  75. }
  76. # export the host public key to the monkeysphere gpg pub key file
  77. create_gpg_pub_file() {
  78. log debug "creating openpgp public key file..."
  79. gpg_host_export > "$HOST_KEY_PUB_GPG"
  80. log info "GPG host public key file: $HOST_KEY_PUB_GPG"
  81. }
  82. # load the host fingerprint into the fingerprint variable, using the
  83. # export gpg pub key file
  84. # FIXME: this seems much less than ideal, with all this temp keyring
  85. # stuff. is there a way we can do this without having to create temp
  86. # files?
  87. load_fingerprint() {
  88. if [ -f "$HOST_KEY_PUB_GPG" ] ; then
  89. HOST_FINGERPRINT=$( \
  90. (FUBAR=$(mktemp -d) && export GNUPGHOME="$FUBAR" \
  91. && gpg --quiet --import \
  92. && gpg --quiet --list-keys --with-colons --with-fingerprint \
  93. && rm -rf "$FUBAR") <"$HOST_KEY_PUB_GPG" \
  94. | grep '^fpr:' | cut -d: -f10 )
  95. else
  96. HOST_FINGERPRINT=
  97. fi
  98. }
  99. # load the host fingerprint into the fingerprint variable, using the
  100. # gpg host secret key
  101. load_fingerprint_secret() {
  102. HOST_FINGERPRINT=$( \
  103. gpg_host --quiet --list-secret-key \
  104. --with-colons --with-fingerprint \
  105. | grep '^fpr:' | cut -d: -f10 )
  106. }
  107. # output host key ssh fingerprint
  108. load_ssh_fingerprint() {
  109. [ -f "$HOST_KEY_PUB" ] || return 0
  110. HOST_FINGERPRINT_SSH=$(ssh-keygen -l -f "$HOST_KEY_PUB" \
  111. | awk '{ print $1, $2, $4 }')
  112. }
  113. # fail if host key present
  114. check_host_key() {
  115. [ -z "$HOST_FINGERPRINT" ] \
  116. || failure "An OpenPGP host key already exists."
  117. }
  118. # fail if host key not present
  119. check_host_no_key() {
  120. [ "$HOST_FINGERPRINT" ] \
  121. || failure "You don't appear to have a Monkeysphere host key on this server. Please run 'monkeysphere-host expert import-key' first."
  122. }
  123. # output the index of a user ID on the host key
  124. # return 1 if user ID not found
  125. find_host_userid() {
  126. local userID="$1"
  127. local tmpuidMatch
  128. local line
  129. # match to only ultimately trusted user IDs
  130. tmpuidMatch="u:$(echo $userID | gpg_escape)"
  131. # find the index of the requsted user ID
  132. # NOTE: this is based on circumstantial evidence that the order of
  133. # this output is the appropriate index
  134. line=$(gpg_host_list | egrep '^(uid|uat):' | cut -f2,10 -d: | \
  135. grep -n -x -F "$tmpuidMatch" 2>/dev/null)
  136. if [ "$line" ] ; then
  137. echo ${line%%:*}
  138. return 0
  139. else
  140. return 1
  141. fi
  142. }
  143. # show info about the host key
  144. show_key() {
  145. gpg_host --fingerprint --list-key --list-options show-unusable-uids \
  146. "0x${HOST_FINGERPRINT}!" 2>/dev/null || true
  147. # FIXME: make sure expiration date is shown
  148. echo "OpenPGP fingerprint: $HOST_FINGERPRINT"
  149. load_ssh_fingerprint
  150. if [ "$HOST_FINGERPRINT_SSH" ] ; then
  151. echo "ssh fingerprint: $HOST_FINGERPRINT_SSH"
  152. else
  153. log error "SSH host key not found."
  154. fi
  155. # FIXME: other relevant key parameters?
  156. }
  157. ########################################################################
  158. # MAIN
  159. ########################################################################
  160. # unset variables that should be defined only in config file
  161. unset KEYSERVER
  162. unset MONKEYSPHERE_USER
  163. # load configuration file
  164. [ -e ${MONKEYSPHERE_HOST_CONFIG:="${SYSCONFIGDIR}/monkeysphere-host.conf"} ] && . "$MONKEYSPHERE_HOST_CONFIG"
  165. # set empty config variable with ones from the environment, or with
  166. # defaults
  167. LOG_LEVEL=${MONKEYSPHERE_LOG_LEVEL:=${LOG_LEVEL:="INFO"}}
  168. KEYSERVER=${MONKEYSPHERE_KEYSERVER:=${KEYSERVER:="pool.sks-keyservers.net"}}
  169. AUTHORIZED_USER_IDS=${MONKEYSPHERE_AUTHORIZED_USER_IDS:=${AUTHORIZED_USER_IDS:="%h/.monkeysphere/authorized_user_ids"}}
  170. RAW_AUTHORIZED_KEYS=${MONKEYSPHERE_RAW_AUTHORIZED_KEYS:=${RAW_AUTHORIZED_KEYS:="%h/.ssh/authorized_keys"}}
  171. MONKEYSPHERE_USER=${MONKEYSPHERE_MONKEYSPHERE_USER:=${MONKEYSPHERE_USER:="monkeysphere"}}
  172. # other variables
  173. CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:="true"}
  174. GNUPGHOME_HOST=${MONKEYSPHERE_GNUPGHOME_HOST:="${MHDATADIR}"}
  175. # export variables needed in su invocation
  176. export DATE
  177. export MODE
  178. export LOG_LEVEL
  179. export MONKEYSPHERE_USER
  180. export KEYSERVER
  181. export GNUPGHOME_HOST
  182. export GNUPGHOME
  183. export HOST_FINGERPRINT=
  184. export HOST_FINGERPRINT_SSH=
  185. # get subcommand
  186. COMMAND="$1"
  187. [ "$COMMAND" ] || failure "Type '$PGRM help' for usage."
  188. shift
  189. case $COMMAND in
  190. 'show-key'|'show'|'s')
  191. load_fingerprint
  192. check_host_no_key
  193. show_key
  194. ;;
  195. 'set-expire'|'extend-key'|'e')
  196. load_fingerprint
  197. check_host_no_key
  198. source "${MHSHAREDIR}/set_expire"
  199. set_expire "$@"
  200. ;;
  201. 'add-hostname'|'add-name'|'n+')
  202. load_fingerprint
  203. check_host_no_key
  204. source "${MHSHAREDIR}/add_hostname"
  205. add_hostname "$@"
  206. ;;
  207. 'revoke-hostname'|'revoke-name'|'n-')
  208. load_fingerprint
  209. check_host_no_key
  210. source "${MHSHAREDIR}/revoke_hostname"
  211. revoke_hostname "$@"
  212. ;;
  213. 'add-revoker'|'o')
  214. load_fingerprint
  215. check_host_no_key
  216. source "${MHSHAREDIR}/add_revoker"
  217. add_revoker "$@"
  218. ;;
  219. 'revoke-key'|'r')
  220. load_fingerprint
  221. check_host_no_key
  222. source "${MHSHAREDIR}/revoke_key"
  223. revoke_key "$@"
  224. ;;
  225. 'publish-key'|'publish'|'p')
  226. load_fingerprint
  227. check_host_no_key
  228. source "${MHSHAREDIR}/publish_key"
  229. publish_key
  230. ;;
  231. 'expert')
  232. SUBCOMMAND="$1"
  233. shift
  234. case "$SUBCOMMAND" in
  235. 'help'|'h'|'?')
  236. cat <<EOF
  237. usage: $PGRM expert <subcommand> [options] [args]
  238. expert subcommands:
  239. import-key (i) FILE [NAME[:PORT]] import existing ssh key to gpg
  240. gen-key (g) [NAME[:PORT]] generate gpg key for the host
  241. --length (-l) BITS key length in bits (2048)
  242. diagnostics (d) monkeysphere host status
  243. EOF
  244. ;;
  245. 'import-key'|'i')
  246. load_fingerprint
  247. check_host_key
  248. source "${MHSHAREDIR}/import_key"
  249. import_key "$@"
  250. ;;
  251. 'gen-key'|'g')
  252. load_fingerprint
  253. check_host_key
  254. source "${MHSHAREDIR}/gen_key"
  255. gen_key "$@"
  256. ;;
  257. 'diagnostics'|'d')
  258. source "${MHSHAREDIR}/diagnostics"
  259. diagnostics
  260. ;;
  261. *)
  262. failure "Unknown expert subcommand: '$COMMAND'
  263. Type '$PGRM help' for usage."
  264. ;;
  265. esac
  266. ;;
  267. 'version'|'v')
  268. echo "$VERSION"
  269. ;;
  270. '--help'|'help'|'-h'|'h'|'?')
  271. usage
  272. ;;
  273. *)
  274. failure "Unknown command: '$COMMAND'
  275. Type '$PGRM help' for usage."
  276. ;;
  277. esac
  278. exit "$RETURN"