#!/bin/bash

# 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) [HOSTNAME]                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 user IDs for a user
  remove-user-userids (r) USER UID...   remove user IDs for a user
  help (h,?)                            this help

EOF
}

# generate server gpg key
gen_key() {
    local hostName

    hostName=${1:-$(hostname --fqdn)}

    # set key defaults
    KEY_TYPE=${KEY_TYPE:-"RSA"}
    KEY_LENGTH=${KEY_LENGTH:-"2048"}
    KEY_USAGE=${KEY_USAGE:-"auth"}
    cat <<EOF
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
EOF
    read -p "Key is valid for? ($EXPIRE) " EXPIRE; EXPIRE=${EXPIRE:-"0"}

    SERVICE=${SERVICE:-"ssh"}
    USERID=${USERID:-"$SERVICE"://"$hostName"}

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

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

Revoker: 1:$REVOKER sensitive
EOF
)
    fi

    echo "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
)

    log -n "generating server key... "
    echo "$keyParameters" | gpg --batch --gen-key
    loge "done."
}

########################################################################
# 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"}
CHECK_KEYSERVER=${CHECK_KEYSERVER:="true"}
REQUIRED_USER_KEY_CAPABILITY=${REQUIRED_USER_KEY_CAPABILITY:-"a"}
USER_CONTROLLED_AUTHORIZED_KEYS=${USER_CONTROLLED_AUTHORIZED_KEYS:-"%h/.ssh/authorized_keys"}

export GNUPGHOME

# make sure the monkeysphere home directory exists
mkdir -p "${MS_HOME}/authorized_user_ids"
# make sure gpg home exists with proper permissions
mkdir -p -m 0700 "$GNUPGHOME"
# make sure the authorized_keys directory exists
mkdir -p "${CACHE}/authorized_keys"

case $COMMAND in
    'update-users'|'update-user'|'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 -----"

	    # set variables for the user
	    AUTHORIZED_USER_IDS="${MS_HOME}/authorized_user_ids/${uname}"
	    # temporary authorized_keys file
	    AUTHORIZED_KEYS="${CACHE}/authorized_keys/${uname}.tmp"

            # make sure user's authorized_user_ids file exists
	    touch "$AUTHORIZED_USER_IDS"
	    # make sure the authorized_keys file exists and is clear
	    > "$AUTHORIZED_KEYS"

	    # skip if the user's authorized_user_ids file is empty
	    if [ ! -s "$AUTHORIZED_USER_IDS" ] ; then
		log "authorized_user_ids file for '$uname' is empty."
		continue
	    fi

	    # process authorized_user_ids file
	    log "processing authorized_user_ids file..."
	    process_authorized_user_ids

	    # add user-controlled authorized_keys file path if specified
	    if [ "$USER_CONTROLLED_AUTHORIZED_KEYS" != '-' ] ; then
		userHome=$(getent passwd "$uname" | cut -d: -f6)
		userAuthorizedKeys=${USER_CONTROLLED_AUTHORIZED_KEYS/\%h/"$userHome"}
		log -n "adding user's authorized_keys file... "
		cat "$userAuthorizedKeys" >> "$AUTHORIZED_KEYS"
		loge "done."
	    fi

	    # move the temp authorized_keys file into place
	    mv -f "${CACHE}/authorized_keys/${uname}.tmp" "${CACHE}/authorized_keys/${uname}"

	    log "authorized_keys file updated."
	done

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

    'gen-key'|'g')
	gen_key "$1"
	;;

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

    'trust-keys'|'trust-key'|'t')
	if [ -z "$1" ] ; then
	    failure "You must specify at least one key to trust."
	fi

	# process key IDs
	for keyID ; do
	    trust_key "$keyID"
	done
	;;

    'update-user-userids'|'update-user-userid'|'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 user ID."
	fi

	# set variables for the user
	AUTHORIZED_USER_IDS="$MS_HOME"/authorized_user_ids/"$uname"

        # make sure user's authorized_user_ids file exists
	touch "$AUTHORIZED_USER_IDS"

	# process the user IDs
	for userID ; do
	    update_userid "$userID"
	done

	log "Run the following to update user's authorized_keys file:"
	log "$PGRM update-users $uname"
	;;

    'remove-user-userids'|'remove-user-userid'|'r')
	uname="$1"
	shift
	if [ -z "$uname" ] ; then
	    failure "You must specify user."
	fi
	if [ -z "$1" ] ; then
	    failure "You must specify at least one user ID."
	fi

	# set variables for the user
	AUTHORIZED_USER_IDS="$MS_HOME"/authorized_user_ids/"$uname"

        # make sure user's authorized_user_ids file exists
	touch "$AUTHORIZED_USER_IDS"

	# process the user IDs
	for userID ; do
	    remove_userid "$userID"
	done

	log "Run the following to update user's authorized_keys file:"
	log "$PGRM update-users $uname"
	;;

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

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