#!/bin/sh

# Configure glexec on package installation or upgrade.
# This script is intended for use from a %postinst script, although
# it can be used at any time by the system administrator
#
# This script will configure
# /etc/lcmaps/lcmaps-glexec.db
# /etc/glexec.conf

# Defaults
logfile=
lclogfile=
whitelist=
loglevel=3
actionid=http://glite.org/xacml/action/execute
resourceid=http://authz-interop.org/xacml/resource/resource-type/wn


# Synopsis:
usage() {
    cat >&2 <<EOF
Configure glexec/LCMAPS based on authorisation framework.

Usage: $0 [options] <framework> [ endpoint ... ]

Options:
 -h,        --help             show this helptext
 -l FILE,   --log-file         file to send logging to (default is use syslog)
 -c FILE,   --lcmaps-log-file  file to log LCMAPS messages to.
 -L {0-5},  --log-level        the gLExec and LCMAPS level of verbosity in
                               logging (default $loglevel)
 -w UIDs,   --white-list       comma-separated list of users that may 
                               use glexec
 -A URI,    --pepc-actionid    the action ID to request from the ARGUS
                               framework (default $actionid)
 -R URI,    --pepc-resourceid  the resource ID to request from the ARGUS
                               framework (default $resourceid)

For package maintainers:
 -o FILE,   --config-file      The name of the config file to write instead of
                               /etc/glexec.conf.
 -d FILE,   --lcmaps-db        The name of the LCMAPS db file, instead of
                               /etc/lcmaps/lcmaps-glexec.db

The framework is one of:
 scas  - the Site Central Authorisation System
 argus - the ARGUS framework
 local - no central authorisation

For 'scas' and 'argus' one or more endpoints are required.
EOF

}

# variables

# full path of the configuration files
lcmapsdb="/etc/lcmaps/lcmaps-glexec.db"
lcmapsdbdir=`dirname "$lcmapsdb"`
glexecconf="/etc/glexec.conf"


plugin_exists()	{
    for plugin in "$@" ; do
	# Note: test with -f not with -l to test the target, not the symlink.
	test -f "/usr/lib64/lcmaps/$plugin" || \
	    echo "Warning: plugin \"$plugin\" appears not to be installed" >&2
    done
}


scasconfig() {

    sep=
    scasendpoints=
    for i in "$@" ; do
	scasendpoints="$scasendpoints$sep\" --endpoint $i\""
	sep="
             "
    done
    
    # Test we have at least on endpoint
    test -z "$scasendpoints" && {
	echo "Error: need to know at least one SCAS endpoint" >&2
	exit 1
    }

    # Make sure the directory exists before creating the file
    test -d "$lcmapsdbdir" || mkdir -p "$lcmapsdbdir"

    # Test plugins exist
    plugin_exists lcmaps_verify_proxy.mod lcmaps_scas_client.mod

    # Create lcmaps.db file
    cat > $lcmapsdb <<EOF
# LCMAPS config file for glexec generated by $0 on `date`

# where to look for modules
path = /usr/lib64/lcmaps

# module definitions
verify_proxy = "lcmaps_verify_proxy.mod"
               " -certdir /etc/grid-security/certificates"
               " --allow-limited-proxy"

scasclient = "lcmaps_scas_client.mod"
             " -capath /etc/grid-security/certificates"
             $scasendpoints
             " -resourcetype wn"
             " -actiontype execute-now"

# policies
glexec_get_account:
verify_proxy -> scasclient

EOF
    if [ $? -ne 0 ];then
	echo "Creation of \"$lcmapsdb\" failed" >&2
	exit 1
    fi
}

argusconfig() {
    sep=
    argusendpoints=
    for i in "$@" ; do
	argusendpoints="$argusendpoints$sep\" --pep-daemon-endpoint-url $i\""
	sep="
              "
    done

    # Test we have at least on endpoint
    test -z "$argusendpoints" && {
	echo "Error: need to know at least one PEP-daemon endpoint" >&2
	exit 1
    }

    # Make sure the directory exists before creating the file
    test -d "$lcmapsdbdir" || mkdir -p "$lcmapsdbdir"

    # Test plugins exist
    plugin_exists lcmaps_verify_proxy.mod lcmaps_c_pep.mod

    # Try to figure out if we use curl with NSS. Note that this is not 100%
    # since curl is not necessarily installed and could also be a different
    # version from the installed libcurl.
    extraflag=""
    curl --version | grep -q NSS/ && {
	extraflag='              " --use-pilot-proxy-as-cafile"'
    }

    # Create lcmaps.db file
    cat > $lcmapsdb <<EOF
# LCMAPS config file for glexec generated by $0 on `date`

# where to look for modules
path = /usr/lib64/lcmaps

# module definitions
verify_proxy = "lcmaps_verify_proxy.mod"
               " -certdir /etc/grid-security/certificates"
               " --allow-limited-proxy"

pepc        = "lcmaps_c_pep.mod"
              $argusendpoints
              " -resourceid $resourceid"
              " -actionid $actionid"
              " -capath /etc/grid-security/certificates"
              " -pep-certificate-mode implicit"
$extraflag

# policies
glexec_get_account:
verify_proxy -> pepc
EOF
    if [ $? -ne 0 ];then
	echo "Creation of \"$lcmapsdb\" failed" >&2
	exit 1
    fi

}


