# Jamie McClelland <jm@mayfirst.org>
# Daniel Kahn Gillmor <dkg@fifthhorseman.net>
#
-# Copyright 2008, released under the GPL, version 3 or later
+# Copyright 2008-2009, released under the GPL, version 3 or later
# all-caps variables are meant to be user supplied (ie. from config
# file) and are considered global
export SYSCONFIGDIR
# monkeysphere version
-VERSION=__VERSION__
+VERSION=0.23~pre
+
+# default log level
+LOG_LEVEL="INFO"
+
+# default keyserver
+KEYSERVER="pool.sks-keyservers.net"
+
+# whether or not to check keyservers by defaul
+CHECK_KEYSERVER="true"
+
+# default monkeysphere user
+MONKEYSPHERE_USER="monkeysphere"
+
+# default about whether or not to prompt
+PROMPT="true"
########################################################################
### UTILITY FUNCTIONS
# write output to stderr based on specified LOG_LEVEL the first
# parameter is the priority of the output, and everything else is what
-# is echoed to stderr
+# is echoed to stderr. If there is nothing else, then output comes
+# from stdin, and is not prefaced by log prefix.
log() {
local priority
local level
output=true
fi
if [ "$priority" = "$level" -a "$output" = 'true' ] ; then
- echo -n "ms: " >&2
- echo "$@" >&2
+ if [ "$1" ] ; then
+ echo -n "ms: " >&2
+ echo "$@" >&2
+ else
+ cat >&2
+ fi
fi
done
}
+# run command as monkeysphere user
+su_monkeysphere_user() {
+ # our main goal here is to run the given command as the the
+ # monkeysphere user, but without prompting for any sort of
+ # authentication. If this is not possible, we should just fail.
+
+ # FIXME: our current implementation is overly restrictive, because
+ # there may be some su PAM configurations that would allow su
+ # "$MONKEYSPHERE_USER" -c "$@" to Just Work without prompting,
+ # allowing specific users to invoke commands which make use of
+ # this user.
+
+ # chpst (from runit) would be nice to use, but we don't want to
+ # introduce an extra dependency just for this. This may be a
+ # candidate for re-factoring if we switch implementation languages.
+
+ case $(id -un) in
+ # if monkeysphere user, run the command under bash
+ "$MONKEYSPHERE_USER")
+ bash -c "$@"
+ ;;
+
+ # if root, su command as monkeysphere user
+ 'root')
+ su "$MONKEYSPHERE_USER" -c "$@"
+ ;;
+
+ # otherwise, fail
+ *)
+ log error "non-privileged user."
+ ;;
+ esac
+}
+
# cut out all comments(#) and blank lines from standard input
meat() {
grep -v -e "^[[:space:]]*#" -e '^$' "$1"
head --line="$1" "$2" | tail -1
}
+# make a temporary directory
+msmktempdir() {
+ mktemp -d ${TMPDIR:-/tmp}/monkeysphere.XXXXXXXXXX
+}
+
+# make a temporary file
+msmktempfile() {
+ mktemp ${TMPDIR:-/tmp}/monkeysphere.XXXXXXXXXX
+}
+
# this is a wrapper for doing lock functions.
#
# it lets us depend on either lockfile-progs (preferred) or procmail's
else
lockfile -r 20 "${file}.lock" || failure "unable to lock '$file'"
fi
+ log debug "lock created on '$file'."
;;
touch)
if [ -n "$use_lockfileprogs" ] ; then
else
: Nothing to do here
fi
+ log debug "lock touched on '$file'."
;;
remove)
if [ -n "$use_lockfileprogs" ] ; then
else
rm -f "${file}.lock"
fi
+ log debug "lock removed on '$file'."
;;
*)
failure "bad argument for lock subfunction '$action'"
keyExpire="$1"
- if [ -z "$keyExpire" ]; then
+ if [ -z "$keyExpire" -a "$PROMPT" = 'true' ]; then
cat >&2 <<EOF
Please specify how long the key should be valid.
0 = key does not expire
uname="$1"
path="$2"
+ log debug "checking path permission '$path'..."
+
# return 255 if cannot stat file
if ! stat=$(ls -ld "$path" 2>/dev/null) ; then
log error "could not stat path '$path'."
local sshKey
local tmpfile
+ # set the key processing mode
+ export MODE='known_hosts'
+
host="$1"
userID="ssh://${host}"
nHostsOK=0
nHostsBAD=0
+ # touch the known_hosts file so that the file permission check
+ # below won't fail upon not finding the file
+ (umask 0022 && touch "$KNOWN_HOSTS")
+
+ # check permissions on the known_hosts file path
+ check_key_file_permissions "$USER" "$KNOWN_HOSTS" || failure
+
# create a lockfile on known_hosts:
lock create "$KNOWN_HOSTS"
# FIXME: we're discarding any pre-existing EXIT trap; is this bad?
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..."
hosts=$(meat "$KNOWN_HOSTS" | cut -d ' ' -f 1 | grep -v '^|.*$' | tr , ' ' | tr '\n' ' ')
local ok
local sshKey
+ # set the key processing mode
+ export MODE='authorized_keys'
+
userID="$1"
log verbose "processing: $userID"
nIDsOK=0
nIDsBAD=0
+ # check permissions on the authorized_keys file path
+ check_key_file_permissions "$USER" "$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?
# remove the lockfile and the trap
lock remove "$AUTHORIZED_KEYS"
+
+ # remove the trap
trap - EXIT
# note if the authorized_keys file was updated
authorizedUserIDs="$1"
+ # exit if the authorized_user_ids file is empty
+ if [ ! -e "$authorizedUserIDs" ] ; then
+ failure "authorized_user_ids file '$authorizedUserIDs' does not exist."
+ fi
+
+ # check permissions on the authorized_user_ids file path
+ check_key_file_permissions "$USER" "$authorizedUserIDs" || failure
+
log debug "processing authorized_user_ids file..."
if ! meat "$authorizedUserIDs" > /dev/null ; then
update_authorized_keys "${userIDs[@]}"
}
+
+# takes a gpg key or keys on stdin, and outputs a list of
+# fingerprints, one per line:
+list_primary_fingerprints() {
+ local file="$1"
+ local fake=$(msmktempdir)
+ GNUPGHOME="$fake" gpg --no-tty --quiet --import
+ GNUPGHOME="$fake" gpg --with-colons --fingerprint --list-keys | \
+ awk -F: '/^fpr:/{ print $10 }'
+ rm -rf "$fake"
+}