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