localconfig() {

    # Make sure the directory exists before creating the file
    test -d "$lcmapsdbdir" || mkdir -p "$lcmapsdbdir"

    # Test plugins exist
    plugin_exists lcmaps_verify_proxy.mod lcmaps_localaccount.mod

    cat > $lcmapsdb <<EOF
# LCMAPS config file for glexec generated by $0 on `date`

# where to look for modules
path = /usr/lib64/lcmaps

# module definitions
verify_proxy = "lcmaps_verify_proxy.mod"
               " -certdir /etc/grid-security/certificates"
               " --allow-limited-proxy"

localaccount = "lcmaps_localaccount.mod"
               " -gridmapfile /etc/grid-security/grid-mapfile"

glexec_get_account:
verify_proxy -> localaccount

EOF
    if [ $? -ne 0 ];then
	echo "Creation of \"$lcmapsdb\" failed" >&2
	exit 1
    fi
}


# Start here.

if [ $# -lt 1 ]; then
    usage
    exit 1
fi

# parse command-line options

doscas=0
doargus=0
dolocal=0

while [ $# -gt 0 ] ; do
    case "$1" in
	-h|--help)
	    usage
	    exit 0
	    ;;
	-l|--log-file)
	    logfile="$2"
	    if [ "$(echo "$logfile"|cut -c1)" != "/" ];then
		echo "Logfile \"$logfile\" is not an absolute filename" >&2
		exit 1
	    fi
	    shift 2
	    ;;
	-c|--lcmaps-log-file) 
	    lclogfile="$2"
	    if [ "$(echo "$lclogfile"|cut -c1)" != "/" ];then
		echo "LCMAPS logfile \"$lclogfile\" is not an absolute filename" >&2
		exit 1
	    fi
	    shift 2
	    ;;
	-w|--white-list)
	    whitelist="$2"
	    shift 2
	    ;;
	-L|--log-level)
	    loglevel="$(echo "$2"|sed 's/[^0-9-]//g')"
	    if [ "x$loglevel" != "x$2" ];then
		echo "loglevel \"$2\" is not a number" >&2
		exit 1
	    fi
	    if [ $loglevel -lt 0 -o $loglevel -gt 5 ];then
		echo "loglevel \"$2\" is not in the interval [0-5]" >&2
		exit 1
	    fi
	    shift 2
	    ;;
	-A|--pepc-actionid)
	    actionid="$2"
	    shift 2
	    ;;
	-R|--pepc-resourceid)
	    resourceid="$2"
	    shift 2
	    ;;
	-o|--config-file)
	    glexecconf="$2"
	    if [ "$(echo "$glexecconf"|cut -c1)" != "/" ];then
		echo "Configfile \"$glexecconf\" is not an absolute filename" >&2
		exit 1
	    fi
	    shift 2
	    ;;
	-d|lcmaps-db)
	    lcmapsdb="$2"
	    if [ "$(echo "$lcmapsdb"|cut -c1)" != "/" ];then
		echo "LCMAPS db \"$lcmapsdb\" is not an absolute filename" >&2
		exit 1
	    fi
	    shift 2
	    ;;
	scas)
	    doscas=1
	    break
	    ;;
	argus)
	    doargus=1
	    break
	    ;;
	local)
	    dolocal=1
	    break
	    ;;
        *) 
	    echo "Unknown entry on commandline: \"$1\"" >&2
	    exit 1
	    ;;
    esac
done

# Check we got a framework
if [ `expr $doscas + $doargus + $dolocal` -ne 1 ];then
    echo "Need exactly one framework" >&2
    exit 1
fi

# Parse remaining command-line arguments
if [ $doscas -eq 1 ];then
    shift
    scasconfig "$@"
elif [ $doargus -eq 1 ];then
    shift
    argusconfig "$@"
elif [ $dolocal -eq 1 ];then
    localconfig
