#!/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
  show-fingerprint (f)                  show server's host key fingerprint
  publish-key (p)                       publish server's host key to keyserver
  trust-key (t) KEYID [LEVEL]           set owner trust for keyid
  help (h,?)                            this help

EOF
}

# generate server gpg key
gen_key() {
    local hostName

    hostName=${1:-$(hostname --fqdn)}
    service=${SERVICE:-"ssh"}
    userID="${service}://${hostName}"

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

    # set key defaults
    KEY_TYPE=${KEY_TYPE:-"RSA"}
    KEY_LENGTH=${KEY_LENGTH:-"2048"}
    KEY_USAGE=${KEY_USAGE:-"auth"}
    KEY_EXPIRE=${KEY_EXPIRE:-"0"}
    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? ($KEY_EXPIRE) " KEY_EXPIRE; KEY_EXPIRE=${KEY_EXPIRE:-"0"}

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

    # add the revoker field if requested
    # FIXME: the "1:" below assumes that $REVOKER's key is an RSA key.  why?
    # FIXME: why is this marked "sensitive"?  how will this signature ever
    # be transmitted to the expected revoker?
    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

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

%commit
%echo done
EOF
)

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

    # output the server fingerprint
    fingerprint_server_key "=${userID}"

    # find the key fingerprint of the server primary key
    keyID=$(gpg --list-key --with-colons --with-fingerprint "=${userID}" | \
	grep '^fpr:' | head -1 | cut -d: -f10)

    # write the key to the file
    # NOTE: assumes that the primary key is the proper key to use
    (umask 077 && gpgsecret2ssh "$keyID" > "${MS_HOME}/ssh_host_rsa_key")
    log "Private SSH host key output to file: ${MS_HOME}/ssh_host_rsa_key"
}

# gpg output key fingerprint
fingerprint_server_key() {
    local ID

    if [ -z "$1" ] ; then
	ID="$1"
    else
	ID="=ssh://$(hostname --fqdn)"
    fi

    gpg --fingerprint --list-secret-keys "$ID"
}

########################################################################
# 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"}
AUTHORIZED_USER_IDS=${AUTHORIZED_USER_IDS:-"%h/.config/monkeysphere/authorized_user_ids"}
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
	    # get users from command line
	    unames="$@"
	else
	    # or just look at all users if none specified
	    unames=$(getent passwd | cut -d: -f1)
	fi

	# loop over users
	for uname in $unames ; do
	    MODE="authorized_keys"

	    # check all specified users exist
	    if ! getent passwd "$uname" >/dev/null ; then
		error "----- unknown user '$uname' -----"
		continue
	    fi

	    # set authorized_user_ids variable,
	    # translate ssh-style path variables
	    authorizedUserIDs=$(translate_ssh_variables "$uname" "$AUTHORIZED_USER_IDS")

	    # skip user if authorized_user_ids file does not exist
	    if [ ! -f "$authorizedUserIDs" ] ; then
		continue
	    fi

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

	    # temporary authorized_keys file
	    AUTHORIZED_KEYS=$(mktemp)

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

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

	    # add user-controlled authorized_keys file path if specified
	    if [ "$USER_CONTROLLED_AUTHORIZED_KEYS" != '-' ] ; then
		userAuthorizedKeys=$(translate_ssh_variables "$uname" "$USER_CONTROLLED_AUTHORIZED_KEYS")
		if [ -f "$userAuthorizedKeys" ] ; then
		    log -n "adding user's authorized_keys file... "
		    cat "$userAuthorizedKeys" >> "$AUTHORIZED_KEYS"
		    loge "done."
		fi
	    fi

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

	    log "authorized_keys file updated."
	done
	;;

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

    'show-fingerprint'|'f')
	fingerprint_server_key "$@"
	;;

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

    'trust-key'|'trust-key'|'t')
	trust_key "$@"
	;;

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

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

exit "$ERR"