Merge branch 'master' of http://lair.fifthhorseman.net/~dkg/git/monkeysphere
authorMatt Goins <mjgoins@openflows.com>
Wed, 25 Jun 2008 05:59:19 +0000 (01:59 -0400)
committerMatt Goins <mjgoins@openflows.com>
Wed, 25 Jun 2008 05:59:19 +0000 (01:59 -0400)
17 files changed:
debian/changelog
debian/control
debian/dirs
debian/monkeysphere.dirs
doc/TODO
doc/george/changelog
etc/monkeysphere-server.conf
etc/monkeysphere.conf
man/man1/openpgp2ssh.1
man/man8/monkeysphere-server.8
src/common
src/keytrans/gnutls-helpers.c
src/keytrans/gnutls-helpers.h
src/keytrans/openpgp2ssh.c
src/monkeysphere
src/monkeysphere-server
src/monkeysphere-ssh-proxycommand

index 41af80cfed83d0f4dcfefed073bd641c00157799..82f274a02f442d2988eaf4a447f61944487c7eb7 100644 (file)
@@ -1,7 +1,31 @@
-monkeysphere (0.2-1) UNRELEASED; urgency=low
+monkeysphere (0.4-1) UNRELEASED; urgency=low
+
+  [Daniel Kahn Gillmor]
+  * New version (switch UNRELEASED to experimental when ready)
+
+ -- Daniel Kahn Gillmor <dkg-debian.org@fifthhorseman.net>  Tue, 24 Jun 2008 01:25:45 -0400
+
+monkeysphere (0.3-1) experimental; urgency=low
+
+  [ Daniel Kahn Gillmor ]
+  * new version.
+
+  [ Jameson Graef Rollins ]
+  * Move files in /var/cache/monkeysphere and GNUPGHOME for server to
+    the more appropriate /var/lib/monkeysphere.
+
+ -- Daniel Kahn Gillmor <dkg-debian.org@fifthhorseman.net>  Tue, 24 Jun 2008 00:55:29 -0400
+
+monkeysphere (0.2-2) experimental; urgency=low
+
+  * added lockfile-progs dependency
+
+ -- Daniel Kahn Gillmor <dkg-debian.org@fifthhorseman.net>  Mon, 23 Jun 2008 19:34:05 -0400
+
+monkeysphere (0.2-1) experimental; urgency=low
 
   [ Daniel Kahn Gillmor ]
-  * NOT YET RELEASED (switch to "experimental" when ready to release)
+  * openpgp2ssh now supports specifying keys by full fingerprint.
 
   [ Jameson Graef Rollins ]
   * Add AUTHORIZED_USER_IDS config variable for server, which defaults to
@@ -14,7 +38,7 @@ monkeysphere (0.2-1) UNRELEASED; urgency=low
   * Better failure/prompting for gen-subkey
   * Add ability to set any owner trust level for keys in server keychain.
 
- -- Jameson Graef Rollins <jrollins@phys.columbia.edu>  Sun, 22 Jun 2008 11:42:42 -0400
+ -- Daniel Kahn Gillmor <dkg-debian.org@fifthhorseman.net>  Mon, 23 Jun 2008 17:03:19 -0400
 
 monkeysphere (0.1-1) experimental; urgency=low
 
index d4d25c6cd2c75e2db71df111117fd73e857efb96..4f0e5f5ef72a9ab5f593748fb7840374a2e264f6 100644 (file)
@@ -3,14 +3,14 @@ Section: net
 Priority: extra
 Maintainer: Daniel Kahn Gillmor <dkg-debian.org@fifthhorseman.net>
 Uploaders: Jameson Rollins <jrollins@fifthhorseman.net>
-Build-Depends: debhelper (>= 7.0), libgnutls-dev (>= 2.3.14)
+Build-Depends: debhelper (>= 7.0), libgnutls-dev (>= 2.4.0)
 Standards-Version: 3.8.0.1
 Homepage: http://cmrg.fifthhorseman.net/wiki/OpenPGPandSSH
 Dm-Upload-Allowed: yes
 
 Package: monkeysphere
 Architecture: any
-Depends: openssh-client, gnupg | gnupg2, coreutils (>= 6), moreutils, ${shlibs:Depends}
+Depends: openssh-client, gnupg | gnupg2, coreutils (>= 6), moreutils, lockfile-progs, ${shlibs:Depends}
 Recommends: netcat
 Enhances: openssh-client, openssh-server
 Description: use the OpenPGP web of trust to verify ssh connections
index b458649fbeef34dc0cc0fa0090fd9f917c1c8b8a..43b742ae9448d9ac532a159bc6699ec02c01835a 100644 (file)
@@ -1,5 +1,5 @@
-var/cache/monkeysphere
-var/cache/monkeysphere/authorized_keys
+var/lib/monkeysphere
+var/lib/monkeysphere/authorized_keys
 usr/bin
 usr/sbin
 usr/share
index 6e9089952ab4095b9bc12d9163cc9aeeacf7299e..b0b2d9c195b1670e544f669625ed86e0fee76e70 100644 (file)
@@ -1,4 +1,4 @@
 usr/share/monkeysphere
-var/cache/monkeysphere
-var/cache/monkeysphere/authorized_keys
+var/lib/monkeysphere
+var/lib/monkeysphere/authorized_keys
 etc/monkeysphere
index 4f32bb065727653c0fa8c83dceb6bb7e69bb1bec..e50da4dd1de55be70ec231905cb238b4fc2469a6 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -5,9 +5,6 @@ Detail advantages of monkeysphere: detail the race conditions in ssh,
    and how the monkeysphere can help you reduce these threat vectors:
    threat model reduction diagrams.
 
-Determine how openssh handles multiple processes writing to
-   known_hosts/authorized_keys files (lockfile, atomic appends?)
-
 Handle unverified monkeysphere hosts in such a way that they're not
    always removed from known_hosts file.  Ask user to lsign the host
    key?
@@ -30,22 +27,10 @@ Ensure that authorized_user_ids are under as tight control as ssh
    expects from authorized_keys: we don't want monkeysphere to be a
    weak link in the filesystem.
 
-What happens when a user account has no corresponding
-   /etc/monkeysphere/authorized_user_ids/$USER file?  What gets placed
-   in /var/cache/monkeysphere/authorized_keys/$USER?  It looks
-   currently untouched, which could mean bad things for such a user.
-   - if authorized_user_ids is empty, then the user's authorized_keys
-     file will be also, unless the user-controlled authorized_keys file
-     is added.  I believe this is expected, correct behavior.
-
 Consider the default permissions for
