summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJameson Rollins <jrollins@finestructure.net>2010-10-18 09:55:53 -0400
committerJameson Rollins <jrollins@finestructure.net>2010-10-18 16:34:32 -0400
commitdf882c1e7e63fc658d0296dbd272499923fc4c69 (patch)
treee9e7e364780bc6429e09340d74e1bf7dc580be33
parent7f20193196c87b2cff0bf95d5ec53b5be3bdabb8 (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-xsrc/monkeysphere10
-rw-r--r--src/share/common487
-rw-r--r--src/share/m/keys_for_userid26
-rw-r--r--src/share/m/ssh_proxycommand1
-rw-r--r--src/share/m/update_authorized_keys51
-rw-r--r--src/share/m/update_known_hosts91
-rw-r--r--src/share/ma/update_users37
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}"