diff options
author | Jameson Rollins <jrollins@finestructure.net> | 2010-10-18 09:55:53 -0400 |
---|---|---|
committer | Jameson Rollins <jrollins@finestructure.net> | 2010-10-18 16:34:32 -0400 |
commit | df882c1e7e63fc658d0296dbd272499923fc4c69 (patch) | |
tree | e9e7e364780bc6429e09340d74e1bf7dc580be33 | |
parent | 7f20193196c87b2cff0bf95d5ec53b5be3bdabb8 (diff) |
Simplification/refactoring of key/file processing
This is a fairly major overhaul to greatly reduce the number of
redundant code paths. We here created a new process_keys_for_file
function that processes key from a userid for a given key file. All
the main top elevel functions now call this one function.
The main top level monkeysphere functions for updating the user's
authorized_keys and known_hosts files are now moved to their own
sourced files, which greatly reduces the amount of code sourced with
common.
monkeysphere now updates authorized_keys and known_hosts in temporary
files that are then atomically moved into place upon completion.
Finally, removed the confusing return codes in the key/file processing
functions that were based on number of valid/invalid keys processed.
It was confusing in the presence of actual errors that stopped
processing.
-rwxr-xr-x | src/monkeysphere | 10 | ||||
-rw-r--r-- | src/share/common | 487 | ||||
-rw-r--r-- | src/share/m/keys_for_userid | 26 | ||||
-rw-r--r-- | src/share/m/ssh_proxycommand | 1 | ||||
-rw-r--r-- | src/share/m/update_authorized_keys | 51 | ||||
-rw-r--r-- | src/share/m/update_known_hosts | 91 | ||||
-rw-r--r-- | src/share/ma/update_users | 37 |
7 files changed, 263 insertions, 440 deletions
diff --git a/src/monkeysphere b/src/monkeysphere index 0aa4a84..9d0685b 100755 --- a/src/monkeysphere +++ b/src/monkeysphere @@ -220,6 +220,8 @@ case $COMMAND in # whether or not to check keyservers CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:=${CHECK_KEYSERVER:="true"}} + source "${MSHAREDIR}/update_known_hosts" + # if hosts are specified on the command line, process just # those hosts if [ "$1" ] ; then @@ -235,9 +237,8 @@ case $COMMAND in 'update-authorized_keys'|'update-authorized-keys'|'a') # whether or not to check keyservers CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:=${CHECK_KEYSERVER:="true"}} - - # process authorized_user_ids file - process_authorized_user_ids "$AUTHORIZED_USER_IDS" + source "${MSHAREDIR}/update_authorized_keys" + update_authorized_keys ;; 'import-subkey'|'import'|'i') @@ -267,17 +268,20 @@ case $COMMAND in 'keys-for-userid'|'u') CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:=${CHECK_KEYSERVER:="true"}} + source "${MSHAREDIR}/keys_for_userid" keys_for_userid "$@" ;; 'sshfprs-for-userid') CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:=${CHECK_KEYSERVER:="true"}} + source "${MSHAREDIR}/keys_for_userid" keys_for_userid "$@" | "$SYSSHAREDIR/keytrans" sshfpr ;; 'keys-from-userid') echo "Warning: 'keys-from-userid' is deprecated. Please use 'keys-for-userid' instead." >&2 CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:=${CHECK_KEYSERVER:="true"}} + source "${MSHAREDIR}/keys_for_userid" keys_for_userid "$@" ;; diff --git a/src/share/common b/src/share/common index 5486eaa..ec8b5b2 100644 --- a/src/share/common +++ b/src/share/common @@ -505,14 +505,13 @@ ssh2known_hosts() { # output authorized_keys line from ssh key ssh2authorized_keys() { - local koptions="$1" - local userID="$2" - local key="$3" + local userID="$1" + local key="$2" - if [[ -z "$koptions" ]]; then - printf "%s MonkeySphere%s %s\n" "$key" "$DATE" "$userID" + if [[ "$AUTHORIZED_KEYS_OPTIONS" ]]; then + printf "%s %s MonkeySphere%s %s\n" "$AUTHORIZED_KEYS_OPTIONS" "$key" "$DATE" "$userID" else - printf "%s %s MonkeySphere%s %s\n" "$koptions" "$key" "$DATE" "$userID" + printf "%s MonkeySphere%s %s\n" "$key" "$DATE" "$userID" fi } @@ -787,442 +786,104 @@ process_user_id() { # being processed in the key files over "bad" keys (key flag '1') } -# output all valid keys for specified user ID literal -keys_for_userid() { - local userID - local noKey= - local nKeys - local nKeysOK - local ok - local sshKey - local tmpfile - - userID="$1" - - log verbose "processing: $userID" - - nKeys=0 - nKeysOK=0 - - IFS=$'\n' - for line in $(process_user_id "${userID}") ; do - # note that key was found - nKeys=$((nKeys+1)) - - ok=$(echo "$line" | cut -d: -f1) - sshKey=$(echo "$line" | cut -d: -f2) - - if [ -z "$sshKey" ] ; then - continue - fi - - # if key OK, output key to stdout - if [ "$ok" -eq '0' ] ; then - # note that key was found ok - nKeysOK=$((nKeysOK+1)) - - printf '%s\n' "$sshKey" - fi - done - - # if at least one key was found... - if [ "$nKeys" -gt 0 ] ; then - # if ok keys were found, return 0 - if [ "$nKeysOK" -gt 0 ] ; then - return 0 - # else return 2 - else - return 2 - fi - # if no keys were found, return 1 - else - return 1 - fi -} - -# process a single host in the known_host file -process_host_known_hosts() { +process_keys_for_file() { + local keyFile="$1" + local userID="$2" local host - local userID - local noKey= - local nKeys - local nKeysOK local ok local sshKey - local tmpfile - - # set the key processing mode - export REQUIRED_KEY_CAPABILITY="$REQUIRED_HOST_KEY_CAPABILITY" - - host="$1" - userID="ssh://${host}" - - log verbose "processing: $host" + local noKey= - nKeys=0 - nKeysOK=0 + log verbose "processing: $userID" + log debug "keyFile: $keyFile" IFS=$'\n' - for line in $(process_user_id "${userID}") ; do - # note that key was found - nKeys=$((nKeys+1)) - - ok=$(echo "$line" | cut -d: -f1) - sshKey=$(echo "$line" | cut -d: -f2) + for line in $(process_user_id ssh "${userID}") ; do + ok=${line%%:*} + sshKey=${line#*:} if [ -z "$sshKey" ] ; then continue fi - # remove any old host key line, and note if removed nothing is - # removed - remove_line "$KNOWN_HOSTS" "$sshKey" || noKey=true - - # if key OK, add new host line - if [ "$ok" -eq '0' ] ; then - # note that key was found ok - nKeysOK=$((nKeysOK+1)) - - # hash if specified - if [ "$HASH_KNOWN_HOSTS" = 'true' ] ; then - if (type ssh-keygen >/dev/null) ; then - # FIXME: this is really hackish cause ssh-keygen won't - # hash from stdin to stdout - tmpfile=$(mktemp ${TMPDIR:-/tmp}/tmp.XXXXXXXXXX) - ssh2known_hosts "$host" "$sshKey" > "$tmpfile" - ssh-keygen -H -f "$tmpfile" 2>/dev/null - cat "$tmpfile" >> "$KNOWN_HOSTS" - rm -f "$tmpfile" "${tmpfile}.old" - else - # FIXME: we could do this without needing ssh-keygen. hashed - # known_hosts looks like: |1|X|Y where 1 means SHA1 (nothing - # else is defined in openssh sources), X is the salt (same - # length as the digest output), base64-encoded, and Y is the - # digested hostname (also base64-encoded). - - # see hostfile.{c,h} in openssh sources. - - failure "Cannot hash known_hosts as requested" - fi - else - ssh2known_hosts "$host" "$sshKey" >> "$KNOWN_HOSTS" - fi - - # log if this is a new key to the known_hosts file - if [ "$noKey" ] ; then - log info "* new key for $host added to known_hosts file." - fi - fi - done - - # if at least one key was found... - if [ "$nKeys" -gt 0 ] ; then - # if ok keys were found, return 0 - if [ "$nKeysOK" -gt 0 ] ; then - return 0 - # else return 2 - else - return 2 - fi - # if no keys were found, return 1 - else - return 1 - fi -} - -# update the known_hosts file for a set of hosts listed on command -# line -update_known_hosts() { - local returnCode=0 - local nHosts - local nHostsOK - local nHostsBAD - local fileCheck - local host - local newUmask - - # the number of hosts specified on command line - nHosts="$#" - - nHostsOK=0 - nHostsBAD=0 - - # touch the known_hosts file so that the file permission check - # below won't fail upon not finding the file - if [ ! -f "$KNOWN_HOSTS" ]; then - # make sure to create any files or directories with the appropriate write bits turned off: - newUmask=$(printf "%04o" $(( 0$(umask) | 0022 )) ) - [ -d $(dirname "$KNOWN_HOSTS") ] \ - || (umask "$newUmask" && mkdir -p -m 0700 $(dirname "$KNOWN_HOSTS") ) \ - || failure "Could not create path to known_hosts file '$KNOWN_HOSTS'" - # make sure to create this file with the appropriate bits turned off: - (umask "$newUmask" && touch "$KNOWN_HOSTS") \ - || failure "Unable to create known_hosts file '$KNOWN_HOSTS'" - fi - - # check permissions on the known_hosts file path - check_key_file_permissions $(whoami) "$KNOWN_HOSTS" \ - || failure "Bad permissions governing known_hosts file '$KNOWN_HOSTS'" - - # create a lockfile on known_hosts: - lock create "$KNOWN_HOSTS" - # FIXME: we're discarding any pre-existing EXIT trap; is this bad? - trap "lock remove $KNOWN_HOSTS" EXIT - - # note pre update file checksum - fileCheck=$(file_hash "$KNOWN_HOSTS") - - for host ; do - # process the host - process_host_known_hosts "$host" || returnCode="$?" - # note the result - case "$returnCode" in - 0) - nHostsOK=$((nHostsOK+1)) + # remove the old host key line + case "$FILE_TYPE" in + ('raw'|'authorized_keys') + remove_line "$keyFile" "$sshKey" || noKey=true ;; - 2) - nHostsBAD=$((nHostsBAD+1)) + ('known_hosts') + host=${userID#ssh://} + remove_line "$keyFile" "${host}.*${sshKey}" || noKey=true ;; esac - # touch the lockfile, for good measure. - lock touch "$KNOWN_HOSTS" - done - - # remove the lockfile and the trap - lock remove "$KNOWN_HOSTS" - trap - EXIT - - # note if the known_hosts file was updated - if [ "$(file_hash "$KNOWN_HOSTS")" != "$fileCheck" ] ; then - log debug "known_hosts file updated." - fi - - # if an acceptable host was found, return 0 - if [ "$nHostsOK" -gt 0 ] ; then - return 0 - # else if no ok hosts were found... - else - # if no bad host were found then no hosts were found at all, - # and return 1 - if [ "$nHostsBAD" -eq 0 ] ; then - return 1 - # else if at least one bad host was found, return 2 - else - return 2 - fi - fi -} - -# process hosts from a known_hosts file -process_known_hosts() { - local hosts - - # exit if the known_hosts file does not exist - if [ ! -e "$KNOWN_HOSTS" ] ; then - failure "known_hosts file '$KNOWN_HOSTS' does not exist." - fi - - log debug "processing known_hosts file:" - log debug " $KNOWN_HOSTS" - - hosts=$(meat "$KNOWN_HOSTS" | cut -d ' ' -f 1 | grep -v '^|.*$' | tr , ' ' | tr '\n' ' ') - - if [ -z "$hosts" ] ; then - log debug "no hosts to process." - return - fi - - # take all the hosts from the known_hosts file (first - # field), grep out all the hashed hosts (lines starting - # with '|')... - update_known_hosts $hosts -} - -# process uids for the authorized_keys file -process_uid_authorized_keys() { - local userID - local koptions - local nKeys - local nKeysOK - local ok - local sshKey - - # set the key processing mode - export REQUIRED_KEY_CAPABILITY="$REQUIRED_USER_KEY_CAPABILITY" - - koptions="$1" - userID="$2" - - log verbose "processing: $userID" - - nKeys=0 - nKeysOK=0 - - IFS=$'\n' - for line in $(process_user_id "$userID") ; do - # note that key was found - nKeys=$((nKeys+1)) - - ok=$(echo "$line" | cut -d: -f1) - sshKey=$(echo "$line" | cut -d: -f2) - - if [ -z "$sshKey" ] ; then - continue - fi - - # remove the old host key line - remove_line "$AUTHORIZED_KEYS" "$sshKey" - # if key OK, add new host line if [ "$ok" -eq '0' ] ; then - # note that key was found ok - nKeysOK=$((nKeysOK+1)) - - ssh2authorized_keys "$koptions" "$userID" "$sshKey" >> "$AUTHORIZED_KEYS" - fi - done - - # if at least one key was found... - if [ "$nKeys" -gt 0 ] ; then - # if ok keys were found, return 0 - if [ "$nKeysOK" -gt 0 ] ; then - return 0 - # else return 2 - else - return 2 - fi - # if no keys were found, return 1 - else - return 1 - fi -} - -# update the authorized_keys files from a list of user IDs on command -# line -update_authorized_keys() { - local returnCode=0 - local userID - local nIDs - local nIDsOK - local nIDsBAD - local fileCheck - local x koptions - declare -i argtype - - if (( $# % 2 )); then log error "Bad number of arguments; this should never happen."; return 1; fi - - # the number of ids specified on command line - (( nIDs=$#/2 )) - (( argtype=0 )) - - nIDsOK=0 - nIDsBAD=0 - - log debug "updating authorized_keys file:" - log debug " $AUTHORIZED_KEYS" - - # check permissions on the authorized_keys file path - check_key_file_permissions $(whoami) "$AUTHORIZED_KEYS" || failure - - # create a lockfile on authorized_keys - lock create "$AUTHORIZED_KEYS" - # FIXME: we're discarding any pre-existing EXIT trap; is this bad? - trap "lock remove $AUTHORIZED_KEYS" EXIT - - # note pre update file checksum - fileCheck="$(file_hash "$AUTHORIZED_KEYS")" - - # remove any monkeysphere lines from authorized_keys file - remove_monkeysphere_lines "$AUTHORIZED_KEYS" - - for x; do - (( argtype++ )) - if (( $argtype % 2 )); then - koptions="$x" - else - userID="$x" - - # process the user ID, change return code if key not found - # for user ID - process_uid_authorized_keys "$koptions" "$userID" || returnCode="$?" - - # note the result - case "$returnCode" in - 0) - nIDsOK=$((nIDsOK+1)) + case "$FILE_TYPE" in + ('raw') + echo "$sshKey" | log debug + echo "$sshKey" >> "$keyFile" ;; - 2) - nIDsBAD=$((nIDsBAD+1)) + ('authorized_keys') + ssh2authorized_keys "$userID" "$sshKey" | log debug + ssh2authorized_keys "$userID" "$sshKey" \ + >> "$keyFile" ;; - esac + ('known_hosts') + # hash if specified + if [ "$HASH_KNOWN_HOSTS" = 'true' ] ; then + if (type ssh-keygen >/dev/null) ; then + # FIXME: this is really hackish cause + # ssh-keygen won't hash from stdin to + # stdout + tmpfile=$(mktemp ${TMPDIR:-/tmp}/tmp.XXXXXXXXXX) + ssh2known_hosts "$host" "$sshKey" \ + > "$tmpfile" + ssh-keygen -H -f "$tmpfile" 2>/dev/null + cat "$tmpfile" >> "$keyFile" + rm -f "$tmpfile" "${tmpfile}.old" + # FIXME: we could do this without needing + # ssh-keygen. hashed known_hosts looks + # like: |1|X|Y where 1 means SHA1 (nothing + # else is defined in openssh sources), X + # is the salt (same length as the digest + # output), base64-encoded, and Y is the + # digested hostname (also base64-encoded). + # see hostfile.{c,h} in openssh sources. + else + failure "Cannot hash known_hosts as requested" + fi + else + ssh2known_hosts "$host" "$sshKey" | log debug + ssh2known_hosts "$host" "$sshKey" \ + >> "$keyFile" + fi - # touch the lockfile, for good measure. - lock touch "$AUTHORIZED_KEYS" + # log if this is a new key to the known_hosts file + if [ "$noKey" ] ; then + log info "* new key will be added to known_hosts file." + fi + ;; + esac fi done - - # remove the lockfile and the trap - lock remove "$AUTHORIZED_KEYS" - - # remove the trap - trap - EXIT - - # note if the authorized_keys file was updated - if [ "$(file_hash "$AUTHORIZED_KEYS")" != "$fileCheck" ] ; then - log debug "authorized_keys file updated." - fi - - # if an acceptable id was found, return 0 - if [ "$nIDsOK" -gt 0 ] ; then - return 0 - # else if no ok ids were found... - else - # if no bad ids were found then no ids were found at all, and - # return 1 - if [ "$nIDsBAD" -eq 0 ] ; then - return 1 - # else if at least one bad id was found, return 2 - else - return 2 - fi - fi } -# process an authorized_user_ids file for authorized_keys +# process an authorized_user_ids file on stdin for authorized_keys process_authorized_user_ids() { + local authorizedKeys="$1" + declare -i nline=0 local line - declare -i nline declare -a userIDs declare -a koptions - declare -a export_array - - authorizedUserIDs="$1" - - (( nline=0 )) - - # exit if the authorized_user_ids file is empty - if [ ! -e "$authorizedUserIDs" ] ; then - failure "authorized_user_ids file '$authorizedUserIDs' does not exist." - fi - - log debug "processing authorized_user_ids file:" - log debug " $authorizedUserIDs" - - # check permissions on the authorized_user_ids file path - check_key_file_permissions $(whoami) "$authorizedUserIDs" || failure - - if ! meat "$authorizedUserIDs" >/dev/null ; then - log debug " no user IDs to process." - return - fi - - nline=0 # extract user IDs from authorized_user_ids file IFS=$'\n' - for line in $(meat "$authorizedUserIDs") ; do + while read line ; do case "$line" in + ("#"*) + continue + ;; (" "*|$'\t'*) if [[ -z ${koptions[${nline}]} ]]; then koptions[${nline}]=$(echo $line | sed 's/^[ ]*//;s/[ ]$//;') @@ -1231,7 +892,7 @@ process_authorized_user_ids() { fi ;; (*) - ((nline++)) + nline=$((nline+1)) userIDs[${nline}]="$line" unset koptions[${nline}] || true ;; @@ -1239,10 +900,8 @@ process_authorized_user_ids() { done for i in $(seq 1 $nline); do - export_array+=("${koptions[$i]}" "${userIDs[$i]}") + AUTHORIZED_KEYS_OPTIONS="${koptions[$i]}" FILE_TYPE='authorized_keys' process_keys_for_file "$authorizedKeys" "${userIDs[$i]}" || returnCode="$?" done - - update_authorized_keys "${export_array[@]}" } # takes a gpg key or keys on stdin, and outputs a list of diff --git a/src/share/m/keys_for_userid b/src/share/m/keys_for_userid new file mode 100644 index 0000000..a65356b --- /dev/null +++ b/src/share/m/keys_for_userid @@ -0,0 +1,26 @@ +# -*-shell-script-*- +# This should be sourced by bash (though we welcome changes to make it POSIX sh compliant) + +# Monkeysphere keys-for-userid subcommand +# +# The monkeysphere scripts are written by: +# Jameson Rollins <jrollins@finestructure.net> +# Jamie McClelland <jm@mayfirst.org> +# Daniel Kahn Gillmor <dkg@fifthhorseman.net> +# +# They are Copyright 2010, and are all released under the GPL, version +# 3 or later. + +keys_for_userid() { + local tmpFile=$(msmktempfile) + + trap "rm -f $tmpFile" EXIT + + FILE_TYPE='raw' process_keys_for_file "$tmpFile" "$@" + + cat "$tmpFile" + + rm -f "$tmpFile" + + trap - EXIT +} diff --git a/src/share/m/ssh_proxycommand b/src/share/m/ssh_proxycommand index 5fb2ce4..a4c01c6 100644 --- a/src/share/m/ssh_proxycommand +++ b/src/share/m/ssh_proxycommand @@ -272,6 +272,7 @@ CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:=$CHECK_KEYSERVER} # update the known_hosts file for the host local returnCode=0 +source "${MSHAREDIR}/update_known_hosts" update_known_hosts "$HOSTP" || returnCode="$?" # output on depending on the return of the update-known_hosts diff --git a/src/share/m/update_authorized_keys b/src/share/m/update_authorized_keys new file mode 100644 index 0000000..f38bdab --- /dev/null +++ b/src/share/m/update_authorized_keys @@ -0,0 +1,51 @@ +# -*-shell-script-*- +# This should be sourced by bash (though we welcome changes to make it POSIX sh compliant) + +# Monkeysphere update_authorized_keys subcommand +# +# The monkeysphere scripts are written by: +# Jameson Rollins <jrollins@finestructure.net> +# Jamie McClelland <jm@mayfirst.org> +# Daniel Kahn Gillmor <dkg@fifthhorseman.net> +# +# They are Copyright 2010, and are all released under the GPL, version +# 3 or later. + +update_authorized_keys() { + local tmpFile + + log debug "updating authorized_keys file:" + log debug " $AUTHORIZED_KEYS" + + # check permissions on the authorized_{keys,user_ids} file paths + check_key_file_permissions $(whoami) "$AUTHORIZED_KEYS" || failure + check_key_file_permissions $(whoami) "$AUTHORIZED_USER_IDS" || failure + + # create a lockfile on authorized_keys + lock create "$AUTHORIZED_KEYS" + + # make temp file + #tmpFile="$(dirname "$keyFile")/.$(basename "$keyFile")." + tmpFile=$(mktemp "${AUTHORIZED_KEYS}.monkeysphere.XXXXXX") + + # FIXME: we're discarding any pre-existing EXIT trap; is this bad? + trap "lock remove $AUTHORIZED_KEYS; rm -f $tmpFile" EXIT + + # remove any monkeysphere lines from authorized_keys file + remove_monkeysphere_lines "$AUTHORIZED_KEYS" > "$tmpFile" + + process_authorized_user_ids "$tmpFile" \ + < "$AUTHORIZED_USER_IDS" + + # note if the authorized_keys file was updated + if [ "$(file_hash "$AUTHORIZED_KEYS")" != "$(file_hash "$tmpFile")" ] ; then + log debug "authorized_keys file updated." + fi + mv -f "$tmpFile" "$AUTHORIZED_KEYS" + + # remove the lockfile and the trap + lock remove "$AUTHORIZED_KEYS" + + # remove the trap + trap - EXIT +} diff --git a/src/share/m/update_known_hosts b/src/share/m/update_known_hosts new file mode 100644 index 0000000..58cf78a --- /dev/null +++ b/src/share/m/update_known_hosts @@ -0,0 +1,91 @@ +# -*-shell-script-*- +# This should be sourced by bash (though we welcome changes to make it POSIX sh compliant) + +# Monkeysphere update_known_hosts subcommand +# +# The monkeysphere scripts are written by: +# Jameson Rollins <jrollins@finestructure.net> +# Jamie McClelland <jm@mayfirst.org> +# Daniel Kahn Gillmor <dkg@fifthhorseman.net> +# +# They are Copyright 2010, and are all released under the GPL, version +# 3 or later. + +# update the known_hosts file for a set of hosts listed on command +# line +update_known_hosts() { + local returnCode=0 + local fileCheck + local host + local newUmask + + # touch the known_hosts file so that the file permission check + # below won't fail upon not finding the file + if [ ! -f "$KNOWN_HOSTS" ]; then + # make sure to create any files or directories with the appropriate write bits turned off: + newUmask=$(printf "%04o" $(( 0$(umask) | 0022 )) ) + [ -d $(dirname "$KNOWN_HOSTS") ] \ + || (umask "$newUmask" && mkdir -p -m 0700 $(dirname "$KNOWN_HOSTS") ) \ + || failure "Could not create path to known_hosts file '$KNOWN_HOSTS'" + # make sure to create this file with the appropriate bits turned off: + (umask "$newUmask" && touch "$KNOWN_HOSTS") \ + || failure "Unable to create known_hosts file '$KNOWN_HOSTS'" + fi + + # check permissions on the known_hosts file path + check_key_file_permissions $(whoami) "$KNOWN_HOSTS" \ + || failure "Bad permissions governing known_hosts file '$KNOWN_HOSTS'" + + # create a lockfile on known_hosts: + lock create "$KNOWN_HOSTS" + + # make temp file + tmpFile=$(mktemp "${KNOWN_HOSTS}.monkeysphere.XXXXXX") + + # FIXME: we're discarding any pre-existing EXIT trap; is this bad? + trap "lock remove $KNOWN_HOSTS; rm -f $tmpFile" EXIT + + for host ; do + FILE_TYPE='known_hosts' process_keys_for_file "$tmpFile" "ssh://${host}" + + # touch the lockfile, for good measure. + lock touch "$KNOWN_HOSTS" + done + + # note if the authorized_keys file was updated + if [ "$(file_hash "$KNOWN_HOSTS")" != "$(file_hash "$tmpFile")" ] ; then + log debug "known_hosts file updated." + fi + mv -f "$tmpFile" "$KNOWN_HOSTS" + + # remove the lockfile and the trap + lock remove "$KNOWN_HOSTS" + + # remove the trap + trap - EXIT +} + +# process hosts from a known_hosts file +process_known_hosts() { + local hosts + + # exit if the known_hosts file does not exist + if [ ! -e "$KNOWN_HOSTS" ] ; then + failure "known_hosts file '$KNOWN_HOSTS' does not exist." + fi + + log debug "processing known_hosts file:" + log debug " $KNOWN_HOSTS" + + hosts=$(meat "$KNOWN_HOSTS" | cut -d ' ' -f 1 | grep -v '^|.*$' | tr , ' ' | tr '\n' ' ') + + if [ -z "$hosts" ] ; then + log debug "no hosts to process." + return + fi + + # take all the hosts from the known_hosts file (first + # field), grep out all the hashed hosts (lines starting + # with '|')... + update_known_hosts $hosts +} diff --git a/src/share/ma/update_users b/src/share/ma/update_users index 4d2bb35..c84716e 100644 --- a/src/share/ma/update_users +++ b/src/share/ma/update_users @@ -17,6 +17,7 @@ local returnCode=0 local unames local uname local authorizedKeysDir +local tmpAuthorizedKeys local authorizedUserIDs if [ "$1" ] ; then @@ -57,19 +58,14 @@ for uname in $unames ; do # trap to delete temporary directory on exit trap "rm -rf $TMPLOC" EXIT - # create temporary authorized_user_ids file - TMP_AUTHORIZED_USER_IDS="${TMPLOC}/authorized_user_ids" - touch "$TMP_AUTHORIZED_USER_IDS" - # create temporary authorized_keys file - AUTHORIZED_KEYS="${TMPLOC}/authorized_keys" - touch "$AUTHORIZED_KEYS" + tmpAuthorizedKeys="${TMPLOC}/authorized_keys" + touch "$tmpAuthorizedKeys" # set restrictive permissions on the temporary files # FIXME: is there a better way to do this? chmod 0700 "$TMPLOC" - chmod 0600 "$AUTHORIZED_KEYS" - chmod 0600 "$TMP_AUTHORIZED_USER_IDS" + chmod 0600 "$tmpAuthorizedKeys" chown -R "$MONKEYSPHERE_USER" "$TMPLOC" # process authorized_user_ids file @@ -80,17 +76,12 @@ for uname in $unames ; do log debug "authorized_user_ids file found." # check permissions on the authorized_user_ids file path if check_key_file_permissions "$uname" "$authorizedUserIDs" ; then - # copy user authorized_user_ids file to temporary - # location - cat "$authorizedUserIDs" > "$TMP_AUTHORIZED_USER_IDS" - - # export needed variables - export AUTHORIZED_KEYS # process authorized_user_ids file, as monkeysphere user su_monkeysphere_user \ - ". ${SYSSHAREDIR}/common; STRICT_MODES='$STRICT_MODES' process_authorized_user_ids $TMP_AUTHORIZED_USER_IDS" \ - || returnCode="$?" + ". ${SYSSHAREDIR}/common; STRICT_MODES='$STRICT_MODES' process_authorized_user_ids $tmpAuthorizedKeys" \ + < "$authorizedUserIDs" + else log debug "not processing authorized_user_ids." fi @@ -107,7 +98,7 @@ for uname in $unames ; do # check permissions on the authorized_keys file path if check_key_file_permissions "$uname" "$rawAuthorizedKeys" ; then log verbose "adding raw authorized_keys file... " - cat "$rawAuthorizedKeys" >> "$AUTHORIZED_KEYS" + cat "$rawAuthorizedKeys" >> "$tmpAuthorizedKeys" else log debug "not adding raw authorized_keys file." fi @@ -117,7 +108,7 @@ for uname in $unames ; do fi # move the new authorized_keys file into place - if [ -s "$AUTHORIZED_KEYS" ] ; then + if [ -s "$tmpAuthorizedKeys" ] ; 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. @@ -130,14 +121,14 @@ for uname in $unames ; do if [ "$OUTPUT_STDOUT" ] ; then log debug "outputting keys to stdout..." - cat "$AUTHORIZED_KEYS" + cat "$tmpAuthorizedKeys" else log debug "moving new file to ${authorizedKeysDir}/${uname}..." # FIXME: is there a better way to do this? - chown $(whoami) "$AUTHORIZED_KEYS" && \ - chgrp $(id -g "$uname") "$AUTHORIZED_KEYS" && \ - chmod g+r "$AUTHORIZED_KEYS" && \ - mv -f "$AUTHORIZED_KEYS" "${authorizedKeysDir}/${uname}" || \ + chown $(whoami) "$tmpAuthorizedKeys" && \ + chgrp $(id -g "$uname") "$tmpAuthorizedKeys" && \ + chmod g+r "$tmpAuthorizedKeys" && \ + mv -f "$tmpAuthorizedKeys" "${authorizedKeysDir}/${uname}" || \ { log error "Failed to install authorized_keys for '$uname'!" rm -f "${authorizedKeysDir}/${uname}" |