summaryrefslogtreecommitdiff
path: root/src/monkeysphere-server
blob: 4c403f2a2647ea4f074a8bad5637ad134190a97d (plain)
  1. #!/bin/bash
  2. # monkeysphere-server: MonkeySphere server admin tool
  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. ########################################################################
  10. PGRM=$(basename $0)
  11. PGRM_PATH=$(dirname $0)
  12. SHARE=${SHARE:-"/usr/share/monkeysphere"}
  13. export SHARE
  14. . "${SHARE}/common"
  15. VARLIB="/var/lib/monkeysphere"
  16. export VARLIB
  17. # date in UTF format if needed
  18. DATE=$(date -u '+%FT%T')
  19. # unset some environment variables that could screw things up
  20. GREP_OPTIONS=
  21. # default return code
  22. ERR=0
  23. ########################################################################
  24. # FUNCTIONS
  25. ########################################################################
  26. usage() {
  27. cat <<EOF
  28. usage: $PGRM <subcommand> [args]
  29. MonkeySphere server admin tool.
  30. subcommands:
  31. update-users (u) [USER]... update users authorized_keys files
  32. gen-key (g) [HOSTNAME] generate gpg key for the server
  33. show-fingerprint (f) show server's host key fingerprint
  34. publish-key (p) publish server's host key to keyserver
  35. trust-key (t) KEYID [LEVEL] set owner trust for keyid
  36. help (h,?) this help
  37. EOF
  38. }
  39. # generate server gpg key
  40. gen_key() {
  41. local hostName
  42. local userID
  43. local keyParameters
  44. local fingerprint
  45. hostName=${1:-$(hostname --fqdn)}
  46. SERVICE=${SERVICE:-"ssh"}
  47. userID="${SERVICE}://${hostName}"
  48. GNUPGHOME="$GNUPGHOME_HOST"
  49. if gpg --list-key ="$userID" > /dev/null 2>&1 ; then
  50. failure "Key for '$userID' already exists"
  51. fi
  52. # set key defaults
  53. KEY_TYPE=${KEY_TYPE:-"RSA"}
  54. KEY_LENGTH=${KEY_LENGTH:-"2048"}
  55. KEY_USAGE=${KEY_USAGE:-"auth"}
  56. KEY_EXPIRE=${KEY_EXPIRE:-"0"}
  57. cat <<EOF
  58. Please specify how long the key should be valid.
  59. 0 = key does not expire
  60. <n> = key expires in n days
  61. <n>w = key expires in n weeks
  62. <n>m = key expires in n months
  63. <n>y = key expires in n years
  64. EOF
  65. read -p "Key is valid for? ($KEY_EXPIRE) " KEY_EXPIRE; KEY_EXPIRE=${KEY_EXPIRE:-"0"}
  66. # set key parameters
  67. keyParameters=$(cat <<EOF
  68. Key-Type: $KEY_TYPE
  69. Key-Length: $KEY_LENGTH
  70. Key-Usage: $KEY_USAGE
  71. Name-Real: $userID
  72. Expire-Date: $KEY_EXPIRE
  73. EOF
  74. )
  75. # add the revoker field if requested
  76. # FIXME: the "1:" below assumes that $REVOKER's key is an RSA key. why?
  77. # FIXME: why is this marked "sensitive"? how will this signature ever
  78. # be transmitted to the expected revoker?
  79. if [ "$REVOKER" ] ; then
  80. keyParameters="${keyParameters}"$(cat <<EOF
  81. Revoker: 1:$REVOKER sensitive
  82. EOF
  83. )
  84. fi
  85. echo "The following key parameters will be used:"
  86. echo "$keyParameters"
  87. read -p "Generate key? [Y|n]: " OK; OK=${OK:=Y}
  88. if [ ${OK/y/Y} != 'Y' ] ; then
  89. failure "aborting."
  90. fi
  91. # add commit command
  92. keyParameters="${keyParameters}"$(cat <<EOF
  93. %commit
  94. %echo done
  95. EOF
  96. )
  97. log "generating server key..."
  98. GNUPGHOME="$GNUPGHOME_HOST"
  99. echo "$keyParameters" | gpg --batch --gen-key
  100. # output the server fingerprint
  101. fingerprint_server_key "=${userID}"
  102. # find the key fingerprint of the server primary key
  103. GNUPGHOME="$GNUPGHOME_HOST"
  104. fingerprint=$(gpg --list-key --with-colons --with-fingerprint "=${userID}" | \
  105. grep '^fpr:' | head -1 | cut -d: -f10)
  106. # export the host key to the authentication keyring
  107. GNUPGHOME="$GNUPGHOME_HOST" gpg --export "$fingerprint" | \
  108. su --preserve-environment "$MONKEYSPHERE_USER" -c -- \
  109. "GNUPGHOME=$GNUPGHOME_AUTHENTICATION gpg --import"
  110. # set host key owner trust to ultimate in authentication keyring
  111. echo "${fingerprint}:6:" | \
  112. su --preserve-environment "$MONKEYSPHERE_USER" -c -- \
  113. "GNUPGHOME=$GNUPGHOME_AUTHENTICATION gpg --import-ownertrust"
  114. # write the key to the file
  115. # NOTE: assumes that the primary key is the proper key to use
  116. GNUPGHOME="$GNUPGHOME_HOST"
  117. (umask 077 && gpgsecret2ssh "$fingerprint" > "${VARLIB}/ssh_host_rsa_key")
  118. log "Private SSH host key output to file: ${VARLIB}/ssh_host_rsa_key"
  119. }
  120. # gpg output key fingerprint
  121. fingerprint_server_key() {
  122. local ID
  123. if [ "$1" ] ; then
  124. ID="$1"
  125. else
  126. ID="=ssh://$(hostname --fqdn)"
  127. fi
  128. gpg --fingerprint --list-secret-keys "$ID"
  129. }
  130. # publish server key to keyserver
  131. publish_server_key() {
  132. read -p "really publish key to $KEYSERVER? [y|N]: " OK; OK=${OK:=N}
  133. if [ ${OK/y/Y} != 'Y' ] ; then
  134. failure "aborting."
  135. fi
  136. # publish host key
  137. # FIXME: need to figure out better way to identify host key
  138. # dummy command so as not to publish fakes keys during testing
  139. # eventually:
  140. #gpg --keyserver "$KEYSERVER" --send-keys $(hostname -f)
  141. failure "NOT PUBLISHED (to avoid permanent publication errors during monkeysphere development).
  142. To publish manually, do: gpg --keyserver $KEYSERVER --send-keys $(hostname -f)"
  143. }
  144. # retrieve key from web of trust, and set owner trust to "full"
  145. # if key is found.
  146. trust_key() {
  147. local keyID
  148. local trustLevel
  149. keyID="$1"
  150. trustLevel="$2"
  151. if [ -z "$keyID" ] ; then
  152. failure "You must specify key to trust."
  153. fi
  154. export keyID
  155. # get the key from the key server
  156. GNUPGHOME="$GNUPGHOME_AUTHENTICATION"
  157. su --preserve-environment "$MONKEYSPHERE_USER" -c -- \
  158. "gpg --keyserver $KEYSERVER --recv-key $keyID"
  159. if [ "$?" != 0 ] ; then
  160. failure "Could not retrieve key '$keyID'."
  161. fi
  162. # move the key from the authentication keyring to the host keyring
  163. GNUPGHOME="$GNUPGHOME_AUTHENTICATION"
  164. su --preserve-environment "$MONKEYSPHERE_USER" -c -- \
  165. "gpg --export $keyID" | \
  166. GNUPGHOME="$GNUPGHOME_HOST" gpg --import
  167. # get key fingerprint
  168. GNUPGHOME="$GNUPGHOME_HOST"
  169. fingerprint=$(get_key_fingerprint "$keyID")
  170. echo "key found:"
  171. GNUPGHOME="$GNUPGHOME_HOST"
  172. gpg --fingerprint "$fingerprint"
  173. while [ -z "$trustLevel" ] ; do
  174. cat <<EOF
  175. Please decide how far you trust this user to correctly verify other users' keys
  176. (by looking at passports, checking fingerprints from different sources, etc.)
  177. 1 = I don't know or won't say
  178. 2 = I do NOT trust
  179. 3 = I trust marginally
  180. 4 = I trust fully
  181. 5 = I trust ultimately
  182. EOF
  183. read -p "Your decision? " trustLevel
  184. if echo "$trustLevel" | grep -v "[1-5]" ; then
  185. echo "Unknown trust level '$trustLevel'."
  186. unset trustLevel
  187. elif [ "$trustLevel" = 'q' ] ; then
  188. failure "Aborting."
  189. fi
  190. done
  191. # attach a "non-exportable" signature to the key
  192. # this is required for the key to have any validity at all
  193. # the 'y's on stdin indicates "yes, i really want to sign"
  194. GNUPGHOME="$GNUPGHOME_HOST"
  195. echo -e 'y\ny' | \
  196. gpg --quiet --lsign-key --command-fd 0 "$fingerprint"
  197. # copy the host keyring into the authentication keyring
  198. mv "$GNUPGHOME_AUTHENTICATION"/pubring.gpg{,.old}
  199. cp "$GNUPGHOME_HOST"/pubring.gpg "$GNUPGHOME_AUTHENTICATION"/pubring.gpg
  200. chown "$MONKEYSPHERE_USER" "$GNUPGHOME_AUTHENTICATION"/pubring.gpg
  201. GNUPGHOME="$GNUPGHOME_AUTHENTICATION"
  202. su --preserve-environment "$MONKEYSPHERE_USER" -c -- \
  203. "gpg --import ${GNUPGHOME_AUTHENTICATION}/pubring.gpg.old"
  204. # index trustLevel by one to difference between level in ui and level
  205. # internally
  206. trustLevel=$((trustLevel+1))
  207. # import new owner trust level for key
  208. GNUPGHOME="$GNUPGHOME_AUTHENTICATION"
  209. echo "${fingerprint}:${trustLevel}:" | \
  210. su --preserve-environment "$MONKEYSPHERE_USER" -c -- \
  211. "GNUPGHOME=$GNUPGHOME_AUTHENTICATION gpg --import-ownertrust"
  212. if [ $? = 0 ] ; then
  213. log "Owner trust updated."
  214. else
  215. failure "There was a problem changing owner trust."
  216. fi
  217. }
  218. ########################################################################
  219. # MAIN
  220. ########################################################################
  221. COMMAND="$1"
  222. [ "$COMMAND" ] || failure "Type '$PGRM help' for usage."
  223. shift
  224. # set ms home directory
  225. MS_HOME=${MS_HOME:-"$ETC"}
  226. # load configuration file
  227. MS_CONF=${MS_CONF:-"$MS_HOME"/monkeysphere-server.conf}
  228. [ -e "$MS_CONF" ] && . "$MS_CONF"
  229. # set empty config variable with defaults
  230. MONKEYSPHERE_USER=${MONKEYSPHERE_USER:-"monkeysphere"}
  231. KEYSERVER=${KEYSERVER:-"subkeys.pgp.net"}
  232. CHECK_KEYSERVER=${CHECK_KEYSERVER:="true"}
  233. AUTHORIZED_USER_IDS=${AUTHORIZED_USER_IDS:-"%h/.config/monkeysphere/authorized_user_ids"}
  234. RAW_AUTHORIZED_KEYS=${RAW_AUTHORIZED_KEYS:-"%h/.ssh/authorized_keys"}
  235. # other variables
  236. REQUIRED_USER_KEY_CAPABILITY=${REQUIRED_USER_KEY_CAPABILITY:-"a"}
  237. GNUPGHOME_HOST=${GNUPGHOME_HOST:-"${VARLIB}/gnupg-host"}
  238. GNUPGHOME_AUTHENTICATION=${GNUPGHOME_AUTHENTICATION:-"${VARLIB}/gnupg-authentication"}
  239. # export variables
  240. export MODE
  241. export MONKEYSPHERE_USER
  242. export KEYSERVER
  243. export CHECK_KEYSERVER
  244. export REQUIRED_USER_KEY_CAPABILITY
  245. export GNUPGHOME_HOST
  246. export GNUPGHOME_AUTHENTICATION
  247. export GNUPGHOME
  248. case $COMMAND in
  249. 'update-users'|'update-user'|'u')
  250. if [ "$1" ] ; then
  251. # get users from command line
  252. unames="$@"
  253. else
  254. # or just look at all users if none specified
  255. unames=$(getent passwd | cut -d: -f1)
  256. fi
  257. # set mode
  258. MODE="authorized_keys"
  259. # set gnupg home
  260. GNUPGHOME="$GNUPGHOME_AUTHENTICATION"
  261. # check to see if the gpg trust database has been initialized
  262. if [ ! -s "${GNUPGHOME}/trustdb.gpg" ] ; then
  263. failure "GNUPG trust database uninitialized. Please see MONKEYSPHERE-SERVER(8)."
  264. fi
  265. # make sure the authorized_keys directory exists
  266. mkdir -p "${VARLIB}/authorized_keys"
  267. # loop over users
  268. for uname in $unames ; do
  269. # check all specified users exist
  270. if ! getent passwd "$uname" >/dev/null ; then
  271. error "----- unknown user '$uname' -----"
  272. continue
  273. fi
  274. # set authorized_user_ids and raw authorized_keys variables,
  275. # translating ssh-style path variables
  276. authorizedUserIDs=$(translate_ssh_variables "$uname" "$AUTHORIZED_USER_IDS")
  277. rawAuthorizedKeys=$(translate_ssh_variables "$uname" "$RAW_AUTHORIZED_KEYS")
  278. # if neither is found, skip user
  279. if [ ! -s "$authorizedUserIDs" ] ; then
  280. if [ "$rawAuthorizedKeys" = '-' -o ! -s "$rawAuthorizedKeys" ] ; then
  281. continue
  282. fi
  283. fi
  284. log "----- user: $uname -----"
  285. # make temporary directory
  286. TMPDIR=$(mktemp -d)
  287. # trap to delete temporary directory on exit
  288. trap "rm -rf $TMPDIR" EXIT
  289. # create temporary authorized_user_ids file
  290. TMP_AUTHORIZED_USER_IDS="${TMPDIR}/authorized_user_ids"
  291. touch "$TMP_AUTHORIZED_USER_IDS"
  292. # create temporary authorized_keys file
  293. AUTHORIZED_KEYS="${TMPDIR}/authorized_keys"
  294. touch "$AUTHORIZED_KEYS"
  295. # set restrictive permissions on the temporary files
  296. # FIXME: is there a better way to do this?
  297. chmod 0700 "$TMPDIR"
  298. chmod 0600 "$AUTHORIZED_KEYS"
  299. chmod 0600 "$TMP_AUTHORIZED_USER_IDS"
  300. chown -R "$MONKEYSPHERE_USER" "$TMPDIR"
  301. # if the authorized_user_ids file exists...
  302. if [ -s "$authorizedUserIDs" ] ; then
  303. # copy user authorized_user_ids file to temporary
  304. # location
  305. cat "$authorizedUserIDs" > "$TMP_AUTHORIZED_USER_IDS"
  306. # export needed variables
  307. export AUTHORIZED_KEYS
  308. export TMP_AUTHORIZED_USER_IDS
  309. # process authorized_user_ids file, as monkeysphere
  310. # user
  311. su --preserve-environment "$MONKEYSPHERE_USER" -c -- \
  312. ". ${SHARE}/common; process_authorized_user_ids $TMP_AUTHORIZED_USER_IDS"
  313. fi
  314. # add user-controlled authorized_keys file path if specified
  315. if [ "$rawAuthorizedKeys" != '-' -a -s "$rawAuthorizedKeys" ] ; then
  316. log -n "adding raw authorized_keys file... "
  317. cat "$rawAuthorizedKeys" >> "$AUTHORIZED_KEYS"
  318. loge "done."
  319. fi
  320. # openssh appears to check the contents of the
  321. # authorized_keys file as the user in question, so the
  322. # file must be readable by that user at least.
  323. # FIXME: is there a better way to do this?
  324. chown root "$AUTHORIZED_KEYS"
  325. chgrp $(getent passwd "$uname" | cut -f4 -d:) "$AUTHORIZED_KEYS"
  326. chmod g+r "$AUTHORIZED_KEYS"
  327. # if the resulting authorized_keys file is not empty, move
  328. # it into place
  329. mv -f "$AUTHORIZED_KEYS" "${VARLIB}/authorized_keys/${uname}"
  330. log "authorized_keys file updated."
  331. # destroy temporary directory
  332. rm -rf "$TMPDIR"
  333. done
  334. ;;
  335. 'gen-key'|'g')
  336. # set gnupg home
  337. GNUPGHOME="$GNUPGHOME_HOST"
  338. gen_key "$@"
  339. ;;
  340. 'show-fingerprint'|'f')
  341. # set gnupg home
  342. GNUPGHOME="$GNUPGHOME_HOST"
  343. fingerprint_server_key "$@"
  344. ;;
  345. 'publish-key'|'p')
  346. # set gnupg home
  347. GNUPGHOME="$GNUPGHOME_HOST"
  348. publish_server_key
  349. ;;
  350. 'trust-key'|'t')
  351. trust_key "$@"
  352. ;;
  353. 'help'|'h'|'?')
  354. usage
  355. ;;
  356. *)
  357. failure "Unknown command: '$COMMAND'
  358. Type '$PGRM help' for usage."
  359. ;;
  360. esac
  361. exit "$ERR"