#!/bin/sh

# monkeysphere-server: MonkeySphere server admin tool
#
# The monkeysphere scripts are written by:
# Jameson Rollins <jrollins@fifthhorseman.net>
#
# They are Copyright 2008, and are all released under the GPL, version 3
# or later.

########################################################################
PGRM=$(basename $0)

SHAREDIR=${SHAREDIR:-"/usr/share/monkeysphere"}
export SHAREDIR
. "${SHAREDIR}/common"

# date in UTF format if needed
DATE=$(date -u '+%FT%T')

# unset some environment variables that could screw things up
GREP_OPTIONS=

########################################################################
# FUNCTIONS
########################################################################

usage() {
cat <<EOF
usage: $PGRM <subcommand> [args]
Monkeysphere server admin tool.

subcommands:
  update-users (s) [USER]...            update users authorized_keys files
  gen-key (g)                           generate gpg key for the server
  publish-key (p)                       publish server key to keyserver
  trust-keys (t) KEYID...               mark keyids as trusted
  update-user-userids (u) USER UID...   add/update userids for a user
  help (h,?)                            this help

EOF
}

# generate server gpg key
gen_key() {
    # set key defaults
    KEY_TYPE=${KEY_TYPE:-"RSA"}
    KEY_LENGTH=${KEY_LENGTH:-"2048"}
    KEY_USAGE=${KEY_USAGE:-"encrypt,auth"}
    SERVICE=${SERVICE:-"ssh"}
    HOSTNAME_FQDN=${HOSTNAME_FQDN:-$(hostname -f)}

    USERID=${USERID:-"$SERVICE"://"$HOSTNAME_FQDN"}

    # set key parameters
    keyParameters=$(cat <<EOF
Key-Type: $KEY_TYPE
Key-Length: $KEY_LENGTH
Key-Usage: $KEY_USAGE
Name-Real: $USERID
EOF
)

    # add the revoker field if requested
    if [ "$REVOKER" ] ; then
	keyParameters="${keyParameters}"$(cat <<EOF

Revoker: 1:$REVOKER sensitive
EOF
)
    fi

    log "The following key parameters will be used:"
    echo "$keyParameters"

    read -p "generate key? [Y|n]: " OK; OK=${OK:=Y}
    if [ ${OK/y/Y} != 'Y' ] ; then
	failure "aborting."
    fi

    if gpg --list-key ="$USERID" > /dev/null 2>&1 ; then
	failure "key for '$USERID' already exists"
    fi

    # add commit command
    keyParameters="${keyParameters}"$(cat <<EOF

%commit
%echo done
EOF
)

    echo "generating server key..."
    echo "$keyParameters" | gpg --batch --gen-key
}

# publish server key to keyserver
publish_key() {
    read -p "publish key to $KEYSERVER? [Y|n]: " OK; OK=${OK:=Y}
    if [ ${OK/y/Y} != 'Y' ] ; then
	failure "aborting."
    fi

    keyID=$(gpg --list-key --with-colons ="$USERID" 2> /dev/null | grep '^pub:' | cut -d: -f5)

    # dummy command so as not to publish fakes keys during testing
    # eventually:
    #gpg --send-keys --keyserver "$KEYSERVER" "$keyID"
    echo "NOT PUBLISHED: gpg --send-keys --keyserver $KEYSERVER $keyID"
}

########################################################################
# MAIN
########################################################################

COMMAND="$1"
[ "$COMMAND" ] || failure "Type '$PGRM help' for usage."
shift

# set ms home directory
MS_HOME=${MS_HOME:-"$ETC"}

# load configuration file
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}
KEYSERVER=${KEYSERVER:-subkeys.pgp.net}
REQUIRED_KEY_CAPABILITY=${REQUIRED_KEY_CAPABILITY:-"e a"}
USER_CONTROLLED_AUTHORIZED_KEYS=${USER_CONTROLLED_AUTHORIZED_KEYS:-%h/.ssh/authorized_keys}
STAGING_AREA=${STAGING_AREA:-"$LIB"/stage}

export GNUPGHOME

# make sure gpg home exists with proper permissions
mkdir -p -m 0700 "$GNUPGHOME"

case $COMMAND in
    'update-users'|'s')
	if [ "$1" ] ; then
	    unames="$@"
	else
	    unames=$(ls -1 "$MS_HOME"/authorized_user_ids)
	fi

	for uname in $unames ; do
	    MODE="authorized_keys"

	    log "----- user: $uname -----"

	    AUTHORIZED_USER_IDS="$MS_HOME"/authorized_user_ids/"$uname"
	    cacheDir="$STAGING_AREA"/"$uname"/user_keys
	    msAuthorizedKeys="$STAGING_AREA"/"$uname"/authorized_keys

            # make sure authorized_user_ids file exists
	    if [ ! -s "$AUTHORIZED_USER_IDS" ] ; then
		log "authorized_user_ids file for '$uname' is empty or does not exist."
		continue
	    fi

	    # set user-controlled authorized_keys file path
	    if [ "$USER_CONTROLLED_AUTHORIZED_KEYS" ] ; then
		userHome=$(getent passwd "$uname" | cut -d: -f6)
		userAuthorizedKeys=${USER_CONTROLLED_AUTHORIZED_KEYS/\%h/"$userHome"}
	    fi

	    # update authorized_keys
	    update_authorized_keys "$cacheDir" "$msAuthorizedKeys" "$userAuthorizedKeys"
	done

	log "----- done. -----"
	;;

    'gen-key'|'g')
	gen_key
	;;

    'publish-key'|'p')
	publish_key
	;;

    'trust-keys'|'t')
	if [ -z "$1" ] ; then
	    failure "you must specify at least one key to trust."
	fi
	for keyID ; do
	    trust_key "$keyID"
	done
	;;

    'update-user-userids'|'u')
	uname="$1"
	shift
	if [ -z "$uname" ] ; then
	    failure "you must specify user."
	fi
	if [ -z "$1" ] ; then
	    failure "you must specify at least one userid."
	fi
	AUTHORIZED_USER_IDS="$MS_HOME"/authorized_user_ids/"$uname"
	userKeysCacheDir="$STAGING_AREA"/"$uname"/user_keys
	for userID ; do
	    update_userid "$userID" "$userKeysCacheDir"
	done
	;;

    'help'|'h'|'?')
        usage
        ;;

    *)
        failure "Unknown command: '$COMMAND'
Type 'cereal-admin help' for usage."
        ;;
esac