#! /bin/bash
### BEGIN INIT INFO
# Provides:          xapissl
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: XenAPI server SSL proxy
# Description:       This file will initialize stunnel for
#                    the XenAPI server.
### END INIT INFO
#
# chkconfig: 2345 91 01
# description: XenAPI server SSL proxy
# processname: stunnel
# config: /etc/xensource/stunnel.conf
# pidfile: /var/run/xapissl.pid

# Source function library.
. /lib/lsb/init-functions

ACCEPT=$2
PEMFILE="/etc/xensource/xapi-ssl.pem"
SSLPIDFILE="/var/run/xapissl.pid"
SSLCONFFILE="/etc/xensource/xapi-ssl.conf"
XAPISSL_LOCK="/var/lock/xapissl"
BACK_COMPAT=0
[ "${3}" = back_compat_6_5 ] && BACK_COMPAT=1

# Check if there is request to overwrite permfile
_PARAM="${4}"
if [ -n "${_PARAM}" ]; then
    _PEMFILE="${_PARAM#*=}"
    if [ -n "${_PEMFILE}" -a -e "${_PEMFILE}" ]; then
        PEMFILE="${_PEMFILE}"
    fi
fi

# If stunnel4 exists, use it. Otherwise use stunnel.
[ $(which stunnel4) ] && STUNNEL=$(which stunnel4)
[ -z ${STUNNEL} ] && STUNNEL=$(which stunnel)

STUNNEL_VERSION=$(${STUNNEL} -version 2>&1 | head -1 | awk '{print $2}')
ANCIENT_STUNNEL=0
[ '4.15' = "${STUNNEL_VERSION}" ] && ANCIENT_STUNNEL=1

. /etc/xensource-inventory

mgmt_ip() {
    if [ -n "${MANAGEMENT_INTERFACE}" ] &&
        [ "${MANAGEMENT_INTERFACE}" != "lo" ];
    then
        while [ true ]; do
            IP=`/sbin/ip address show dev ${MANAGEMENT_INTERFACE} | sed -ne 's/.*inet \([^ /]*\).*/\1/p'`
            if [ -n "$IP" ]; then
                echo "$IP"
                return
            else
                sleep 1
            fi
        done
    fi
}

writec () {
    echo "${1}" >> $SSLCONFFILE
} 

# Write out the stunnel config file. This requires the management
# interface, so it's done here rather than written statically.
writeconffile () {
    # Initial boilerplate which is valid whether the management
    # interface is enabled or disabled.
    . /etc/xensource-inventory

    # (This "good" list must match, or at least contain one of,
    #  the ciphersuites-good-outbound list in /etc/xapi.conf.)
    GOOD_CIPHERS='RSA+AES128-SHA256'
    BACK_COMPAT_CIPHERS='RSA+AES256-SHA:RSA+AES128-SHA:RSA+RC4-SHA:RSA+RC4-MD5:RSA+DES-CBC3-SHA'

    if [ -n "${STUNNEL_IDLE_TIMEOUT}" ]; then
        TIMEOUTSTR="TIMEOUTidle = ${STUNNEL_IDLE_TIMEOUT}"
    fi
    # If we must, allow SSLv3 for connections from old XenServers
    if [ $BACK_COMPAT = 1 ]; then
        EXTRA_CIPHERS=":${BACK_COMPAT_CIPHERS}"
    fi

    # First line is to overwrite, not append, so don't use writec
    echo "; Autogenerated by ${0}" > $SSLCONFFILE
    writec '; during xapi start-up.'
    writec '; '
    if [ ${ANCIENT_STUNNEL} = 0 ]; then
        # stunnel 4.56 fips demands sslVersion = TLSv1 (not "all" or even
        # "TLSv1.2") so we cannot use fips mode.
        writec 'fips = no'
    fi
cat >> $SSLCONFFILE <<EOF
pid = ${SSLPIDFILE}
socket = r:TCP_NODELAY=1
socket = a:TCP_NODELAY=1
socket = l:TCP_NODELAY=1
socket = r:SO_KEEPALIVE=1
socket = a:SO_KEEPALIVE=1
compression = zlib
${TIMEOUTSTR}

[xapi]
accept = ${ACCEPT}
connect = 80
cert = ${PEMFILE}
ciphers = !SSLv2:${GOOD_CIPHERS}${EXTRA_CIPHERS}
TIMEOUTclose = 0
options = NO_SSLv2
EOF
    if [ $BACK_COMPAT = 0 ]; then
        writec 'options = NO_SSLv3'
        # Ancient (pre 4.16) stunnel does not support sslVersion.
        if [ ${ANCIENT_STUNNEL} = 0 ]; then
            writec 'sslVersion = TLSv1.2'
        fi
    else
        if [ ${ANCIENT_STUNNEL} = 0 ]; then
            # stunnel does not let us specify "SSLv3 and TLSv1.2 only".
            # With multiple sslVersion entries, only the last is used.
            writec 'sslVersion = all'

            # If we had v5.06 or newer we would need to allow SSLv3 with
            # writec 'options -NO_SSLv3'
            # but all earlier versions choke on that option.
        fi
    fi
    return
}