-   /var/cache/monkeysphere/authorized_keys/* (and indeed the whole
+   /var/lib/monkeysphere/authorized_keys/* (and indeed the whole
    directory path leading up to that)
 
-As an administrator, how do i reverse the effect of a
-   "monkeysphere-server trust-keys" that i later decide i should not
-   have run?
-
 Make sure alternate ports are handled for known_hosts.
 
 Script to import private key into ssh agent.
@@ -105,20 +90,20 @@ When using ssh-proxycommand, if only host keys found are expired or
 Update monkeysphere-ssh-proxycommand man page with new keyserver
    checking policy info.
 
-Update monkeysphere-ssh-proxycommand man page with info about
-   no-connect option.
-
 File bug against seahorse about how, when creating new primary keys,
    it presents option for "RSA (sign only)" but then creates an "esca"
    key.
 
 File bug against enigmail about lack of ability to create subkeys.
 
-Priviledge separation: monkeysphere user to handle authn keyring and
+Privilege separation: monkeysphere user to handle authn keyring and
    generate authorized_keys file (which would be moved into place by
    root).  Host keyring would be owned by root.
 
-Check permissions of authorized_user_ids file to be writable only by
-   user and root (same as authorized_keys)
+Test and document what happens when any filesystem that the
+   monkeysphere-server relies on and modifies (/tmp, /etc, and /var?)
+   fills up.
 
-Improve function that sets owner trust for keys in server keychain.
+Optimize keyserver access, particularly on monkeysphere-server
+   update-users -- is there a way to query the keyserver all in a
+   chunk?
index aefbf7fe7c87da22a9fb057862b6681f2affd025..e49a053f5820972173c25bc5431f49e3a3886a20 100644 (file)
@@ -6,7 +6,14 @@
 *  Please add new entries in reverse chronological order whenever you make   *
 *  changes to this system                                                   *
 ******************************************************************************
-
+2008-06-23 - dkg
+       * added monkeysphere apt repository to /etc/apt/sources.list
+       * added dkg's key to apt's list of trusted keys.
+       * ran aptitude dist-upgrade
+       * upgraded to monkeysphere 0.2-1
+       * moved authorized_user_ids files into users' home directories.
+       * installed lockfile-progs
+       
 2008-06-22 - dkg
        * installed screen (mjgoins and i were collaborating)
        
index 847e8795ea4c53f0825a4f64262c761c5f364218..defb0f7e9b07c6248fe736fa121cfc10d08403d0 100644 (file)
@@ -3,20 +3,9 @@
 # This is an sh-style shell configuration file.  Variable names should
 # be separated from their assignements by a single '=' and no spaces.
 
-# GPG home directory for server
-#GNUPGHOME=/etc/monkeysphere/gnupg
-
 # GPG keyserver to search for keys
 #KEYSERVER=subkeys.pgp.net
 
-# Required user key capabilities
-# Must be quoted, lowercase, space-seperated list of the following:
-#   e = encrypt
-#   s = sign
-#   c = certify
-#   a = authentication
-#REQUIRED_USER_KEY_CAPABILITY="a"
-
 # Path to authorized_user_ids file to process to create
 # authorized_keys file.  '%h' will be replaced by the home directory
 # of the user, and %u will be replaced by the username of the user.
@@ -26,6 +15,8 @@
 
 # Whether to add user controlled authorized_keys file to
 # monkeysphere-generated authorized_keys file.  Should be path to file
-# where '%h' will be replaced by the home directory of the user.
-# To not add any user-controlled file, put "-"
-#USER_CONTROLLED_AUTHORIZED_KEYS="%h/.ssh/authorized_keys"
+# where '%h' will be replaced by the home directory of the user or
+# '%u' by the username.  To not add any user-controlled file, put "-"
+# FIXME: this usage of "-" contravenes the normal convention where "-"
+# means standard in/out.  Why not use "none" or "" instead?
+#RAW_AUTHORIZED_KEYS="%h/.ssh/authorized_keys"
index f2ba4a78c12c6b0e8377ac4d27da1d9e51d3ab4b..aa3a6640bd129eb893fc0aa8c17a8aa77741e430 100644 (file)
@@ -9,14 +9,13 @@
 # GPG keyserver to search for keys
 #KEYSERVER=subkeys.pgp.net
 
-# Required key capabilities
-# Must be quoted, lowercase, space-seperated list of the following:
-#   e = encrypt
-#   s = sign
-#   c = certify
-#   a = authentication
-#REQUIRED_HOST_KEY_CAPABILITY="a"
-#REQUIRED_USER_KEY_CAPABILITY="a"
+# Set whether or not to check keyservers at every monkeysphere
+# interaction, including all ssh connections if you use the
+# monkeysphere-ssh-proxycommand.
+# NOTE: setting CHECK_KEYSERVER to true will leak information about
+# the timing and frequency of your ssh connections to the maintainer
+# of the keyserver.
+#CHECK_KEYSERVER=true
 
 # ssh known_hosts file
 #KNOWN_HOSTS=~/.ssh/known_hosts
@@ -25,9 +24,5 @@
 # Should be "true" or "false"
 #HASH_KNOWN_HOSTS=true
 
-# ssh authorized_keys file
-#AUTHORIZED_KEYS=~/.ssh/known_hosts
-
-# This overrides other environment variables
-# NOTE: there is leakage
-#CHECK_KEYRING=true
+# ssh authorized_keys file (FIXME: why is this relevant in this file?)
+#AUTHORIZED_KEYS=~/.ssh/authorized_keys
index bea1da50c4e1737fc30a7ba0ebee1aa8b163347f..6141ec52113a585427b70fbe337616bf28f23ea3 100644 (file)
@@ -19,11 +19,14 @@ SSH-style key on standard output.
 .Pp
 If the data on standard input contains no subkeys, you can invoke
 .Nm
-without arguments.  If the data on standard input contains
-multiple keys (e.g. a primary key and associated subkeys), you must
-specify a specific OpenPGP keyid (e.g. CCD2ED94D21739E9) or
-fingerprint as the first argument to indicate which key to export.
-The keyid must be exactly 16 hex characters.
+without arguments.  If the data on standard input contains multiple
+keys (e.g. a primary key and associated subkeys), you must specify a
+specific OpenPGP key identifier as the first argument to indicate
+which key to export.  The key ID is normally the 40 hex digit OpenPGP
+fingerprint of the key or subkey desired, but
+.Nm
+will accept as few as the last 8 digits of the fingerprint as a key
+ID.
 .Pp
 If the input contains an OpenPGP RSA or DSA public key, it will be
 converted to the OpenSSH-style single-line keystring, prefixed with
@@ -78,8 +81,9 @@ Secret key output is currently not passphrase-protected.
 .Nm
 currently cannot handle passphrase-protected secret keys on input.
 .Pp
-It would be nice to be able to use keyids shorter or longer than 16
-hex characters.
+Key identifiers consisting of an odd number of hex digits are not
+accepted.  Users who use a key ID with a standard length of 8, 16, or
+40 hex digits should not be affected by this.
 .Pp
 .Nm
 only acts on keys associated with the first primary key
index e821e63be1b85c7a92a94ca0a848dac772d17866..9bb7b2d51e8547f36e18df8a5df7b86a3e1e42cb 100644 (file)
@@ -28,8 +28,8 @@ file are processed, and the user's authorized_keys file in
 /var/cache/monkeysphere/authorized_keys/USER.  See `man monkeysphere'
 for more info.  If the USER_CONTROLLED_AUTHORIZED_KEYS variable is
 set, then a user-controlled authorized_keys file (usually
-~USER/.ssh/authorized_keys) is added to the authorized_keys file.  `k'
-may be used in place of `update-known_hosts'.
+~USER/.ssh/authorized_keys) is added to the authorized_keys file.  `u'
+may be used in place of `update-users.
 .TP
 .B gen-key
 Generate a gpg key for the host.  `g' may be used in place of
@@ -63,12 +63,12 @@ that is done, publish the key to a keyserver with "publish-key"
 subcommand.  Finally, you need to modify the sshd_config to tell sshd
 where the new server host key:
 
-HostKey /etc/monkeysphere/ssh_host_rsa_key
+HostKey /var/lib/monkeysphere/ssh_host_rsa_key
 
 If the server will also handle user authentication through
 monkeysphere-generated authorized_keys files, set the following:
 
-AuthorizedKeysFile /var/cache/monkeysphere/authorized_keys/%u
+AuthorizedKeysFile /var/lib/monkeysphere/authorized_keys/%u
 
 Once those changes are made, restart the ssh server.
 
@@ -81,17 +81,18 @@ System monkeysphere-server config file.
 /etc/monkeysphere/monkeysphere.conf
 System-wide monkeysphere config file.
 .TP
-/etc/monkeysphere/gnupg
-Monkeysphere GNUPG home directory.
+/var/lib/monkeysphere/authorized_keys/USER
+Monkeysphere-generated user authorized_keys files.
 .TP
-/etc/monkeysphere/ssh_host_rsa_key
-Copy of the host's private key in ssh format, suitable for use by sshd.
+/var/lib/monkeysphere/ssh_host_rsa_key
+Copy of the host's private key in ssh format, suitable for use by
+sshd.
 .TP
-/etc/monkeysphere/authorized_user_ids/USER
-Server maintained authorized_user_ids files for users.
+/var/lib/monkeysphere/gnupg-host
+Monkeysphere host GNUPG home directory.
 .TP
-/var/cache/monkeysphere/authorized_keys/USER
-User authorized_keys file.
+/var/lib/monkeysphere/gnupg-authentication
+Monkeysphere authentication GNUPG home directory.
 
 .SH AUTHOR
 
index 4021263681b3fd3a0d752bc01bab9121538570f8..ead3736d7241ae1709dceff82494fc66b17e6dfb 100644 (file)
 # managed directories
 ETC="/etc/monkeysphere"
 export ETC
-CACHE="/var/cache/monkeysphere"
-export CACHE
-ERR=0
-export ERR
 
 ########################################################################
 ### UTILITY FUNCTIONS
@@ -111,15 +107,13 @@ translate_ssh_variables() {
     echo "$path"
 }
 
-### CONVERTION UTILITIES
+### CONVERSION UTILITIES
 
 # output the ssh key for a given key ID
 gpg2ssh() {
     local keyID
     
-    #keyID="$1" #TMP
-    # only use last 16 characters until openpgp2ssh can take all 40 #TMP
-    keyID=$(echo "$1" | cut -c 25-) #TMP
+    keyID="$1"
 
     gpg --export "$keyID" | openpgp2ssh "$keyID" 2> /dev/null
 }
@@ -265,7 +259,7 @@ process_user_id() {
     fi
     requiredPubCapability=$(echo "$requiredCapability" | tr "[:lower:]" "[:upper:]")
 
-    # if CHECK_KEYSERVER variable set, check the keyserver
+    # if CHECK_KEYSERVER variable set to true, check the keyserver
     # for the user ID
     if [ "$CHECK_KEYSERVER" = "true" ] ; then
        gpg_fetch_userid "$userID"
@@ -344,9 +338,9 @@ process_user_id() {
                # 0 = ok, 1 = bad
                if [ "$keyOK" -a "$uidOK" -a "$lastKeyOK" ] ; then
                    log "  * acceptable key found."
-                   echo 0 "$fingerprint"
+                   echo "0:${fingerprint}"
                else
-                   echo 1 "$fingerprint"
+                   echo "1:${fingerprint}"
                fi
                ;;
            'sub') # sub keys
@@ -379,116 +373,199 @@ process_user_id() {
                # 0 = ok, 1 = bad
                if [ "$keyOK" -a "$uidOK" -a "$lastKeyOK" ] ; then
                    log "  * acceptable key found."
-                   echo 0 "$fingerprint"
+                   echo "0:${fingerprint}"
                else
-                   echo 1 "$fingerprint"
+                   echo "1:${fingerprint}"
                fi
                ;;
        esac
     done
 }
 
-# process hosts in the known_host file
-process_hosts_known_hosts() {
+# process a single host in the known_host file
+process_host_known_hosts() {
     local host
     local userID
     local ok
     local keyid
     local tmpfile
+    local returnCode
+
+    # default return code is 1, which assumes no key was found
+    returnCode=1
+
+    host="$1"
+
+    log "processing host: $host"
+
+    userID="ssh://${host}"
+
+    for line in $(process_user_id "ssh://${host}") ; do
+       ok=$(echo "$line" | cut -d: -f1)
+       keyid=$(echo "$line" | cut -d: -f2)
+
+       sshKey=$(gpg2ssh "$keyid")
+       # remove the old host key line
+       remove_line "$KNOWN_HOSTS" "$sshKey"
+       # if key OK, add new host line
+       if [ "$ok" -eq '0' ] ; then
+           # hash if specified
+           if [ "$HASH_KNOWN_HOSTS" = 'true' ] ; then
+               # FIXME: this is really hackish cause ssh-keygen won't
+               # hash from stdin to stdout
+               tmpfile=$(mktemp)
+               ssh2known_hosts "$host" "$sshKey" > "$tmpfile"
+               ssh-keygen -H -f "$tmpfile" 2> /dev/null
+               cat "$tmpfile" >> "$KNOWN_HOSTS"
+               rm -f "$tmpfile" "${tmpfile}.old"
+           else
+               ssh2known_hosts "$host" "$sshKey" >> "$KNOWN_HOSTS"
+           fi
+           # set return code to be 0, since a key was found
+           returnCode=0
+       fi
+       return "$returnCode"
+    done
+
+    return "$returnCode"
+}
+
+# update the known_hosts file for a set of hosts listed on command
+# line
+update_known_hosts() {
+    local host
+    local returnCode
+
+    # default return code is 0, which assumes a key was found for
+    # every host.  code will be set to 1 if a key is not found for at
+    # least one host
+    returnCode=0
+
+    # set the trap to remove any lockfiles on exit
+    trap "lockfile-remove $KNOWN_HOSTS" EXIT
 
     # create a lockfile on known_hosts
     lockfile-create "$KNOWN_HOSTS"
 
     for host ; do
-       log "processing host: $host"
-
-       userID="ssh://${host}"
-
-       process_user_id "ssh://${host}" | \
-       while read -r ok keyid ; do
-           sshKey=$(gpg2ssh "$keyid")
-           # remove the old host key line
-           remove_line "$KNOWN_HOSTS" "$sshKey"
-           # if key OK, add new host line
-           if [ "$ok" -eq '0' ] ; then
-               # hash if specified
-               if [ "$HASH_KNOWN_HOSTS" = 'true' ] ; then
-                   # FIXME: this is really hackish cause ssh-keygen won't
-                   # hash from stdin to stdout
-                   tmpfile=$(mktemp)
-                   ssh2known_hosts "$host" "$sshKey" > "$tmpfile"
-                   ssh-keygen -H -f "$tmpfile" 2> /dev/null
-                   cat "$tmpfile" >> "$KNOWN_HOSTS"
-                   rm -f "$tmpfile" "${tmpfile}.old"
-               else
-                   ssh2known_hosts "$host" "$sshKey" >> "$KNOWN_HOSTS"
-               fi
-           fi
-       done
+       # process the host, change return code if host key not found
+       process_host_known_hosts "$host" || returnCode=1
+       
        # touch the lockfile, for good measure.
        lockfile-touch --oneshot "$KNOWN_HOSTS"
     done
 
     # remove the lockfile
     lockfile-remove "$KNOWN_HOSTS"
+
+    return "$returnCode"
+}
+
+# process known_hosts file, going through line-by-line, extract each
+# host, and process with the host processing function
+process_known_hosts() {
+    local returnCode
+
+    # default return code is 0, which assumes a key was found for
+    # every host.  code will be set to 1 if a key is not found for at
+    # least one host
+    returnCode=0
+
+    # take all the hosts from the known_hosts file (first field), grep
+    # out all the hashed hosts (lines starting with '|')...
+    for line in $(cat "$KNOWN_HOSTS" | meat | cut -d ' ' -f 1 | grep -v '^|.*$') ; do
+       # break up hosts into separate words
+       update_known_hosts $(echo "$line" | tr , ' ') || returnCode=1
+    done
+
+    return "$returnCode"
 }
 
 # process uids for the authorized_keys file
-process_uids_authorized_keys() {
+process_uid_authorized_keys() {
     local userID
     local ok
     local keyid
+    local returnCode
+
+    # default return code is 1, which assumes no key was found
+    returnCode=1
+
+    userID="$1"
+
+    log "processing user ID: $userID"
+
+    for line in $(process_user_id "$userID") ; do
+       ok=$(echo "$line" | cut -d: -f1)
+       keyid=$(echo "$line" | cut -d: -f2)
+
+       sshKey=$(gpg2ssh "$keyid")
+       # remove the old host key line
+       remove_line "$AUTHORIZED_KEYS" "$sshKey"
+       # if key OK, add new host line
+       if [ "$ok" -eq '0' ] ; then
+           ssh2authorized_keys "$userID" "$sshKey" >> "$AUTHORIZED_KEYS"
+
+           # set return code to be 0, since a key was found
+           returnCode=0
+       fi
+    done
+
+    return "$returnCode"
+}
+
+# update the authorized_keys files from a list of user IDs on command
+# line
+update_authorized_keys() {
+    local userID
+    local returnCode
+
+    # default return code is 0, which assumes a key was found for
+    # every user ID.  code will be set to 1 if a key is not found for
+    # at least one user ID
+    returnCode=0
+
+    # set the trap to remove any lockfiles on exit
+    trap "lockfile-remove $AUTHORIZED_KEYS" EXIT
 
     # create a lockfile on authorized_keys
     lockfile-create "$AUTHORIZED_KEYS"
 
     for userID ; do
-       log "processing user ID: $userID"
-
-       process_user_id "$userID" | \
-       while read -r ok keyid ; do
-           sshKey=$(gpg2ssh "$keyid")
-           # remove the old host key line
-           remove_line "$AUTHORIZED_KEYS" "$sshKey"
-           # if key OK, add new host line
-           if [ "$ok" -eq '0' ] ; then
-               ssh2authorized_keys "$userID" "$sshKey" >> "$AUTHORIZED_KEYS"
-           fi
-       done
+       # process the user ID, change return code if key not found for
+       # user ID
+       process_uid_authorized_keys "$userID" || returnCode=1
+
        # touch the lockfile, for good measure.
        lockfile-touch --oneshot "$AUTHORIZED_KEYS"
     done
 
     # remove the lockfile
     lockfile-remove "$AUTHORIZED_KEYS"
-}
 
-# process known_hosts file
-# go through line-by-line, extract each host, and process with the
-# host processing function
-process_known_hosts() {
-    local hosts
-    local host
-
-    # take all the hosts from the known_hosts file (first field),
-    # grep out all the hashed hosts (lines starting with '|')...
-    cat "$KNOWN_HOSTS" | meat | \
-       cut -d ' ' -f 1 | grep -v '^|.*$' | \
-    while IFS=, read -r -a hosts ; do
-       process_hosts_known_hosts ${hosts[@]}
-    done
+    return "$returnCode"
 }
 
 # process an authorized_user_ids file for authorized_keys
 process_authorized_user_ids() {
     local userid
+    local returnCode
+
+    # default return code is 0, and is set to 1 if a key for a user ID
+    # is not found
+    returnCode=0
 
     authorizedUserIDs="$1"
 
-    cat "$authorizedUserIDs" | meat | \
-    while read -r userid ; do
-       process_uids_authorized_keys "$userid"
+    # set the IFS to be newline for parsing the authorized_user_ids
+    # file.  can't find it in BASH(1) (found it on the net), but it
+    # works.
+    IFS=$'\n'
+    for userid in $(cat "$authorizedUserIDs" | meat) ; do
+       update_authorized_keys "$userid" || returnCode=1
     done
+
+    return "$returnCode"
 }
 
 # EXPERIMENTAL (unused) process userids found in authorized_keys file
@@ -498,6 +575,11 @@ process_authorized_user_ids() {
 process_authorized_keys() {
     local authorizedKeys
     local userID
+    local returnCode
+
+    # default return code is 0, and is set to 1 if a key for a user
+    # is not found
+    returnCode=0
 
     authorizedKeys="$1"
 
@@ -522,8 +604,10 @@ process_authorized_keys() {
 
        # process the userid
        log "processing userid: '$userID'"
-       process_user_id "$userID" > /dev/null
+       process_user_id "$userID" > /dev/null || returnCode=1
     done
+
+    return "$returnCode"
 }
 
 ##################################################
index 5b4c46af187a2c662fb8ea97f66a54355cd1a5c2..7c4348dc0e8dd58048094ea475dc90cc82867634 100644 (file)
@@ -44,11 +44,11 @@ void init_keyid(gnutls_openpgp_keyid_t keyid) {
 void make_keyid_printable(printable_keyid out, gnutls_openpgp_keyid_t keyid)
 {
   assert(sizeof(out) >= 2*sizeof(keyid));
-  hex_print_data((char*)out, (const char*)keyid, sizeof(keyid));
+  hex_print_data((char*)out, (const unsigned char*)keyid, sizeof(keyid));
 }
 
 /* you must have twice as many bytes in the out buffer as in the in buffer */
