X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=rhesus%2Frhesus;h=dec24a2945c7c5e7851d7518379033a5f5475325;hb=491612988f2207deaa479249f5a42c9e916704d1;hp=0c7e1003db01326e0c0a46282aa068c731ea9bb6;hpb=97429d91d8b9e69756efac3a28105535807221f3;p=monkeysphere.git diff --git a/rhesus/rhesus b/rhesus/rhesus index 0c7e100..dec24a2 100755 --- a/rhesus/rhesus +++ b/rhesus/rhesus @@ -1,25 +1,25 @@ -#!/bin/sh +#!/bin/sh -e -# rhesus: monkeysphere authorized_keys update script +# rhesus: monkeysphere authorized_keys/known_hosts generating script # # Written by # Jameson Rollins # # Copyright 2008, released under the GPL, version 3 or later -################################################## -# load conf file -CONF_FILE=${CONF_FILE:-"/etc/monkeysphere/monkeysphere.conf"} -. "$CONF_FILE" - -export GNUPGHOME -################################################## - CMD=$(basename $0) +######################################################################## +# FUNCTIONS +######################################################################## + usage() { cat </dev/null 2>&1 +} + +# convert escaped characters from gpg output back into original +# character +# FIXME: undo all escape character translation in with-colons gpg output +unescape() { + echo "$1" | sed 's/\\x3a/:/' +} + +# stand in until we get dkg's gpg2ssh program +gpg2ssh_tmp() { + local mode + local keyID + + mode="$1" + keyID="$2" + userID="$3" + + if [ "$mode" = 'authorized_keys' -o "$mode" = 'a' ] ; then + gpgkey2ssh "$keyID" | sed -e "s/COMMENT/$userID/" + elif [ "$mode" = 'known_hosts' -o "$mode" = 'k' ] ; then + echo -n "$userID "; gpgkey2ssh "$keyID" | sed -e 's/ COMMENT//' + fi +} + +# userid and key policy checking +# the following checks policy on the returned keys +# - checks that full key has appropriate valididy (u|f) +# - checks key has appropriate capability (E|A) +# - checks that particular desired user id has appropriate validity +# see /usr/share/doc/gnupg/DETAILS.gz +# FIXME: add some more status output +# expects global variable: "mode" +process_user_id() { + local userID + local cacheDir + local keyOK + local keyCapability + local keyFingerprint + local userIDHash + + userID="$1" + cacheDir="$2" + + # fetch all keys from keyserver + # if none found, break + if ! gpg_fetch_keys "$userID" ; then + echo " no keys found." + return + fi + + # some crazy piping here that takes the output of gpg and + # pipes it into a "while read" loop that reads each line + # of standard input one-by-one. + gpg --fixed-list-mode --list-key --with-colons \ + --with-fingerprint ="$userID" 2> /dev/null | \ + cut -d : -f 1,2,5,10,12 | \ + while IFS=: read -r type validity keyid uidfpr capability ; do + # process based on record type + case $type in + 'pub') + # new key, wipe the slate + keyOK= + keyCapability= + keyFingerprint= + # check primary key validity + if [ "$validity" != 'u' -a "$validity" != 'f' ] ; then + continue + fi + # check capability is not Disabled... + if echo "$capability" | grep -q 'D' ; then + continue + fi + # check capability is Encryption and Authentication + # FIXME: make more flexible capability specification + # (ie. in conf file) + if echo "$capability" | grep -q -v 'E' ; then + if echo "$capability" | grep -q -v 'A' ; then + continue + fi + fi + keyCapability="$capability" + keyOK=true + keyID="$keyid" + ;; + 'fpr') + # if key ok, get fingerprint + if [ "$keyOK" ] ; then + keyFingerprint="$uidfpr" + fi + ;; + 'uid') + # check key ok and we have key fingerprint + if [ -z "$keyOK" -o -z "$keyFingerprint" ] ; then + continue + fi + # check key validity + if [ "$validity" != 'u' -a "$validity" != 'f' ] ; then + continue + fi + # check the uid matches + if [ "$(unescape "$uidfpr")" != "$userID" ] ; then + continue + fi + # convert the key + # FIXME: needs to apply extra options if specified + echo -n " valid key found; generating ssh key(s)... " + userIDHash=$(echo "$userID" | sha1sum | awk '{ print $1 }') + # export the key with gpg2ssh + #gpg --export "$keyFingerprint" | gpg2ssh "$mode" > "$cacheDir"/"$userIDHash"."$keyFingerprint" + # stand in until we get dkg's gpg2ssh program + gpg2ssh_tmp "$mode" "$keyID" "$userID" > "$cacheDir"/"$userIDHash"."$keyFingerprint" + if [ "$?" = 0 ] ; then + echo "done." + else + echo "error." + fi + ;; + esac + done +} + +# process the auth_*_ids file +# go through line-by-line, extracting and processing each user id +# expects global variable: "mode" +process_auth_file() { + local authIDsFile + local cacheDir + local nLines + local line + local userID + + authIDsFile="$1" + cacheDir="$2" + + # find number of user ids in auth_user_ids file + nLines=$(meat <"$authIDsFile" | wc -l) + + # clean out keys file and remake keys directory + rm -rf "$cacheDir" + mkdir -p "$cacheDir" + + # loop through all user ids + for line in $(seq 1 $nLines) ; do + # get user id + # FIXME: needs to handle extra options if necessary + userID=$(meat <"$authIDsFile" | cutline "$line" ) + + # process the user id and extract keys + log "processing user id: '$userID'" + process_user_id "$userID" "$cacheDir" + done +} + +######################################################################## +# MAIN +######################################################################## if [ -z "$1" ] ; then usage exit 1 fi -# user name of user to update -USERNAME="$1" -if ! id "$USERNAME" > /dev/null ; then - failure "User '$USERNAME' does not exist." +# check mode +mode="$1" +shift 1 + +# check user +if ! id -u "$USER" > /dev/null 2>&1 ; then + failure "invalid user '$USER'." +fi + +# set user home directory +HOME=$(getent passwd "$USER" | cut -d: -f6) + +# get ms home directory +MS_HOME=${MS_HOME:-"$HOME"/.config/monkeysphere} + +# load configuration file +MS_CONF=${MS_CONF:-"$MS_HOME"/monkeysphere.conf} +[ -e "$MS_CONF" ] && . "$MS_CONF" + +# set config variable defaults +STAGING_AREA=${STAGING_AREA:-"$MS_HOME"} +AUTH_HOST_FILE=${AUTH_HOST_FILE:-"$MS_HOME"/auth_host_ids} +AUTH_USER_FILE=${AUTH_USER_FILE:-"$MS_HOME"/auth_user_ids} +GNUPGHOME=${GNUPGHOME:-"$HOME"/.gnupg} +KEYSERVER=${KEYSERVER:-subkeys.pgp.net} + +USER_KNOW_HOSTS="$HOME"/.ssh/known_hosts +USER_AUTHORIZED_KEYS="$HOME"/.ssh/authorized_keys + +# export USER and GNUPGHOME variables, since they are used by gpg +export USER +export GNUPGHOME + +# stagging locations +hostKeysCacheDir="$STAGING_AREA"/host_keys +userKeysCacheDir="$STAGING_AREA"/user_keys +msKnownHosts="$STAGING_AREA"/known_hosts +msAuthorizedKeys="$STAGING_AREA"/authorized_keys + +# set mode variables +if [ "$mode" = 'known_hosts' -o "$mode" = 'k' ] ; then + fileType=known_hosts + authFileType=auth_host_ids + authIDsFile="$AUTH_HOST_FILE" + outFile="$msKnownHosts" + cacheDir="$hostKeysCacheDir" + userFile="$USER_KNOWN_HOSTS" +elif [ "$mode" = 'authorized_keys' -o "$mode" = 'a' ] ; then + fileType=authorized_keys + authFileType=auth_user_ids + authIDsFile="$AUTH_USER_FILE" + outFile="$msAuthorizedKeys" + cacheDir="$userKeysCacheDir" + userFile="$USER_AUTHORIZED_KEYS" +else + failure "unknown command '$mode'." fi -AUTH_USER_IDS="$AUTH_USER_IDS_DIR"/"$USERNAME" -if [ ! -e "$AUTH_USER_IDS" ] ; then - failure "No auth_user_ids file for user '$USERNAME'." +# check auth ids file +if [ ! -s "$authIDsFile" ] ; then + echo "'$authFileType' file is empty or does not exist." + exit fi -KEYDIR="$AUTH_KEYS_DIR"/"$USERNAME"/keys -AUTH_KEYS="$AUTH_KEYS_DIR"/authorized_keys - -# make sure the gnupg home exists with proper permissions -mkdir -p "$GNUPGHOME" -chmod 0700 "$GNUPGHOME" - -# find number of user ids in auth_user_ids file -NLINES=$(meat "$AUTH_USER_IDS" | wc -l) - -# clean out keys file and remake keys directory -rm -rf "$KEYDIR" -mkdir -p "$KEYDIR" - -# loop through all user ids, and generate ssh keys -for (( N=1; N<=$NLINES; N=N+1 )) ; do - # get user id - USERID=$(meat "$AUTH_USER_IDS" | cutline "$N" ) - USERID_HASH=$(echo "$USERID" | sha1sum | awk '{ print $1 }') - - KEYFILE="$KEYDIR"/"$USERID_HASH" - - # search for key on keyserver - echo "ms: validating: '$USERID'" - RETURN=$(echo 1 | gpg --quiet --batch --command-fd 0 --with-colons --keyserver "$KEYSERVER" --search ="$USERID") - - # if the key was found... - if [ "$RETURN" ] ; then - echo "ms: key found." - - # checking key attributes - # see /usr/share/doc/gnupg/DETAILS.gz: - - PUB_INFO=$(gpg --fixed-list-mode --with-colons --list-keys --with-fingerprint ="$USERID" | grep '^pub:') - - # extract needed fields - KEY_TRUST=$(echo "$PUB_INFO" | cut -d: -f2) - KEY_CAPABILITY=$(echo "$PUB_INFO" | cut -d: -f12) - - # check if key disabled - if echo "$KEY_CAPABILITY" | grep -q '[D]' ; then - echo "ms: key disabled -> SKIPPING" - continue - fi +log "user '$USER': monkeysphere $fileType generation" - # check key capability - REQUIRED_KEY_CAPABILITY=${REQUIRED_KEY_CAPABILITY:-'a'} - if echo "$KEY_CAPABILITY" | grep -q '[$REQUIRED_KEY_CAPABILITY]' ; then - echo "ms: key capability verified ('$KEY_CAPABILITY')." - else - echo "ms: unacceptable key capability ('$KEY_CAPABILITY') -> SKIPPING" +# make sure gpg home exists with proper permissions +mkdir -p -m 0700 "$GNUPGHOME" + +# if users are specified on the command line, process just +# those users +if [ "$1" ] ; then + # process userids given on the command line + for userID ; do + if ! grep -q "$userID" "$authIDsFile" ; then + log "userid '$userID' not in $authFileType file." continue fi + log "processing user id: '$userID'" + process_user_id "$userID" "$cacheDir" + done +# otherwise if no users are specified, process the entire +# auth_*_ids file +else + # process the auth file + process_auth_file "$authIDsFile" "$cacheDir" +fi - echo -n "ms: key " - - # if key is not fully trusted exit - # (this includes not revoked or expired) - # determine trust - case "$KEY_TRUST" in - 'i') - echo -n "invalid" ;; - 'r') - echo -n "revoked" ;; - 'e') - echo -n "expired" ;; - '-'|'q'|'n'|'m') - echo -n "has unacceptable trust" ;; - 'f'|'u') - echo -n "fully trusted" - # convert pgp key to ssh key, and write to cache file - echo -n " -> generating ssh key..." - #gpg2ssh "$KEYID" | sed -e "s/COMMENT/$USERID/" > "$KEYFILE" - echo " done." - continue - ;; - *) - echo -n "has unknown trust" ;; - esac - echo ". -> SKIPPING" - else - echo "ms: key not found." - fi -done - -if [ $(ls "$KEYDIR") ] ; then - echo "ms: writing ms authorized_keys file..." - cat "$KEYDIR"/* > "$AUTH_KEYS" +# write output key file +log "writing ms $fileType file... " +> "$outFile" +if [ "$(ls "$cacheDir")" ] ; then + log -n "adding gpg keys... " + cat "$cacheDir"/* > "$outFile" + echo "done." else - echo "ms: no gpg keys to add to authorized_keys file." + log "no gpg keys to add." fi -if [ -s ~"$USERNAME"/.ssh/authorized_keys ] ; then - echo "ms: adding user authorized_keys..." - cat ~"$USERNAME"/.ssh/authorized_keys >> "$AUTH_KEYS" +if [ -s "$userFile" ] ; then + log -n "adding user $fileType file... " + cat "$userFile" >> "$outFile" + echo "done." fi +log "ms $fileType file generated:" +log "$outFile"