#!/bin/sh

# Copyright (C) 2022 Simon Josefsson
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

set -e
set -u
set -x

# Tests privilege separation between Apache and the GSS-API
# credential, by setting up a local MIT Kerberos KDC, Apache2,
# gssproxy, and configure them so that a curl connection with GSS-API
# authentication succeeds.

if ! command -v ss && ! command -v netstat; then
    echo SKIP: $0: Required tools 'ss' or 'netstat' missing...
    exit 77
fi

if ! command -v id || ! command -v hostname; then
    echo SKIP: $0: Required tools missing...
    exit 77
fi

if ! command -v dpkg; then
    echo SKIP: $0: Required 'dpkg' missing...
    exit 77
fi

for pkg in krb5-kdc krb5-admin-server apache2 libapache2-mod-auth-gssapi gssproxy curl; do
    if ! dpkg -V $pkg; then
	echo SKIP: $0: Required package $pkg not installed...  try this:
	echo apt-get install krb5-kdc krb5-admin-server apache2 libapache2-mod-auth-gssapi gssproxy curl
	exit 77
    fi
done

service apache2 stop
service krb5-kdc stop
if command -v systemctl; then
    service gssproxy stop
else
    killall gssproxy || true
fi

export PATH=$PATH:/sbin:/usr/sbin

tail --pid=$$ -F /var/log/syslog &

trap '
     set +e;
     kdestroy
     service apache2 stop
     service krb5-kdc stop
     for f in /tmp/out-*;
         do echo ----- BEGIN FILE $f -----
	 cat $f
     done
     tail -v /var/log/apache2/error.log /var/log/apache2/access.log
     mv /etc/krb5kdc/kdc.conf-gssproxysave /etc/krb5kdc/kdc.conf
     mv /etc/krb5.conf-gssproxysave /etc/krb5.conf
     mv /etc/gssproxy/gssproxy.conf-gssproxysave /etc/gssproxy/gssproxy.conf
     rm /etc/gssproxy/80-gssproxy-autopkgtest.conf /etc/apache2/conf-enabled/gssproxy-autopkgtest.conf /etc/systemd/system/apache2.service.d/gssproxy-autopkgtest.conf /var/www/html/gssproxy-autopkgtest/foo /var/lib/krb5kdc/gssproxy-principal* /var/lib/krb5kdc/gssproxy-stash /etc/gssproxy/httpd.keytab
     test -d /etc/systemd/system/apache2.service.d && rmdir /etc/systemd/system/apache2.service.d
     rmdir /var/www/html/gssproxy-autopkgtest
     ' 0 INT QUIT ABRT PIPE TERM

my_user=`id -un`
my_hostname=`hostname -f`
my_domainname=`hostname -d`

test -f /etc/krb5kdc/kdc.conf-gssproxysave \
    || cp /etc/krb5kdc/kdc.conf /etc/krb5kdc/kdc.conf-gssproxysave
cat<<EOF > /etc/krb5kdc/kdc.conf
[realms]
    GSSPROXY.EXAMPLE.ORG = {
        database_name = /var/lib/krb5kdc/gssproxy-principal
        key_stash_file = /etc/krb5kdc/gssproxy-stash
        kdc_ports = 17643
        kdc_tcp_ports = 17643
        default_principal_flags = +preauth
    }
EOF

test -f /etc/krb5.conf-gssproxysave \
    || cp /etc/krb5.conf /etc/krb5.conf-gssproxysave
cat<<EOF > /etc/krb5.conf
[libdefaults]
	default_realm = GSSPROXY.EXAMPLE.ORG

[domain_realm]
	.$my_domainname = GSSPROXY.EXAMPLE.ORG

[realms]
	GSSPROXY.EXAMPLE.ORG = {
		kdc = $my_hostname:17643
	}
EOF

kdb5_util -P foo create -s
kadmin.local addprinc -randkey HTTP/$my_hostname
kadmin.local addprinc -pw bar $my_user
kadmin.local ktadd -k /etc/gssproxy/httpd.keytab HTTP/$my_hostname

service krb5-kdc start

i=0
while ! (ss -na || netstat -na) | grep 0.0.0.0:17643 | grep LISTEN; do
    i=`expr $i + 1`
    test "$i" = "10" && exit 1
    sleep 1
done

kdestroy
echo bar | kinit $my_user

test -f /etc/gssproxy/gssproxy.conf-gssproxysave \
    || cp /etc/gssproxy/gssproxy.conf /etc/gssproxy/gssproxy.conf-gssproxysave
cat<<EOF > /etc/gssproxy/gssproxy.conf
[gssproxy]
debug_level = 2
EOF

cat<<EOF > /etc/gssproxy/80-gssproxy-autopkgtest.conf
[service/HTTP]
  mechs = krb5
  cred_store = keytab:/etc/gssproxy/httpd.keytab
  cred_store = ccache:/var/lib/gssproxy/clients/krb5cc_%U
  euid = www-data
EOF
if ! command -v systemctl; then
cat<<EOF >> /etc/gssproxy/80-gssproxy-autopkgtest.conf
[service/HTTP2]
  mechs = krb5
  cred_store = keytab:/etc/gssproxy/httpd.keytab
  cred_store = ccache:/var/lib/gssproxy/clients/krb5cc_%U
  euid = root
EOF
fi

KRB5RCACHEDIR=/var/lib/gssproxy/rcache /usr/sbin/gssproxy -i --debug-level=2 > /tmp/out-gssproxy-out 2> /tmp/out-gssproxy-err &

cat <<EOF > /etc/apache2/conf-enabled/gssproxy-autopkgtest.conf
<Location /gssproxy-autopkgtest>
  AuthType GSSAPI
  AuthName "GSSAPI Login"
  Require valid-user
</Location>
EOF

if command -v systemctl; then
    mkdir -p /etc/systemd/system/apache2.service.d
    cat<<EOF > /etc/systemd/system/apache2.service.d/gssproxy-autopkgtest.conf
[Service]
Environment=GSS_USE_PROXY=1
EOF
    systemctl daemon-reload

    service apache2 start
else
    GSS_USE_PROXY=1 apachectl start
fi

mkdir -p /var/www/html/gssproxy-autopkgtest
echo Ossifrage > /var/www/html/gssproxy-autopkgtest/foo

curl --verbose --negotiate -u : http://$my_hostname/gssproxy-autopkgtest/foo > /tmp/out-curl-out 2> /tmp/out-curl-err

grep Ossifrage /tmp/out-curl-out

echo PASS: $0

exit 0