start() {
    echo -n $"Starting xapi SSL: "
    if [ -e ${XAPISSL_LOCK} ]; then
        if [ -e ${SSLPIDFILE} ] && [ -e /proc/`cat ${SSLPIDFILE}` ]; then
            echo -n $"cannot start xapi SSL: xapi SSL is already running.";
            failure $"cannot start xapi SSL: xapi SSL already running.";
            echo
            return 1
        fi
    fi
    if [ ! -f ${PEMFILE} ]; then
        # generating a pem file
        CN=`hostname -f`

        case "${CN}" in
            localhost*)
                CN=`mgmt_ip`;;
            *.*)
                :;;
            *)
                CN=`mgmt_ip`;;
        esac
        "/opt/xensource/libexec/generate_ssl_cert" ${PEMFILE} ${CN}
    fi
    writeconffile
    start_daemon ${STUNNEL} ${SSLCONFFILE}
    RETVAL=$?

    echo
    [ $RETVAL -eq 0 ] && touch ${XAPISSL_LOCK};
    return $RETVAL
}

stop() {
    echo -n $"Stopping xapi SSL: "
    if [ ! -e ${XAPISSL_LOCK} ]; then
        echo -n $"cannot stop xapi SSL: xapi SSL is not running."
        failure $"cannot stop xapi: xapi SSL is not running."
        echo
        return 1;
    fi
    SSLPID=$(cat ${SSLPIDFILE})
    kill ${SSLPID}
    if [ $? -ne 0 ]; then
        echo -n $"stunnel already dead"
        failure $"stunnel already dead"
        return 1
    fi

    # Wait until the stunnel pid disappears
    RETRIES=180
    while [ ${RETRIES} -ne 0 ]; do
        RETRIES=$(( ${RETRIES} - 1 ))
        kill -0 $SSLPID 2> /dev/null
        if [ $? -eq 0 ]; then
            echo -n .
            kill ${SSLPID} # in case the first signal was missed
            sleep 1
        else
            echo
            rm -f ${XAPISSL_LOCK}
            return 0
        fi
    done

    # If stunnel still hasn't exited then kill it forcefully
    echo -n $"stunnel ($SSLPID) failed to terminate \
gracefully, terminating forcefully"
    failure $"stunnel ($SSLPID) failed to terminate \
gracefully, terminating forcefully"
    kill -9 ${SSLPID}
    rm -f ${XAPISSL_LOCK}
    return 1
}

status() {
    if [ -e ${XAPISSL_LOCK} ] &&
        [ -e ${SSLPIDFILE} ] &&
        [ -e /proc/`cat ${SSLPIDFILE}` ];
    then
        status_of_proc ${STUNNEL} `basename ${STUNNEL}` && exit 0 || exit $?
    else
        echo "stunnel is not running ... failed!"
        exit 1
    fi
}

restart() {
    stop
    start
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        restart
        ;;
    status)
        status
        ;;
    condrestart)
        [ -f ${XAPISSL_LOCK} ] && restart || :
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart}"
        exit 1
esac
