summaryrefslogtreecommitdiff
path: root/src/monkeysphere-server
blob: 91e212193dc9999bcf5f3b342639bd4f75a0df01 (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. # Daniel Kahn Gillmor <dkg@fifthhorseman.net>
  7. #
  8. # They are Copyright 2008, and are all released under the GPL, version 3
  9. # or later.
  10. ########################################################################
  11. PGRM=$(basename $0)
  12. SHARE=${MONKEYSPHERE_SHARE:="/usr/share/monkeysphere"}
  13. export SHARE
  14. . "${SHARE}/common" || exit 1
  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. unset GREP_OPTIONS
  21. # default return code
  22. RETURN=0
  23. ########################################################################
  24. # FUNCTIONS
  25. ########################################################################
  26. usage() {
  27. cat <<EOF
  28. usage: $PGRM <subcommand> [options] [args]
  29. MonkeySphere server admin tool.
  30. subcommands:
  31. update-users (u) [USER]... update user authorized_keys files
  32. gen-key (g) [NAME[:PORT]] generate gpg key for the server
  33. --length (-l) BITS key length in bits (2048)
  34. --expire (-e) EXPIRE date to expire
  35. --revoker (-r) FINGERPRINT add a revoker
  36. extend-key (e) EXPIRE extend expiration to EXPIRE
  37. add-hostname (n+) NAME[:PORT] add hostname user ID to server key
  38. revoke-hostname (n-) NAME[:PORT] revoke hostname user ID
  39. show-key (s) output all server host key information
  40. fingerprint (f) output just the key fingerprint
  41. publish-key (p) publish server host key to keyserver
  42. diagnostics (d) report on server monkeysphere status
  43. add-id-certifier (c+) KEYID import and tsign a certification key
  44. --domain (-n) DOMAIN limit ID certifications to DOMAIN
  45. --trust (-t) TRUST trust level of certifier (full)
  46. --depth (-d) DEPTH trust depth for certifier (1)
  47. remove-id-certifier (c-) KEYID remove a certification key
  48. list-id-certifiers (c) list certification keys
  49. gpg-authentication-cmd CMD gnupg-authentication command
  50. help (h,?) this help
  51. EOF
  52. }
  53. su_monkeysphere_user() {
  54. su --preserve-environment "$MONKEYSPHERE_USER" -- -c "$@"
  55. }
  56. # function to interact with the host gnupg keyring
  57. gpg_host() {
  58. local returnCode
  59. GNUPGHOME="$GNUPGHOME_HOST"
  60. export GNUPGHOME
  61. # NOTE: we supress this warning because we need the monkeysphere
  62. # user to be able to read the host pubring. we realize this might
  63. # be problematic, but it's the simplest solution, without too much
  64. # loss of security.
  65. gpg --no-permission-warning "$@"
  66. returnCode="$?"
  67. # always reset the permissions on the host pubring so that the
  68. # monkeysphere user can read the trust signatures
  69. chgrp "$MONKEYSPHERE_USER" "${GNUPGHOME_HOST}/pubring.gpg"
  70. chmod g+r "${GNUPGHOME_HOST}/pubring.gpg"
  71. return "$returnCode"
  72. }
  73. # function to interact with the authentication gnupg keyring
  74. # FIXME: this function requires basically accepts only a single
  75. # argument because of problems with quote expansion. this needs to be
  76. # fixed/improved.
  77. gpg_authentication() {
  78. GNUPGHOME="$GNUPGHOME_AUTHENTICATION"
  79. export GNUPGHOME
  80. su_monkeysphere_user "gpg $@"
  81. }
  82. # output just key fingerprint
  83. fingerprint_server_key() {
  84. gpg_host --list-secret-keys --fingerprint \
  85. --with-colons --fixed-list-mode 2> /dev/null | \
  86. grep '^fpr:' | head -1 | cut -d: -f10
  87. }
  88. # output key information
  89. show_server_key() {
  90. local fingerprint
  91. fingerprint=$(fingerprint_server_key)
  92. gpg_host --fingerprint --list-secret-key "$fingerprint"
  93. }
  94. # update authorized_keys for users
  95. update_users() {
  96. if [ "$1" ] ; then
  97. # get users from command line
  98. unames="$@"
  99. else
  100. # or just look at all users if none specified
  101. unames=$(getent passwd | cut -d: -f1)
  102. fi
  103. # set mode
  104. MODE="authorized_keys"
  105. # set gnupg home
  106. GNUPGHOME="$GNUPGHOME_AUTHENTICATION"
  107. # check to see if the gpg trust database has been initialized
  108. if [ ! -s "${GNUPGHOME}/trustdb.gpg" ] ; then
  109. failure "GNUPG trust database uninitialized. Please see MONKEYSPHERE-SERVER(8)."
  110. fi
  111. # make sure the authorized_keys directory exists
  112. mkdir -p "${VARLIB}/authorized_keys"
  113. # loop over users
  114. for uname in $unames ; do
  115. # check all specified users exist
  116. if ! getent passwd "$uname" >/dev/null ; then
  117. log "----- unknown user '$uname' -----"
  118. continue
  119. fi
  120. # set authorized_user_ids and raw authorized_keys variables,
  121. # translating ssh-style path variables
  122. authorizedUserIDs=$(translate_ssh_variables "$uname" "$AUTHORIZED_USER_IDS")
  123. rawAuthorizedKeys=$(translate_ssh_variables "$uname" "$RAW_AUTHORIZED_KEYS")
  124. # if neither is found, skip user
  125. if [ ! -s "$authorizedUserIDs" ] ; then
  126. if [ "$rawAuthorizedKeys" = '-' -o ! -s "$rawAuthorizedKeys" ] ; then
  127. continue
  128. fi
  129. fi
  130. log "----- user: $uname -----"
  131. # exit if the authorized_user_ids file is empty
  132. if ! check_key_file_permissions "$uname" "$AUTHORIZED_USER_IDS" ; then
  133. log "Improper permissions on authorized_user_ids file path."
  134. continue
  135. fi
  136. # check permissions on the authorized_keys file path
  137. if ! check_key_file_permissions "$uname" "$RAW_AUTHORIZED_KEYS" ; then
  138. log "Improper permissions on authorized_keys file path path."
  139. continue
  140. fi
  141. # make temporary directory
  142. TMPDIR=$(mktemp -d)
  143. # trap to delete temporary directory on exit
  144. trap "rm -rf $TMPDIR" EXIT
  145. # create temporary authorized_user_ids file
  146. TMP_AUTHORIZED_USER_IDS="${TMPDIR}/authorized_user_ids"
  147. touch "$TMP_AUTHORIZED_USER_IDS"
  148. # create temporary authorized_keys file
  149. AUTHORIZED_KEYS="${TMPDIR}/authorized_keys"
  150. touch "$AUTHORIZED_KEYS"
  151. # set restrictive permissions on the temporary files
  152. # FIXME: is there a better way to do this?
  153. chmod 0700 "$TMPDIR"
  154. chmod 0600 "$AUTHORIZED_KEYS"
  155. chmod 0600 "$TMP_AUTHORIZED_USER_IDS"
  156. chown -R "$MONKEYSPHERE_USER" "$TMPDIR"
  157. # if the authorized_user_ids file exists...
  158. if [ -s "$authorizedUserIDs" ] ; then
  159. # copy user authorized_user_ids file to temporary
  160. # location
  161. cat "$authorizedUserIDs" > "$TMP_AUTHORIZED_USER_IDS"
  162. # export needed variables
  163. export AUTHORIZED_KEYS
  164. export TMP_AUTHORIZED_USER_IDS
  165. # process authorized_user_ids file, as monkeysphere
  166. # user
  167. su_monkeysphere_user \
  168. ". ${SHARE}/common; process_authorized_user_ids $TMP_AUTHORIZED_USER_IDS"
  169. RETURN="$?"
  170. fi
  171. # add user-controlled authorized_keys file path if specified
  172. if [ "$rawAuthorizedKeys" != '-' -a -s "$rawAuthorizedKeys" ] ; then
  173. log -n "adding raw authorized_keys file... "
  174. cat "$rawAuthorizedKeys" >> "$AUTHORIZED_KEYS"
  175. loge "done."
  176. fi
  177. # openssh appears to check the contents of the
  178. # authorized_keys file as the user in question, so the
  179. # file must be readable by that user at least.
  180. # FIXME: is there a better way to do this?
  181. chown root "$AUTHORIZED_KEYS"
  182. chgrp $(getent passwd "$uname" | cut -f4 -d:) "$AUTHORIZED_KEYS"
  183. chmod g+r "$AUTHORIZED_KEYS"
  184. # move the resulting authorized_keys file into place
  185. mv -f "$AUTHORIZED_KEYS" "${VARLIB}/authorized_keys/${uname}"
  186. # destroy temporary directory
  187. rm -rf "$TMPDIR"
  188. done
  189. }
  190. # generate server gpg key
  191. gen_key() {
  192. local keyType
  193. local keyLength
  194. local keyUsage
  195. local keyExpire
  196. local revoker
  197. local hostName
  198. local userID
  199. local keyParameters
  200. local fingerprint
  201. # set default key parameter values
  202. keyType="RSA"
  203. keyLength="2048"
  204. keyUsage="auth"
  205. keyExpire=
  206. revoker=
  207. # get options
  208. TEMP=$(getopt -o e:l:r -l expire:,length:,revoker: -n "$PGRM" -- "$@")
  209. if [ $? != 0 ] ; then
  210. exit 1
  211. fi
  212. # Note the quotes around `$TEMP': they are essential!
  213. eval set -- "$TEMP"
  214. while true ; do
  215. case "$1" in
  216. -l|--length)
  217. keyLength="$2"
  218. shift 2
  219. ;;
  220. -e|--expire)
  221. keyExpire="$2"
  222. shift 2
  223. ;;
  224. -r|--revoker)
  225. revoker="$2"
  226. shift 2
  227. ;;
  228. --)
  229. shift
  230. ;;
  231. *)
  232. break
  233. ;;
  234. esac
  235. done
  236. hostName=${1:-$(hostname --fqdn)}
  237. userID="ssh://${hostName}"
  238. # check for presense of key with user ID
  239. if gpg_host --list-key ="$userID" > /dev/null 2>&1 ; then
  240. failure "Key for '$userID' already exists"
  241. fi
  242. # prompt about key expiration if not specified
  243. if [ -z "$keyExpire" ] ; then
  244. keyExpire=$(get_gpg_expiration)
  245. fi
  246. if ! test_gpg_expire "$keyExpire" ; then
  247. failure "invalid key expiration value '$keyExpire'."
  248. fi
  249. # set key parameters
  250. keyParameters=$(cat <<EOF
  251. Key-Type: $keyType
  252. Key-Length: $keyLength
  253. Key-Usage: $keyUsage
  254. Name-Real: $userID
  255. Expire-Date: $keyExpire
  256. EOF
  257. )
  258. # add the revoker field if specified
  259. # FIXME: the "1:" below assumes that $REVOKER's key is an RSA key.
  260. # FIXME: key is marked "sensitive"? is this appropriate?
  261. if [ "$revoker" ] ; then
  262. keyParameters="${keyParameters}"$(cat <<EOF
  263. Revoker: 1:$revoker sensitive
  264. EOF
  265. )
  266. fi
  267. echo "The following key parameters will be used for the host private key:"
  268. echo "$keyParameters"
  269. read -p "Generate key? (Y/n) " OK; OK=${OK:=Y}
  270. if [ ${OK/y/Y} != 'Y' ] ; then
  271. failure "aborting."
  272. fi
  273. # add commit command
  274. keyParameters="${keyParameters}"$(cat <<EOF
  275. %commit
  276. %echo done
  277. EOF
  278. )
  279. log "generating server key..."
  280. echo "$keyParameters" | gpg_host --batch --gen-key
  281. # output the server fingerprint
  282. fingerprint_server_key "=${userID}"
  283. # find the key fingerprint of the newly generated key
  284. fingerprint=$(fingerprint_server_key)
  285. # export host ownertrust to authentication keyring
  286. log "setting ultimate owner trust for server key..."
  287. echo "${fingerprint}:6:" | gpg_authentication "--import-ownertrust"
  288. # translate the private key to ssh format, and export to a file
  289. # for sshs usage.
  290. # NOTE: assumes that the primary key is the proper key to use
  291. (umask 077 && \
  292. gpg_host --export-secret-key "$fingerprint" | \
  293. openpgp2ssh "$fingerprint" > "${VARLIB}/ssh_host_rsa_key")
  294. log "Private SSH host key output to file: ${VARLIB}/ssh_host_rsa_key"
  295. }
  296. # extend the lifetime of a host key:
  297. extend_key() {
  298. local fpr=$(fingerprint_server_key)
  299. local extendTo="$1"
  300. if [ -z "$fpr" ] ; then
  301. failure "You don't appear to have a MonkeySphere host key on this server. Try 'monkeysphere-server gen-key' first."
  302. fi
  303. if [ -z "$extendTo" ]; then
  304. extendTo=$(get_gpg_expiration)
  305. fi
  306. if ! test_gpg_expire "$extendTo" ; then
  307. failure "invalid expiration value '$extendTo'."
  308. fi
  309. gpg_host --quiet --command-fd 0 --edit-key "$fpr" <<EOF
  310. expire
  311. $extendTo
  312. save
  313. EOF
  314. echo "NOTE: Host key expiration date adjusted, but not yet published."
  315. echo "Run '$PGRM publish-key' to publish the new expiration date."
  316. }
  317. # add hostname user ID to server key
  318. add_hostname() {
  319. local userID
  320. local fingerprint
  321. local tmpuidMatch
  322. local line
  323. local adduidCommand
  324. if [ -z "$1" ] ; then
  325. failure "You must specify a hostname to add."
  326. fi
  327. userID="ssh://${1}"
  328. fingerprint=$(fingerprint_server_key)
  329. # match to only ultimately trusted user IDs
  330. tmpuidMatch="u:$(echo $userID | gpg_escape)"
  331. # find the index of the requsted user ID
  332. # NOTE: this is based on circumstantial evidence that the order of
  333. # this output is the appropriate index
  334. if line=$(gpg_host --list-keys --with-colons --fixed-list-mode "0x${fingerprint}!" \
  335. | egrep '^(uid|uat):' | cut -f2,10 -d: | grep -n -x -F "$tmpuidMatch") ; then
  336. failure "Host userID '$userID' already exists."
  337. fi
  338. echo "The following user ID will be added to the host key:"
  339. echo " $userID"
  340. read -p "Are you sure you would like to add this user ID? (y/N) " OK; OK=${OK:=N}
  341. if [ ${OK/y/Y} != 'Y' ] ; then
  342. failure "User ID not added."
  343. fi
  344. # edit-key script command to add user ID
  345. adduidCommand=$(cat <<EOF
  346. adduid
  347. $userID
  348. save
  349. EOF
  350. )
  351. # execute edit-key script
  352. if echo "$adduidCommand" | \
  353. gpg_host --quiet --command-fd 0 --edit-key "0x${fingerprint}!" ; then
  354. # update trust db
  355. gpg_host --check-trustdb
  356. show_server_key
  357. echo "NOTE: User ID added to key, but key not published."
  358. echo "Run '$PGRM publish-key' to publish the new user ID."
  359. else
  360. failure "Problem adding user ID."
  361. fi
  362. }
  363. # revoke hostname user ID to server key
  364. revoke_hostname() {
  365. local userID
  366. local fingerprint
  367. local tmpuidMatch
  368. local line
  369. local uidIndex
  370. local message
  371. local revuidCommand
  372. if [ -z "$1" ] ; then
  373. failure "You must specify a hostname to revoke."
  374. fi
  375. echo "WARNING: There is a known bug in this function."
  376. echo "This function has been known to occasionally revoke the wrong user ID."
  377. echo "Please see the following bug report for more information:"
  378. echo "http://monkeysphere.info/bugs/revoke-hostname-revoking-wrong-userid/"
  379. read -p "Are you sure you would like to proceed? (y/N) " OK; OK=${OK:=N}
  380. if [ ${OK/y/Y} != 'Y' ] ; then
  381. failure "aborting."
  382. fi
  383. userID="ssh://${1}"
  384. fingerprint=$(fingerprint_server_key)
  385. # match to only ultimately trusted user IDs
  386. tmpuidMatch="u:$(echo $userID | gpg_escape)"
  387. # find the index of the requsted user ID
  388. # NOTE: this is based on circumstantial evidence that the order of
  389. # this output is the appropriate index
  390. if line=$(gpg_host --list-keys --with-colons --fixed-list-mode "0x${fingerprint}!" \
  391. | egrep '^(uid|uat):' | cut -f2,10 -d: | grep -n -x -F "$tmpuidMatch") ; then
  392. uidIndex=${line%%:*}
  393. else
  394. failure "No non-revoked user ID '$userID' is found."
  395. fi
  396. echo "The following host key user ID will be revoked:"
  397. echo " $userID"
  398. read -p "Are you sure you would like to revoke this user ID? (y/N) " OK; OK=${OK:=N}
  399. if [ ${OK/y/Y} != 'Y' ] ; then
  400. failure "User ID not revoked."
  401. fi
  402. message="Hostname removed by monkeysphere-server $DATE"
  403. # edit-key script command to revoke user ID
  404. revuidCommand=$(cat <<EOF
  405. $uidIndex
  406. revuid
  407. y
  408. 4
  409. $message
  410. y
  411. save
  412. EOF
  413. )
  414. # execute edit-key script
  415. if echo "$revuidCommand" | \
  416. gpg_host --quiet --command-fd 0 --edit-key "0x${fingerprint}!" ; then
  417. # update trust db
  418. gpg_host --check-trustdb
  419. show_server_key
  420. echo "NOTE: User ID revoked, but revocation not published."
  421. echo "Run '$PGRM publish-key' to publish the revocation."
  422. else
  423. failure "Problem revoking user ID."
  424. fi
  425. }
  426. # publish server key to keyserver
  427. publish_server_key() {
  428. read -p "Really publish host key to $KEYSERVER? (y/N) " OK; OK=${OK:=N}
  429. if [ ${OK/y/Y} != 'Y' ] ; then
  430. failure "key not published."
  431. fi
  432. # find the key fingerprint
  433. fingerprint=$(fingerprint_server_key)
  434. # publish host key
  435. gpg_authentication "--keyserver $KEYSERVER --send-keys '0x${fingerprint}!'"
  436. }
  437. diagnostics() {
  438. # * check on the status and validity of the key and public certificates
  439. local seckey
  440. local keysfound
  441. local curdate
  442. local warnwindow
  443. local warndate
  444. local create
  445. local expire
  446. local uid
  447. local fingerprint
  448. local badhostkeys
  449. local sshd_config
  450. # FIXME: what's the correct, cross-platform answer?
  451. sshd_config=/etc/ssh/sshd_config
  452. seckey=$(gpg_host --list-secret-keys --fingerprint --with-colons --fixed-list-mode)
  453. keysfound=$(echo "$seckey" | grep -c ^sec:)
  454. curdate=$(date +%s)
  455. # warn when anything is 2 months away from expiration
  456. warnwindow='2 months'
  457. warndate=$(date +%s -d "$warnwindow")
  458. echo "Checking host GPG key..."
  459. if (( "$keysfound" < 1 )); then
  460. echo "! No host key found."
  461. echo " - Recommendation: run 'monkeysphere-server gen-key'"
  462. elif (( "$keysfound" > 1 )); then
  463. echo "! More than one host key found?"
  464. # FIXME: recommend a way to resolve this
  465. else
  466. create=$(echo "$seckey" | grep ^sec: | cut -f6 -d:)
  467. expire=$(echo "$seckey" | grep ^sec: | cut -f7 -d:)
  468. fingerprint=$(echo "$seckey" | grep ^fpr: | head -n1 | cut -f10 -d:)
  469. # check for key expiration:
  470. if [ "$expire" ]; then
  471. if (( "$expire" < "$curdate" )); then
  472. echo "! Host key is expired."
  473. echo " - Recommendation: extend lifetime of key with 'monkeysphere-server extend-key'"
  474. elif (( "$expire" < "$warndate" )); then
  475. echo "! Host key expires in less than $warnwindow:" $(date -d "$(( $expire - $curdate )) seconds" +%F)
  476. echo " - Recommendation: extend lifetime of key with 'monkeysphere-server extend-key'"
  477. fi
  478. fi
  479. # and weirdnesses:
  480. if [ "$create" ] && (( "$create" > "$curdate" )); then
  481. echo "! Host key was created in the future(?!). Is your clock correct?"
  482. echo " - Recommendation: Check clock ($(date +%F_%T)); use NTP?"
  483. fi
  484. # check for UserID expiration:
  485. echo "$seckey" | grep ^uid: | cut -d: -f6,7,10 | \
  486. while IFS=: read create expire uid ; do
  487. # FIXME: should we be doing any checking on the form
  488. # of the User ID? Should we be unmangling it somehow?
  489. if [ "$create" ] && (( "$create" > "$curdate" )); then
  490. echo "! User ID '$uid' was created in the future(?!). Is your clock correct?"
  491. echo " - Recommendation: Check clock ($(date +%F_%T)); use NTP?"
  492. fi
  493. if [ "$expire" ] ; then
  494. if (( "$expire" < "$curdate" )); then
  495. echo "! User ID '$uid' is expired."
  496. # FIXME: recommend a way to resolve this
  497. elif (( "$expire" < "$warndate" )); then
  498. echo "! User ID '$uid' expires in less than $warnwindow:" $(date -d "$(( $expire - $curdate )) seconds" +%F)
  499. # FIXME: recommend a way to resolve this
  500. fi
  501. fi
  502. done
  503. # FIXME: verify that the host key is properly published to the
  504. # keyservers (do this with the non-privileged user)
  505. # FIXME: check that there are valid, non-expired certifying signatures
  506. # attached to the host key after fetching from the public keyserver
  507. # (do this with the non-privileged user as well)
  508. # FIXME: propose adding a revoker to the host key if none exist (do we
  509. # have a way to do that after key generation?)
  510. # Ensure that the ssh_host_rsa_key file is present and non-empty:
  511. echo
  512. echo "Checking host SSH key..."
  513. if [ ! -s "${VARLIB}/ssh_host_rsa_key" ] ; then
  514. echo "! The host key as prepared for SSH (${VARLIB}/ssh_host_rsa_key) is missing or empty."
  515. else
  516. if [ $(stat -c '%a' "${VARLIB}/ssh_host_rsa_key") != 600 ] ; then
  517. echo "! Permissions seem wrong for ${VARLIB}/ssh_host_rsa_key -- should be 0600."
  518. fi
  519. # propose changes needed for sshd_config (if any)
  520. if ! grep -q "^HostKey[[:space:]]\+${VARLIB}/ssh_host_rsa_key$" "$sshd_config"; then
  521. echo "! $sshd_config does not point to the monkeysphere host key (${VARLIB}/ssh_host_rsa_key)."
  522. echo " - Recommendation: add a line to $sshd_config: 'HostKey ${VARLIB}/ssh_host_rsa_key'"
  523. fi
  524. if badhostkeys=$(grep -i '^HostKey' "$sshd_config" | grep -q -v "^HostKey[[:space:]]\+${VARLIB}/ssh_host_rsa_key$") ; then
  525. echo "! $sshd_config refers to some non-monkeysphere host keys:"
  526. echo "$badhostkeys"
  527. echo " - Recommendation: remove the above HostKey lines from $sshd_config"
  528. fi
  529. fi
  530. fi
  531. # FIXME: look at the ownership/privileges of the various keyrings,
  532. # directories housing them, etc (what should those values be? can
  533. # we make them as minimal as possible?)
  534. # FIXME: look to see that the ownertrust rules are set properly on the
  535. # authentication keyring
  536. # FIXME: make sure that at least one identity certifier exists
  537. echo
  538. echo "Checking for MonkeySphere-enabled public-key authentication for users ..."
  539. # Ensure that User ID authentication is enabled:
  540. if ! grep -q "^AuthorizedKeysFile[[:space:]]\+${VARLIB}/authorized_keys/%u$" "$sshd_config"; then
  541. echo "! $sshd_config does not point to monkeysphere authorized keys."
  542. echo " - Recommendation: add a line to $sshd_config: 'AuthorizedKeysFile ${VARLIB}/authorized_keys/%u'"
  543. fi
  544. if badauthorizedkeys=$(grep -i '^AuthorizedKeysFile' "$sshd_config" | grep -q -v "^AuthorizedKeysFile[[:space:]]\+${VARLIB}/authorized_keys/%u$") ; then
  545. echo "! $sshd_config refers to non-monkeysphere authorized_keys files:"
  546. echo "$badauthorizedkeys"
  547. echo " - Recommendation: remove the above AuthorizedKeysFile lines from $sshd_config"
  548. fi
  549. }
  550. # retrieve key from web of trust, import it into the host keyring, and
  551. # ltsign the key in the host keyring so that it may certify other keys
  552. add_certifier() {
  553. local domain
  554. local trust
  555. local depth
  556. local keyID
  557. local fingerprint
  558. local ltsignCommand
  559. local trustval
  560. # set default values for trust depth and domain
  561. domain=
  562. trust=full
  563. depth=1
  564. # get options
  565. TEMP=$(getopt -o n:t:d: -l domain:,trust:,depth: -n "$PGRM" -- "$@")
  566. if [ $? != 0 ] ; then
  567. exit 1
  568. fi
  569. # Note the quotes around `$TEMP': they are essential!
  570. eval set -- "$TEMP"
  571. while true ; do
  572. case "$1" in
  573. -n|--domain)
  574. domain="$2"
  575. shift 2
  576. ;;
  577. -t|--trust)
  578. trust="$2"
  579. shift 2
  580. ;;
  581. -d|--depth)
  582. depth="$2"
  583. shift 2
  584. ;;
  585. --)
  586. shift
  587. ;;
  588. *)
  589. break
  590. ;;
  591. esac
  592. done
  593. keyID="$1"
  594. if [ -z "$keyID" ] ; then
  595. failure "You must specify the key ID of a key to add."
  596. fi
  597. export keyID
  598. # get the key from the key server
  599. gpg_authentication "--keyserver $KEYSERVER --recv-key '0x${keyID}!'"
  600. # get the full fingerprint of a key ID
  601. fingerprint=$(gpg_authentication "--list-key --with-colons --with-fingerprint 0x${keyID}!" | \
  602. grep '^fpr:' | grep "$keyID" | cut -d: -f10)
  603. if [ -z "$fingerprint" ] ; then
  604. failure "Key '$keyID' not found."
  605. fi
  606. echo
  607. echo "key found:"
  608. gpg_authentication "--fingerprint 0x${fingerprint}!"
  609. echo "Are you sure you want to add the above key as a"
  610. read -p "certifier of users on this system? (y/N) " OK; OK=${OK:-N}
  611. if [ "${OK/y/Y}" != 'Y' ] ; then
  612. failure "Identity certifier not added."
  613. fi
  614. # export the key to the host keyring
  615. gpg_authentication "--export 0x${fingerprint}!" | gpg_host --import
  616. if [ "$trust" == marginal ]; then
  617. trustval=1
  618. elif [ "$trust" == full ]; then
  619. trustval=2
  620. else
  621. failure "Trust value requested ('$trust') was unclear (only 'marginal' or 'full' are supported)."
  622. fi
  623. # ltsign command
  624. # NOTE: *all* user IDs will be ltsigned
  625. ltsignCommand=$(cat <<EOF
  626. ltsign
  627. y
  628. $trustval
  629. $depth
  630. $domain
  631. y
  632. save
  633. EOF
  634. )
  635. # ltsign the key
  636. if echo "$ltsignCommand" | \
  637. gpg_host --quiet --command-fd 0 --edit-key "0x${fingerprint}!" ; then
  638. # update the trustdb for the authentication keyring
  639. gpg_authentication "--check-trustdb"
  640. echo
  641. echo "Identity certifier added."
  642. else
  643. failure "Problem adding identify certifier."
  644. fi
  645. }
  646. # delete a certifiers key from the host keyring
  647. remove_certifier() {
  648. local keyID
  649. local fingerprint
  650. keyID="$1"
  651. if [ -z "$keyID" ] ; then
  652. failure "You must specify the key ID of a key to remove."
  653. fi
  654. if gpg_authentication "--no-options --list-options show-uid-validity --keyring ${GNUPGHOME_AUTHENTICATION}/pubring.gpg --list-key 0x${keyID}!" ; then
  655. read -p "Really remove above listed identity certifier? (y/N) " OK; OK=${OK:-N}
  656. if [ "${OK/y/Y}" != 'Y' ] ; then
  657. failure "Identity certifier not removed."
  658. fi
  659. else
  660. failure
  661. fi
  662. # delete the requested key
  663. if gpg_authentication "--delete-key --batch --yes 0x${keyID}!" ; then
  664. # delete key from host keyring as well
  665. gpg_host --delete-key --batch --yes "0x${keyID}!"
  666. # update the trustdb for the authentication keyring
  667. gpg_authentication "--check-trustdb"
  668. echo
  669. echo "Identity certifier removed."
  670. else
  671. failure "Problem removing identity certifier."
  672. fi
  673. }
  674. # list the host certifiers
  675. list_certifiers() {
  676. local keys
  677. local key
  678. # find trusted keys in authentication keychain
  679. keys=$(gpg_authentication "--no-options --list-options show-uid-validity --keyring ${GNUPGHOME_AUTHENTICATION}/pubring.gpg --list-keys --with-colons --fingerprint" | \
  680. grep ^pub: | cut -d: -f2,5 | egrep '^(u|f):' | cut -d: -f2)
  681. # output keys
  682. for key in $keys ; do
  683. gpg_authentication "--no-options --list-options show-uid-validity --keyring ${GNUPGHOME_AUTHENTICATION}/pubring.gpg --list-key --fingerprint $key"
  684. done
  685. }
  686. # issue command to gpg-authentication keyring
  687. gpg_authentication_cmd() {
  688. gpg_authentication "$@"
  689. }
  690. ########################################################################
  691. # MAIN
  692. ########################################################################
  693. # unset variables that should be defined only in config file
  694. unset KEYSERVER
  695. unset AUTHORIZED_USER_IDS
  696. unset RAW_AUTHORIZED_KEYS
  697. unset MONKEYSPHERE_USER
  698. # load configuration file
  699. [ -e ${MONKEYSPHERE_SERVER_CONFIG:="${ETC}/monkeysphere-server.conf"} ] && . "$MONKEYSPHERE_SERVER_CONFIG"
  700. # set empty config variable with ones from the environment, or with
  701. # defaults
  702. KEYSERVER=${MONKEYSPHERE_KEYSERVER:=${KEYSERVER:="subkeys.pgp.net"}}
  703. AUTHORIZED_USER_IDS=${MONKEYSPHERE_AUTHORIZED_USER_IDS:=${AUTHORIZED_USER_IDS:="%h/.config/monkeysphere/authorized_user_ids"}}
  704. RAW_AUTHORIZED_KEYS=${MONKEYSPHERE_RAW_AUTHORIZED_KEYS:=${RAW_AUTHORIZED_KEYS:="%h/.ssh/authorized_keys"}}
  705. MONKEYSPHERE_USER=${MONKEYSPHERE_MONKEYSPHERE_USER:=${MONKEYSPHERE_USER:="monkeysphere"}}
  706. # other variables
  707. CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:="true"}
  708. REQUIRED_USER_KEY_CAPABILITY=${MONKEYSPHERE_REQUIRED_USER_KEY_CAPABILITY:="a"}
  709. GNUPGHOME_HOST=${MONKEYSPHERE_GNUPGHOME_HOST:="${VARLIB}/gnupg-host"}
  710. GNUPGHOME_AUTHENTICATION=${MONKEYSPHERE_GNUPGHOME_AUTHENTICATION:="${VARLIB}/gnupg-authentication"}
  711. # export variables needed in su invocation
  712. export DATE
  713. export MODE
  714. export MONKEYSPHERE_USER
  715. export KEYSERVER
  716. export CHECK_KEYSERVER
  717. export REQUIRED_USER_KEY_CAPABILITY
  718. export GNUPGHOME_HOST
  719. export GNUPGHOME_AUTHENTICATION
  720. export GNUPGHOME
  721. # get subcommand
  722. COMMAND="$1"
  723. [ "$COMMAND" ] || failure "Type '$PGRM help' for usage."
  724. shift
  725. case $COMMAND in
  726. 'update-users'|'update-user'|'u')
  727. update_users "$@"
  728. ;;
  729. 'gen-key'|'g')
  730. gen_key "$@"
  731. ;;
  732. 'extend-key'|'e')
  733. extend_key "$@"
  734. ;;
  735. 'add-hostname'|'add-name'|'n+')
  736. add_hostname "$@"
  737. ;;
  738. 'revoke-hostname'|'revoke-name'|'n-')
  739. revoke_hostname "$@"
  740. ;;
  741. 'show-key'|'show'|'s')
  742. show_server_key
  743. ;;
  744. 'show-fingerprint'|'fingerprint'|'f')
  745. fingerprint_server_key
  746. ;;
  747. 'publish-key'|'publish'|'p')
  748. publish_server_key
  749. ;;
  750. 'diagnostics'|'d')
  751. diagnostics
  752. ;;
  753. 'add-identity-certifier'|'add-id-certifier'|'add-certifier'|'c+')
  754. add_certifier "$@"
  755. ;;
  756. 'remove-identity-certifier'|'remove-id-certifier'|'remove-certifier'|'c-')
  757. remove_certifier "$@"
  758. ;;
  759. 'list-identity-certifiers'|'list-id-certifiers'|'list-certifiers'|'list-certifier'|'c')
  760. list_certifiers "$@"
  761. ;;
  762. 'gpg-authentication-cmd')
  763. gpg_authentication_cmd "$@"
  764. ;;
  765. '--help'|'help'|'-h'|'h'|'?')
  766. usage
  767. ;;
  768. *)
  769. failure "Unknown command: '$COMMAND'
  770. Type '$PGRM help' for usage."
  771. ;;
  772. esac
  773. exit "$RETURN"