#!/bin/sh

set -e

sasluser="user$$"
saslpass="pass$$"
ldap_admin_pw="ldapadminpw$$"
ldap_domain="example.fake"
ldap_suffix="dc=example,dc=fake"
ldap_admin_dn="cn=admin,${ldap_suffix}"
MECHS="sasldb pam ldap"

cleanup() {
    if [ $? -ne 0 ]; then
        set +e
        echo "## Something failed, gathering logs"
        echo
        echo "## saslauthd"
        journalctl -u saslauthd.service
        echo
        echo "## syslog"
        tail -n 500 /var/log/syslog
        echo
        echo "## sasldb2 users"
        sasldblistusers2
        echo
        echo "## slapd"
        journalctl -u slapd
    fi
    set +e
    if [ -n "${sasluser}" ]; then
        saslpasswd2 -d "${sasluser}" > /dev/null 2>&1 || :
        userdel -r "${sasluser}" > /dev/null 2>&1 || :
    fi
    systemctl stop saslauthd || :
    rm -f /etc/saslauthd.conf || :
}

die() {
    echo "FAIL"
    echo "exit status: ${result}"
    echo "output:"
    echo "${output}"
    exit 1
}


trap cleanup EXIT

_configure_saslauthd() {
    sed -r -i "s,^MECHANISMS=.*,MECHANISMS=\"${1}\"," /etc/default/saslauthd
    if [ "${1}" = "ldap" ]; then
        cat > /etc/saslauthd.conf <<EOF
ldap_servers: ldap://127.0.0.1
ldap_auth_method: bind
ldap_search_base: ${ldap_suffix}
EOF
    fi
}

_populate_ldap_tree() {
    {
        cat <<EOF
dn: ou=People,${ldap_suffix}
ou: People
objectClass: organizationalUnit

EOF
    } | ldapadd -x -D "${ldap_admin_dn}" -w "${ldap_admin_pw}"

}

_add_ldap_user() {
    {
        cat <<EOF
dn: uid=${sasluser},ou=People,${ldap_suffix}
uid: ${sasluser}
objectClass: inetOrgPerson
objectClass: posixAccount
cn: ${sasluser}
sn: ${sasluser}
givenName: ${sasluser}
mail: ${sasluser}@${ldap_domain}
userPassword: $(slappasswd -s ${saslpass})
uidNumber: 10001
gidNumber: 10001
loginShell: /bin/bash
homeDirectory: /home/${sasluser}

EOF
    } | ldapadd -x -D "${ldap_admin_dn}" -w "${ldap_admin_pw}"
}

_setup_slapd() {
    # MUST use REAL TABS as delimiters below!
    debconf-set-selections << EOF
slapd	slapd/domain	string	${ldap_domain}
slapd	shared/organization	string	${ldap_domain}
slapd	slapd/password1	password	${ldap_admin_pw}
slapd	slapd/password2	password	${ldap_admin_pw}
EOF
    rm -rf /var/backups/*slapd* /var/backups/unknown*ldapdb
    dpkg-reconfigure -fnoninteractive -pcritical slapd 2>&1
    systemctl restart slapd # http://bugs.debian.org/1010678
    ldapmodify -Y EXTERNAL -H ldapi:/// 2>&1 <<EOF
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: stats

EOF
    _populate_ldap_tree
}

_setup_saslauthd_sasldb() {
    _configure_saslauthd "${1}"
    echo "${saslpass}" | saslpasswd2 -p -c "${sasluser}"
}

_setup_saslauthd_pam() {
    _configure_saslauthd "${1}"
    useradd "${sasluser}"
    echo "${sasluser}:${saslpass}" | chpasswd
}

_setup_saslauthd_ldap() {
    _configure_saslauthd "${1}"
    _setup_slapd
    _add_ldap_user
}

setup_saslauthd() {
    tries=5

    if echo "${MECHS}" | grep -qw "${1}"; then
        "_setup_saslauthd_${1}" "${1}"
    else
        echo "setup(): invalid mechanism \"${1}\""
        exit 1
    fi
    systemctl restart saslauthd
    echo -n "Waiting for saslauthd restart "
    while [ ${tries} -ne 0 ]; do
        echo -n "."
        if [ -S /var/run/saslauthd/mux ]; then
            echo
            break
        fi
        tries=$((tries-1))
        sleep 1s
    done
    if [ ${tries} -eq 0 ]; then
        echo "ERROR: saslauthd failed to start"
        return 1
    fi
}

override_systemd_throttling() {
    local svc="${1}"

    mkdir -p "/run/systemd/system/${svc}.service.d"
    cat > "/run/systemd/system/${svc}.service.d/override.conf" <<EOF
[Unit]
StartLimitIntervalSec=0
EOF
    systemctl daemon-reload
}

override_systemd_throttling saslauthd

for mech in ${MECHS}; do
    echo "Setting up saslauthd with mecanism ${mech}"
    setup_saslauthd ${mech}

    # test correct credentials
    echo -n "Authentication of user ${sasluser} with correct password should succeed... "
    result=0
    output=$(testsaslauthd -u "${sasluser}" -p "${saslpass}" 2>&1) || result=$?
    [ ${result} -ne 0 ] && die
    [ "${output}" != '0: OK "Success."' ] && die
    echo "OK"

    # test incorrect credentials
    echo -n "Authentication of unknown user ${sasluser}notexist should fail... "
    result=0
    output=$(testsaslauthd -u "${sasluser}"notexist -p "${saslpass}" 2>&1) || result=$?
    [ ${result} = 0 ] && die
    [ "${output}" != '0: NO "authentication failed"' ] && die
    echo "OK"

    echo -n "Authentication of user ${sasluser} with incorrect password should fail... "
    result=0
    output=$(testsaslauthd -u "${sasluser}" -p "${saslpass}"incorrect 2>&1) || result=$?
    [ ${result} = 0 ] && die
    [ "${output}" != '0: NO "authentication failed"' ] && die
    echo "OK"
    echo
done