else
    echo "Error: unknown framework '$1'" >&2
    usage
    exit 1
fi

# write the glexec configuration file
: "${TMPDIR:=/tmp}"
dir=`(umask 077 && mktemp -d "$TMPDIR/glexecXXXXXX") 2>/dev/null` && \
    test -d "$dir" || {
    echo "Failed to create temporary directory" >&2
    exit 1
}
tmpglexecconf="$dir/glexecconf"

cat > $tmpglexecconf <<EOF
## glexec.conf file. See glexec.conf(5) for details, defaults etc.
##
## In switching mode (glexec binary executed (effectively) by root),
## this file should have permissions 0400, owned by user glexec,
## in logging-only mode, it should NOT be writable by group/others.
##

[glexec]
EOF
if [ $? -ne 0 ];then
    echo "Creation of \"$tmpglexecconf\" failed" >&2
    # remove tmpdir
    rm -rf "$dir"
    exit 1
fi

if [ ! -z "$logfile" ]; then
    cat >> $tmpglexecconf <<EOF
log_destination			    = file
log_file			    = $logfile
EOF
else
    cat >> $tmpglexecconf <<EOF
# log_destination		    = syslog
# log_file			    = /var/log/glexec/glexec_log
EOF
fi

cat >> $tmpglexecconf <<EOF    
log_level			    = $loglevel
# diff_syslog_levels		    = yes
# syslog_facility		    = LOG_DAEMON
# log_file_group		    = root

# user_identity_switch_by	    = glexec
use_lcas			    = no

EOF

if [ ! -z "$whitelist" ]; then
    cat >> $tmpglexecconf <<EOF    
user_white_list			    = $whitelist
EOF
else
    cat >> $tmpglexecconf <<EOF    
# user_white_list		    =
EOF
fi

cat >> $tmpglexecconf <<EOF    
# group_white_list		    = glexec
# linger			    = yes
# linger_as_payload		    = no
# force_payload_background	    = no
# close_fds                         = yes

# term_delay			    = 5
# kill_delay			    = 1
# use_setpgid			    = yes
# extra_sighandlers		    = yes

# epilogue                          =
# epilogue_user                     = root
# epilogue_group                    = root
# epilogue_timeout                  = 300

# target_lock_mechanism		    = flock
# input_lock_mechanism		    = flock
# create_target_proxy		    = yes

# certdir			    =
# vomsdir			    =
# backlog_path			    =

# omission_private_key_white_list   =
# preserve_env_variables	    =
# pedantic_security_checks	    = no
# prohibit_exec_via_symlink	    = no

# lcas_libdir			    =
# lcas_moduledir_sfx		    = /lcas
# lcas_db_file			    = /etc/lcas/lcas-glexec.db
EOF

# LCAS log file
if [ ! -z "$lclogfile" ]; then
    cat >> $tmpglexecconf <<EOF
lcas_log_file			    = $lclogfile
EOF
else
    cat >> $tmpglexecconf <<EOF
# lcas_log_file			    = /var/log/glexec/lcas_lcmaps.log
EOF
fi

cat >> $tmpglexecconf <<EOF
lcas_debug_level		    = 0

# lcmaps_libdir			    =
# lcmaps_moduledir_sfx		    = /lcmaps
EOF

# LCMAPS db file
if [ "$lcmapsdb" != "/etc/lcmaps/lcmaps-glexec.db" ]; then
    cat >> $tmpglexecconf <<EOF
lcmaps_db_file			    = $lcmapsdb
EOF
else
    cat >> $tmpglexecconf <<EOF
# lcmaps_db_file		    = /etc/lcmaps/lcmaps-glexec.db
EOF
fi

cat >> $tmpglexecconf <<EOF
# lcmaps_voms_verification	    = yes
EOF

# LCMAPS log file
if [ ! -z "$lclogfile" ]; then
    cat >> $tmpglexecconf <<EOF
lcmaps_log_file			    = $lclogfile
EOF
else
    cat >> $tmpglexecconf <<EOF
# lcmaps_log_file		    = /var/log/glexec/lcas_lcmaps.log
EOF
fi

cat >> $tmpglexecconf <<EOF
lcmaps_debug_level		    = $loglevel
# lcmaps_get_account_policy	    = glexec_get_account
EOF

mv $tmpglexecconf $glexecconf \
&& chown glexec $glexecconf \
&& chmod 400 $glexecconf \
&& {
    rc=0
} || {
    rc=1; echo "Cannot put \"$glexecconf\" in place" >&2
}
# Cleanup temporary dir
rm -rf "$dir"

