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