-void hex_print_data(char* out, const char* in, size_t incount)
+void hex_print_data(char* out, const unsigned char* in, size_t incount)
 {
   static const char hex[16] = "0123456789ABCDEF";
   unsigned int inix = 0, outix = 0;
@@ -73,7 +73,6 @@ unsigned char hex2bin(unsigned char x) {
 
 void collapse_printable_keyid(gnutls_openpgp_keyid_t out, printable_keyid in) {
   unsigned int pkix = 0, outkix = 0;
-  
   while (pkix < sizeof(printable_keyid)) {
     unsigned hi = hex2bin(in[pkix]);
     unsigned lo = hex2bin(in[pkix + 1]);
@@ -92,6 +91,27 @@ void collapse_printable_keyid(gnutls_openpgp_keyid_t out, printable_keyid in) {
   }
 }
 
+unsigned int hexstring2bin(unsigned char* out, const char* in) {
+  unsigned int pkix = 0, outkix = 0;
+  int hi = 0; /* which nybble is it? */
+  
+  while (in[pkix]) {
+    unsigned char z = hex2bin(in[pkix]);
+    if (z != 0xff) {
+      if (!hi) {
+       if (out) out[outkix] = (z << 4);
+       hi = 1;
+      } else {
+       if (out) out[outkix] |= z;
+       hi = 0;
+       outkix++;
+      }
+      pkix++;
+    }      
+  }
+  return outkix*8 + (hi ? 4 : 0);
+}
+
 int convert_string_to_keyid(gnutls_openpgp_keyid_t out, const char* str) {
   printable_keyid p;
   int ret;
index f196456c58cf58f3453975c56d5bba75d6216fe1..bf54af0f93ec1a3f75951a715d1c1874b3dfb5e2 100644 (file)
@@ -49,7 +49,18 @@ int convert_string_to_keyid(gnutls_openpgp_keyid_t out, const char* str);
 int convert_string_to_printable_keyid(printable_keyid out, const char* str);
 
 /* you must have twice as many bytes in the out buffer as in the in buffer */
-void hex_print_data(char* out, const char* in, size_t incount);
+void hex_print_data(char* out, const unsigned char* in, size_t incount);
+
+/* expects a null-terminated string as in, containing an even number
+   of hexadecimal characters.
+
+   returns length in *bits* of raw data as output. 
+
+   the out buffer must be at least half as long as in to hold the
+   output.  if out is NULL, no output will be generated, but the
+   length will still be returned.
+*/
+unsigned int hexstring2bin(unsigned char* out, const char* in);
 
 /* functions to get data into datum objects: */
 
index 92bdc1955c81e0cada4eb80a5177017f5b226575..5cc6cfa087e967e8e8afe49af2839073570fade6 100644 (file)
 
 
 /* FIXME: keyid should be const as well */
-int convert_private_pgp_to_x509(gnutls_x509_privkey_t* output, const gnutls_openpgp_privkey_t* pgp_privkey, gnutls_openpgp_keyid_t* keyid) {
+int convert_private_pgp_to_x509(gnutls_x509_privkey_t* output, const gnutls_openpgp_privkey_t* pgp_privkey, const unsigned char* keyfpr, unsigned int fprlen) {
   gnutls_datum_t m, e, d, p, q, u, g, y, x;
   gnutls_pk_algorithm_t pgp_algo;
   unsigned int pgp_bits;
   int ret;
-  gnutls_openpgp_keyid_t curkeyid;
   int subkeyidx;
   int subkeycount;
   int found = 0;
+  unsigned char fingerprint[20];
+  size_t fingerprint_length = sizeof(fingerprint); 
 
   init_datum(&m);
   init_datum(&e);
@@ -61,20 +62,27 @@ int convert_private_pgp_to_x509(gnutls_x509_privkey_t* output, const gnutls_open
     return 1;
   }
 
-  if ((keyid == NULL) && 
+  if ((keyfpr == NULL) && 
       (subkeycount > 0)) {
-    err(0,"No keyid passed in, but there were %d keys to choose from\n", subkeycount + 1);
+    err(0,"No key identifier passed in, but there were %d keys to choose from\n", subkeycount + 1);
     return 1;
   }
 
-  if (keyid != NULL) {
-    ret = gnutls_openpgp_privkey_get_key_id(*pgp_privkey, curkeyid);
+  if (keyfpr != NULL) {
+    ret = gnutls_openpgp_privkey_get_fingerprint(*pgp_privkey, fingerprint, &fingerprint_length);
     if (ret) {
-      err(0,"Could not get keyid (error: %d)\n", ret);
+      err(0,"Could not get fingerprint (error: %d)\n", ret);
       return 1;
     }
+    if (fprlen > fingerprint_length) {
+      err(0, "Requested key identifier is longer than computed fingerprint\n");
+      return 1;
+    }
+    if (fingerprint_length > fprlen) {
+      err(0, "Only comparing last %d bits of key fingerprint\n", fprlen*8);
+    }
   }
-  if ((keyid == NULL) || (memcmp(*keyid, curkeyid, sizeof(gnutls_openpgp_keyid_t)) == 0)) {
+  if ((keyfpr == NULL) || (memcmp(fingerprint + (fingerprint_length - fprlen), keyfpr, fprlen) == 0)) {
     /* we want to export the primary key: */
     err(0,"exporting primary key\n");
 
@@ -106,12 +114,19 @@ int convert_private_pgp_to_x509(gnutls_x509_privkey_t* output, const gnutls_open
   } else {
     /* lets trawl through the subkeys until we find the one we want: */
     for (subkeyidx = 0; (subkeyidx < subkeycount) && !found; subkeyidx++) {
-      ret = gnutls_openpgp_privkey_get_subkey_id(*pgp_privkey, subkeyidx, curkeyid);
+      ret = gnutls_openpgp_privkey_get_subkey_fingerprint(*pgp_privkey, subkeyidx, fingerprint, &fingerprint_length);
       if (ret) {
-       err(0,"Could not get keyid of subkey with index %d (error: %d)\n", subkeyidx, ret);
+       err(0,"Could not get fingerprint of subkey with index %d (error: %d)\n", subkeyidx, ret);
        return 1;
       }
-      if (memcmp(*keyid, curkeyid, sizeof(gnutls_openpgp_keyid_t)) == 0) {
+      if (fprlen > fingerprint_length) {
+       err(0, "Requested key identifier is longer than computed fingerprint\n");
+       return 1;
+      }
+      if (fingerprint_length > fprlen) {
+       err(1, "Only comparing last %d bits of key fingerprint\n", fprlen*8);
+      }
+      if (memcmp(fingerprint + (fingerprint_length - fprlen), keyfpr, fprlen) == 0) {
        err(0,"exporting subkey index %d\n", subkeyidx);
 
        /* FIXME: this is almost identical to the block above for the
@@ -172,8 +187,7 @@ int convert_private_pgp_to_x509(gnutls_x509_privkey_t* output, const gnutls_open
 }
 
 /* FIXME: keyid should be const also */
-int emit_public_openssh_from_pgp(const gnutls_openpgp_crt_t* pgp_crt, gnutls_openpgp_keyid_t* keyid) {
-  gnutls_openpgp_keyid_t curkeyid;
+int emit_public_openssh_from_pgp(const gnutls_openpgp_crt_t* pgp_crt, const unsigned char* keyfpr, size_t fprlen) {
   int ret;
   int subkeyidx;
   int subkeycount;
@@ -188,6 +202,9 @@ int emit_public_openssh_from_pgp(const gnutls_openpgp_crt_t* pgp_crt, gnutls_ope
      algorithm name: */
   char output_data[20];
 
+  unsigned char fingerprint[20];
+  size_t fingerprint_length = sizeof(fingerprint); 
+
   /* variables for the output conversion: */
   int pipestatus;
   int pipefd, child_pid;
@@ -208,20 +225,27 @@ int emit_public_openssh_from_pgp(const gnutls_openpgp_crt_t* pgp_crt, gnutls_ope
     return 1;
   }
 
-  if ((keyid == NULL) && 
+  if ((keyfpr == NULL) && 
       (subkeycount > 0)) {
-    err(0,"No keyid passed in, but there were %d keys to choose from\n", subkeycount + 1);
+    err(0,"No key identifier passed in, but there were %d keys to choose from\n", subkeycount + 1);
     return 1;
   }
 
-  if (keyid != NULL) {
-    ret = gnutls_openpgp_crt_get_key_id(*pgp_crt, curkeyid);
+  if (keyfpr != NULL) {
+    ret = gnutls_openpgp_crt_get_fingerprint(*pgp_crt, fingerprint, &fingerprint_length);
     if (ret) {
-      err(0,"Could not get keyid (error: %d)\n", ret);
+      err(0,"Could not get key fingerprint (error: %d)\n", ret);
       return 1;
     }
+    if (fprlen > fingerprint_length) {
+      err(0, "Requested key identifier is longer than computed fingerprint\n");
+      return 1;
+    }
+    if (fingerprint_length > fprlen) {
+      err(0, "Only comparing last %d bits of key fingerprint\n", fprlen*8);
+    }
   }
-  if ((keyid == NULL) || (memcmp(*keyid, curkeyid, sizeof(gnutls_openpgp_keyid_t)) == 0)) {
+  if ((keyfpr == NULL) || (memcmp(fingerprint + (fingerprint_length - fprlen), keyfpr, fprlen) == 0)) {
     /* we want to export the primary key: */
     err(0,"exporting primary key\n");
 
@@ -252,12 +276,19 @@ int emit_public_openssh_from_pgp(const gnutls_openpgp_crt_t* pgp_crt, gnutls_ope
   } else {
     /* lets trawl through the subkeys until we find the one we want: */
     for (subkeyidx = 0; (subkeyidx < subkeycount) && !found; subkeyidx++) {
-      ret = gnutls_openpgp_crt_get_subkey_id(*pgp_crt, subkeyidx, curkeyid);
+      ret = gnutls_openpgp_crt_get_subkey_fingerprint(*pgp_crt, subkeyidx, fingerprint, &fingerprint_length);
       if (ret) {
-       err(0,"Could not get keyid of subkey with index %d (error: %d)\n", subkeyidx, ret);
+       err(0,"Could not get fingerprint of subkey with index %d (error: %d)\n", subkeyidx, ret);
        return 1;
       }
-      if (memcmp(*keyid, curkeyid, sizeof(gnutls_openpgp_keyid_t)) == 0) {
+      if (fprlen > fingerprint_length) {
+       err(0, "Requested key identifier is longer than computed fingerprint\n");
+       return 1;
+      }
+      if (fingerprint_length > fprlen) {
+       err(1, "Only comparing last %d bits of key fingerprint\n", fprlen*8);
+      }
+      if (memcmp(fingerprint + (fingerprint_length - fprlen), keyfpr, fprlen) == 0) {
        err(0,"exporting subkey index %d\n", subkeyidx);
 
        /* FIXME: this is almost identical to the block above for the
@@ -351,7 +382,7 @@ int emit_public_openssh_from_pgp(const gnutls_openpgp_crt_t* pgp_crt, gnutls_ope
 
 int main(int argc, char* argv[]) {
   gnutls_datum_t data;
-  int ret;
+  int ret = 0;
   gnutls_x509_privkey_t x509_privkey;
   gnutls_openpgp_privkey_t pgp_privkey;
   gnutls_openpgp_crt_t pgp_crt;
@@ -359,18 +390,54 @@ int main(int argc, char* argv[]) {
   char output_data[10240];
   size_t ods = sizeof(output_data);
   
-  gnutls_openpgp_keyid_t keyid;
-  gnutls_openpgp_keyid_t* use_keyid;
+  unsigned char * fingerprint = NULL;
+  size_t fpr_size;
+  char * prettyfpr = NULL;
 
   init_gnutls();
 
-  /* figure out what keyid we should be looking for: */
-  use_keyid = NULL;
+  /* figure out what key we should be looking for: */
   if (argv[1] != NULL) {
-    ret = convert_string_to_keyid(keyid, argv[1]);
-    if (ret != 0)
-      return ret;
-    use_keyid = &keyid;
+    if (strlen(argv[1]) > 81) {
+      /* safety check to avoid some sort of wacky overflow situation:
+        there's no reason that the key id should be longer than twice
+        a sane fingerprint (one byte between chars, and then another
+        two at the beginning and end) */
+      err(0, "Key identifier is way too long.  Please use at most 40 hex digits.\n");
+      return 1;
+    }
+
+    fpr_size = hexstring2bin(NULL, argv[1]);
+    if (fpr_size > 40*4) {
+      err(0, "Key identifier is longer than 40 hex digits\n");
+      return 1;
+    }
+    /* since fpr_size is initially in bits: */
+    if (fpr_size % 8 != 0) {
+      err(0, "Please provide an even number of hex digits for the key identifier\n");
+      return 1;
+    }
+    fpr_size /= 8;
+
+    fingerprint = malloc(sizeof(unsigned char) * fpr_size);
+    bzero(fingerprint, sizeof(unsigned char) * fpr_size);
+    hexstring2bin(fingerprint, argv[1]);
+
+    prettyfpr = malloc(sizeof(unsigned char)*fpr_size*2 + 1);
+    if (prettyfpr != NULL) {
+      hex_print_data(prettyfpr, fingerprint, fpr_size);
+      prettyfpr[sizeof(unsigned char)*fpr_size*2] = '\0';
+      err(1, "searching for key with fingerprint '%s'\n", prettyfpr);
+      free(prettyfpr);
+    }
+
+    if (fpr_size < 4) {
+      err(0, "You MUST provide at least 8 hex digits in any key identifier\n");
+      return 1;
+    }
+    if (fpr_size < 8)
+      err(0, "You should provide at least 16 hex digits in any key identifier (proceeding with %d digits anyway)\n", fpr_size*2);
+   
   }
 
   
@@ -397,7 +464,7 @@ int main(int argc, char* argv[]) {
       return 1;
     }
     
-    ret = convert_private_pgp_to_x509(&x509_privkey, &pgp_privkey, use_keyid);
+    ret = convert_private_pgp_to_x509(&x509_privkey, &pgp_privkey, fingerprint, fpr_size);
 
     gnutls_openpgp_privkey_deinit(pgp_privkey);
     if (ret)
@@ -423,7 +490,7 @@ int main(int argc, char* argv[]) {
       /* we're dealing with a public key */
       err(0,"Translating public key\n");
 
-      ret = emit_public_openssh_from_pgp(&pgp_crt, use_keyid);
+      ret = emit_public_openssh_from_pgp(&pgp_crt, fingerprint, fpr_size);
       
     } else {
       /* we have no idea what kind of key this is at all anyway! */
@@ -433,5 +500,6 @@ int main(int argc, char* argv[]) {
   }
 
   gnutls_global_deinit();
+  free(fingerprint);
   return 0;
 }
index 9b315e26ae8ee46c7303449390c680f7f5252f7b..d8d4667c9201a6b286527d39aef6ce07916981dc 100755 (executable)
@@ -24,6 +24,9 @@ DATE=$(date -u '+%FT%T')
 # unset some environment variables that could screw things up
 GREP_OPTIONS=
 
+# default return code
+ERR=0
+
 ########################################################################
 # FUNCTIONS
 ########################################################################
@@ -125,15 +128,17 @@ MS_CONF=${MS_CONF:-"${MS_HOME}/monkeysphere.conf"}
 [ -e "$MS_CONF" ] && . "$MS_CONF"
 
 # set empty config variable with defaults
-AUTHORIZED_USER_IDS=${AUTHORIZED_USER_IDS:-"${MS_HOME}/authorized_user_ids"}
 GNUPGHOME=${GNUPGHOME:-"${HOME}/.gnupg"}
 KEYSERVER=${KEYSERVER:-"subkeys.pgp.net"}
 CHECK_KEYSERVER=${CHECK_KEYSERVER:="true"}
-REQUIRED_HOST_KEY_CAPABILITY=${REQUIRED_HOST_KEY_CAPABILITY:-"a"}
-REQUIRED_USER_KEY_CAPABILITY=${REQUIRED_USER_KEY_CAPABILITY:-"a"}
 KNOWN_HOSTS=${KNOWN_HOSTS:-"${HOME}/.ssh/known_hosts"}
-AUTHORIZED_KEYS=${AUTHORIZED_KEYS:-"${HOME}/.ssh/authorized_keys"}
 HASH_KNOWN_HOSTS=${HASH_KNOWN_HOSTS:-"true"}
+AUTHORIZED_KEYS=${AUTHORIZED_KEYS:-"${HOME}/.ssh/authorized_keys"}
+
+# other variables
+AUTHORIZED_USER_IDS=${AUTHORIZED_USER_IDS:-"${MS_HOME}/authorized_user_ids"}
+REQUIRED_HOST_KEY_CAPABILITY=${REQUIRED_HOST_KEY_CAPABILITY:-"a"}
+REQUIRED_USER_KEY_CAPABILITY=${REQUIRED_USER_KEY_CAPABILITY:-"a"}
 
 export GNUPGHOME
 
@@ -143,7 +148,6 @@ mkdir -p -m 0700 "$GNUPGHOME"
 # make sure the user monkeysphere home directory exists
 mkdir -p -m 0700 "$MS_HOME"
 touch "$AUTHORIZED_USER_IDS"
-touch "$AUTHORIZED_KEYS"
 
 case $COMMAND in
     'update-known_hosts'|'update-known-hosts'|'k')
@@ -156,7 +160,7 @@ case $COMMAND in
         # if hosts are specified on the command line, process just
         # those hosts
        if [ "$1" ] ; then
-           process_hosts_known_hosts "$@"
+           update_known_hosts "$@" || ERR=1
 
         # otherwise, if no hosts are specified, process every host
         # in the user's known_hosts file
@@ -165,7 +169,7 @@ case $COMMAND in
                failure "known_hosts file '$KNOWN_HOSTS' is empty."
            fi
            log "processing known_hosts file..."
-           process_known_hosts
+           process_known_hosts || ERR=1
        fi
 
        log "known_hosts file updated."
@@ -181,7 +185,7 @@ case $COMMAND in
 
        # process authorized_user_ids file
        log "processing authorized_user_ids file..."
-       process_authorized_user_ids "$AUTHORIZED_USER_IDS"
+       process_authorized_user_ids "$AUTHORIZED_USER_IDS" || ERR=1
        log "authorized_keys file updated."
        ;;
 
@@ -202,3 +206,5 @@ case $COMMAND in
 Type '$PGRM help' for usage."
         ;;
 esac
+
+exit "$ERR"
index f68f3911fe8255bf8fd8ac07f7716b0d3b01333a..ac7c1cbca3cac6b12e3303338a3cc4b6470f4aff 100755 (executable)
 ########################################################################
 PGRM=$(basename $0)
 
-SHAREDIR=${SHAREDIR:-"/usr/share/monkeysphere"}
-export SHAREDIR
-. "${SHAREDIR}/common"
+SHARE=${SHARE:-"/usr/share/monkeysphere"}
+export SHARE
+. "${SHARE}/common"
+
+VARLIB="/var/lib/monkeysphere"
+export VARLIB
 
 # date in UTF format if needed
 DATE=$(date -u '+%FT%T')
@@ -21,6 +24,9 @@ DATE=$(date -u '+%FT%T')
 # unset some environment variables that could screw things up
 GREP_OPTIONS=
 
+# default return code
+ERR=0
+
 ########################################################################
 # FUNCTIONS
 ########################################################################
@@ -31,7 +37,7 @@ usage: $PGRM <subcommand> [args]
 MonkeySphere server admin tool.
 
 subcommands:
-  update-users (s) [USER]...            update users authorized_keys files
+  update-users (u) [USER]...            update users authorized_keys files
   gen-key (g) [HOSTNAME]                generate gpg key for the server
   show-fingerprint (f)                  show server's host key fingerprint
   publish-key (p)                       publish server's host key to keyserver
@@ -46,8 +52,9 @@ gen_key() {
     local hostName
 
     hostName=${1:-$(hostname --fqdn)}
-    service=${SERVICE:-"ssh"}
-    userID="${service}://${hostName}"
+
+    SERVICE=${SERVICE:-"ssh"}
+    userID="${SERVICE}://${hostName}"
 
     if gpg --list-key ="$userID" > /dev/null 2>&1 ; then
        failure "Key for '$userID' already exists"
@@ -118,8 +125,8 @@ EOF
 
     # write the key to the file
     # NOTE: assumes that the primary key is the proper key to use
-    (umask 077 && gpgsecret2ssh "$keyID" > "${MS_HOME}/ssh_host_rsa_key")
-    log "Private SSH host key output to file: ${MS_HOME}/ssh_host_rsa_key"
+    (umask 077 && gpgsecret2ssh "$keyID" > "${VARLIB}/ssh_host_rsa_key")
+    log "Private SSH host key output to file: ${VARLIB}/ssh_host_rsa_key"
 }
 
 # gpg output key fingerprint
@@ -151,24 +158,26 @@ MS_CONF=${MS_CONF:-"$MS_HOME"/monkeysphere-server.conf}
 [ -e "$MS_CONF" ] && . "$MS_CONF"
 
 # set empty config variable with defaults
-GNUPGHOME=${GNUPGHOME:-"${MS_HOME}/gnupg"}
+MONKEYSPHERE_USER=${MONKEYSPHERE_USER:-"monkeysphere"}
 KEYSERVER=${KEYSERVER:-"subkeys.pgp.net"}
 CHECK_KEYSERVER=${CHECK_KEYSERVER:="true"}
-REQUIRED_USER_KEY_CAPABILITY=${REQUIRED_USER_KEY_CAPABILITY:-"a"}
 AUTHORIZED_USER_IDS=${AUTHORIZED_USER_IDS:-"%h/.config/monkeysphere/authorized_user_ids"}
-USER_CONTROLLED_AUTHORIZED_KEYS=${USER_CONTROLLED_AUTHORIZED_KEYS:-"%h/.ssh/authorized_keys"}
+RAW_AUTHORIZED_KEYS=${RAW_AUTHORIZED_KEYS:-"%h/.ssh/authorized_keys"}
 
-export GNUPGHOME
+# other variables
+REQUIRED_USER_KEY_CAPABILITY=${REQUIRED_USER_KEY_CAPABILITY:-"a"}
+GNUPGHOME_HOST=${GNUPGHOME_HOST:-"${VARLIB}/gnupg-host"}
+GNUPGHOME_AUTHENTICATION=${GNUPGHOME_AUTHENTICATION:-"${VARLIB}/gnupg-authentication"}
 
-# make sure the monkeysphere home directory exists
-mkdir -p "${MS_HOME}/authorized_user_ids"
-# make sure gpg home exists with proper permissions
+# set default GNUPGHOME, and make sure the directory exists.  this is
+# true for all functions expect user authentication
+# (ie. update-users).
+GNUPGHOME="$GNUPGHOME_HOST"
+export GNUPGHOME
 mkdir -p -m 0700 "$GNUPGHOME"
-# make sure the authorized_keys directory exists
-mkdir -p "${CACHE}/authorized_keys"
 
 case $COMMAND in
-    'update-users'|'update-user'|'s')
+    'update-users'|'update-user'|'u')
        if [ "$1" ] ; then
            # get users from command line
            unames="$@"
@@ -177,22 +186,32 @@ case $COMMAND in
            unames=$(getent passwd | cut -d: -f1)
        fi
 
+       # set mode
+       MODE="authorized_keys"
+
+        # make sure the authorized_keys directory exists
+       mkdir -p "${VARLIB}/authorized_keys"
+
+       # set GNUPGHOME, and make sure the directory exists
+       GNUPGHOME="$GNUPGHOME_AUTHENTICATION"
+       export GNUPGHOME
+       mkdir -p -m 0700 "$GNUPGHOME"
+
        # loop over users
        for uname in $unames ; do
-           MODE="authorized_keys"
-
            # check all specified users exist
            if ! getent passwd "$uname" >/dev/null ; then
                error "----- unknown user '$uname' -----"
                continue
            fi
 
-           # set authorized_user_ids variable,
-           # translate ssh-style path variables
+           # set authorized_user_ids and raw authorized_keys variables,
+           # translating ssh-style path variables
            authorizedUserIDs=$(translate_ssh_variables "$uname" "$AUTHORIZED_USER_IDS")
+           rawAuthorizedKeys=$(translate_ssh_variables "$uname" "$RAW_AUTHORIZED_KEYS")
 
-           # skip user if authorized_user_ids file does not exist
-           if [ ! -f "$authorizedUserIDs" ] ; then
+           # if neither is found, skip user
+           if [ ! -s "$authorizedUserIDs" -a ! -s "$rawAuthorizedKeys" ] ; then
                continue
            fi
 
@@ -201,30 +220,42 @@ case $COMMAND in
            # temporary authorized_keys file
            AUTHORIZED_KEYS=$(mktemp)
 
-           # skip if the user's authorized_user_ids file is empty
-           if [ ! -s "$authorizedUserIDs" ] ; then
-               log "authorized_user_ids file '$authorizedUserIDs' is empty."
-               continue
-           fi
+           # trap to delete file on exit
+           trap "rm -f $AUTHORIZE_KEYS" EXIT
 
            # process authorized_user_ids file
-           log "processing authorized_user_ids file..."
-           process_authorized_user_ids "$authorizedUserIDs"
+           if [ -s "$authorizedUserIDs" ] ; then
+               log "processing authorized_user_ids file..."
+               process_authorized_user_ids "$authorizedUserIDs"
+           fi
 
            # add user-controlled authorized_keys file path if specified
-           if [ "$USER_CONTROLLED_AUTHORIZED_KEYS" != '-' ] ; then
-               userAuthorizedKeys=$(translate_ssh_variables "$uname" "$USER_CONTROLLED_AUTHORIZED_KEYS")
-               if [ -f "$userAuthorizedKeys" ] ; then
-                   log -n "adding user's authorized_keys file... "
-                   cat "$userAuthorizedKeys" >> "$AUTHORIZED_KEYS"
+           if [ "$RAW_AUTHORIZED_KEYS" != '-' ] ; then
+               if [ -s "$rawAuthorizedKeys" ] ; then
+                   log -n "adding raw authorized_keys file... "
+                   cat "$rawAuthorizedKeys" >> "$AUTHORIZED_KEYS"
                    loge "done."
                fi
            fi
 
-           # move the temp authorized_keys file into place
-           mv -f "$AUTHORIZED_KEYS" "${CACHE}/authorized_keys/${uname}"
+           # if the resulting authorized_keys file is not empty, move
+           # the temp authorized_keys file into place
+           if [ -s "$AUTHORIZED_KEYS" ] ; then
+               # openssh appears to check the contents of the
+                # authorized_keys file as the user in question, so the
+                # file must be readable by that user at least.
+               # FIXME: is there a better way to do this?
+               chgrp $(getent passwd "$uname" | cut -f4 -d:) "$AUTHORIZED_KEYS"
+               chmod g+r "$AUTHORIZED_KEYS"
+
+               mv -f "$AUTHORIZED_KEYS" "${VARLIB}/authorized_keys/${uname}"
 
-           log "authorized_keys file updated."
+               log "authorized_keys file updated."
+
+           # else destroy it
+           else
+               rm -f "$AUTHORIZED_KEYS"
+           fi
        done
        ;;
 
index f4d4b0d9affb8835ae812e22c9fa58f5388c3fbf..6dcb723e244a6d32d5f114dc02a6f336fcae2a58 100755 (executable)
@@ -31,6 +31,8 @@ fi
 HOST="$1"
 PORT="$2"
 
+MS_HOME=${MS_HOME:-"${HOME}/.config/monkeysphere"}
+
 if [ -z "$HOST" ] ; then
     log "host must be specified."
     usage
@@ -58,11 +60,12 @@ else
     # FIXME: this only works for default known_hosts location
     hostKey=$(ssh-keygen -F "$HOST")
     if [ "$hostKey" ] ; then
-       # if the check keyserver variable is NOT set to true...
-       if  [ "$CHECK_KEYSERVER" != 'true' ] ; then
-           # schedule a keyserver check for host at a later time
-           echo "monkeysphere update-known_hosts $HOST" | at noon
-       fi
+       # do not check the keyserver
+       # FIXME: more nuanced checking should be done here to properly
+       # take into consideration hosts that join monkeysphere by
+       # converting an existing and known ssh key
+       CHECK_KEYSERVER="false"
+
     # if the host key is not found in the known_hosts file...
     else
        # check the keyserver