#! /bin/sh
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2021 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.

echo "running defines.sh"
. $SRCDIR/scripts/defines.sh

if test $AUTOCA = autocano; then 
	echo "Automatic CA overlay not available, test skipped"
	exit 0
fi 

if test $BACKEND = ldif ; then
	# autoca tries to modify an entry in a search response,
	# which deadlocks because the tree is readlocked by the search.
	echo "Test does not support $BACKEND backend, test skipped"
	exit 0
fi

CFDIR=$TESTDIR/slapd.d

mkdir -p $TESTDIR $CFDIR $DBDIR1

$SLAPPASSWD -g -n >$CONFIGPWF

#
# Test operation of autoca:
# - configure over ldap without TLS
# - populate over ldap
# - add host entry
# - add autoca overlay
# - generate server and user certs
# - check for TLS operation
#

echo "Starting slapd on TCP/IP port $PORT1..."
. $CONFFILTER $BACKEND < $DYNAMICCONF > $CONFLDIF
$SLAPADD -F $CFDIR -n 0 -l $CONFLDIF
$SLAPD -F $CFDIR -h $URIP1 -d $LVL > $LOG1 2>&1 &
PID=$!
if test $WAIT != 0 ; then
    echo PID $PID
    read foo
fi
KILLPIDS="$PID"
cd $TESTWD

sleep 1

echo "Using ldapsearch to check that slapd is running..."
for i in 0 1 2 3 4 5; do
	$LDAPSEARCH -s base -b "" -H $URIP1 \
		'objectclass=*' > /dev/null 2>&1
	RC=$?
	if test $RC = 0 ; then
		break
	fi
	echo "Waiting 5 seconds for slapd to start..."
	sleep 5
done

if test $RC != 0 ; then
	echo "ldapsearch failed ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi

echo "Adding schema and databases on slapd..."
$LDAPADD -D cn=config -H $URIP1 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
include: file://$ABS_SCHEMADIR/core.ldif

include: file://$ABS_SCHEMADIR/cosine.ldif

include: file://$ABS_SCHEMADIR/inetorgperson.ldif

include: file://$ABS_SCHEMADIR/openldap.ldif

include: file://$ABS_SCHEMADIR/nis.ldif
EOF
RC=$?
if test $RC != 0 ; then
	echo "ldapadd failed for schema config ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi

nullExclude="" nullOK=""
test $BACKEND = null && nullExclude="# " nullOK="OK"

if [ "$BACKENDTYPE" = mod ]; then
	$LDAPADD -D cn=config -H $URIP1 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: $TESTWD/../servers/slapd/back-$BACKEND
olcModuleLoad: back_$BACKEND.la
EOF
	RC=$?
	if test $RC != 0 ; then
		echo "ldapadd failed for backend config ($RC)!"
		test $KILLSERVERS != no && kill -HUP $KILLPIDS
		exit $RC
	fi
fi

$LDAPADD -D cn=config -H $URIP1 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
dn: olcDatabase={1}$BACKEND,cn=config
objectClass: olcDatabaseConfig
${nullExclude}objectClass: olc${BACKEND}Config
olcDatabase: {1}$BACKEND
olcSuffix: $BASEDN
${nullExclude}olcDbDirectory: $DBDIR1
olcRootDN: $MANAGERDN
olcRootPW: $PASSWD
EOF
RC=$?
if test $RC != 0 ; then
	echo "ldapadd failed for database config ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi

if test $INDEXDB = indexdb ; then
	$LDAPMODIFY -D cn=config -H $URIP1 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
dn: olcDatabase={1}$BACKEND,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: objectClass,entryUUID,entryCSN eq
olcDbIndex: cn,uid pres,eq,sub
EOF
	RC=$?
	if test $RC != 0 ; then
		echo "ldapadd modify for database config ($RC)!"
		test $KILLSERVERS != no && kill -HUP $KILLPIDS
		exit $RC
	fi
fi

echo "Using ldapadd to populate slapd..."
$LDAPADD -D "$MANAGERDN" -H $URIP1 -w $PASSWD -f $LDIFORDERED \
	>> $TESTOUT 2>&1
RC=$?
if test $RC != 0 ; then
	echo "ldapadd failed for database populate ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi

echo "Adding server entries to slapd..."
$LDAPADD -D "$MANAGERDN" -H $URIP1 -w $PASSWD <<EOF >> $TESTOUT 2>&1
dn: ou=Servers,$BASEDN
objectClass: organizationalUnit
ou: Servers

dn: cn=localhost,ou=Servers,$BASEDN
objectClass: device
objectClass: ipHost
cn: localhost
ipHostNumber: 127.0.0.1

dn: cn=www.example.com,ou=Servers,$BASEDN
objectClass: device
objectClass: ipHost
cn: localhost
ipHostNumber: 93.184.216.34
EOF
RC=$?
if test $RC != 0 ; then
	echo "ldapadd failed for database populate ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi

echo "Inserting autoca overlay on slapd..."
if [ "$AUTOCA" = autocamod ]; then
	$LDAPADD -D cn=config -H $URIP1 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: $TESTWD/../servers/slapd/overlays
olcModuleLoad: autoca.la
EOF
	RC=$?
	if test $RC != 0 ; then
		echo "ldapadd failed for moduleLoad ($RC)!"
		test $KILLSERVERS != no && kill -HUP $KILLPIDS
		exit $RC
	fi
fi
$LDAPMODIFY -D cn=config -H $URIP1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
dn: olcOverlay=autoca,olcDatabase={1}$BACKEND,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcAutoCAConfig
olcOverlay: autoca
olcAutoCAlocalDN: cn=localhost,ou=Servers,$BASEDN
EOF
RC=$?
if test $RC != 0 ; then
	echo "ldapmodify failed for autoca config ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi
echo "Using ldapsearch to retrieve CA cert..."
$LDAPSEARCH -b $BASEDN -D $MANAGERDN -H $URIP1 -w $PASSWD -s base \
	'objectclass=*' 'cACertificate;binary'  > $SEARCHOUT 2>&1
RC=$?

if test $RC != 0 ; then
	echo "ldapsearch failed ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi

echo "Setting up CA cert..."
echo "-----BEGIN CERTIFICATE-----" > $TESTDIR/cacert.pem
sed -e "/^dn:/d" -e "s/cACertificate;binary:://" -e "/^$/d" $SEARCHOUT >> $TESTDIR/cacert.pem
echo "-----END CERTIFICATE-----" >> $TESTDIR/cacert.pem

echo "Using ldapsearch to generate localhost cert..."
$LDAPSEARCH -b cn=localhost,ou=Servers,$BASEDN -D $MANAGERDN -H $URIP1 -w $PASSWD -s base \
	-A 'objectclass=*' 'userCertificate;binary' 'userPrivateKey;binary'  >> $TESTOUT 2>&1
RC=$?

if test $RC != 0 ; then
	echo "ldapsearch failed ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi

echo "Using ldapsearch to attempt TLS..."
unset LDAPNOINIT
LDAPTLS_CACERT=$TESTDIR/cacert.pem
export LDAPTLS_CACERT
$LDAPSEARCH -b $BASEDN -D $MANAGERDN -H $URIP1 -w $PASSWD -s base -ZZ \
	'objectclass=*' >> $TESTOUT 2>&1
RC=$?

if test $RC != 0 ; then
	echo "ldapsearch failed ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi

if test $WITH_SASL = no ; then
	echo "SASL support not available, skipping client cert authentication"
else
	# note - the attrs are being saved in raw DER form.
	# they need to be base64 encoded into PEM for most programs to use them
	# so we ignore those files for now.
	echo "Using ldapsearch to generate user cert..."
	$LDAPSEARCH -b "$BABSDN" -D $MANAGERDN -H $URIP1 -w $PASSWD -s base -ZZ \
		-T $TESTDIR -t 'objectclass=*' 'userCertificate;binary' 'userPrivateKey;binary'  >> $TESTOUT 2>&1
	RC=$?

	if test $RC != 0 ; then
		echo "ldapsearch failed ($RC)!"
		test $KILLSERVERS != no && kill -HUP $KILLPIDS
		exit $RC
	fi

	echo "Using ldapsearch to retrieve user cert..."
	$LDAPSEARCH -b "$BABSDN" -D $MANAGERDN -H $URIP1 -w $PASSWD -s base -ZZ \
		'objectclass=*' 'userCertificate;binary' > $SEARCHOUT 2>&1
	RC=$?

	if test $RC != 0 ; then
		echo "ldapsearch failed ($RC)!"
		test $KILLSERVERS != no && kill -HUP $KILLPIDS
		exit $RC
	fi

	echo "Setting up user cert..."
	echo "-----BEGIN CERTIFICATE-----" > $TESTDIR/usercert.pem
	sed -e "/^dn:/d" -e "/^ dc=com/d" -e "s/userCertificate;binary:://" -e "/^$/d" $SEARCHOUT >> $TESTDIR/usercert.pem
	echo "-----END CERTIFICATE-----" >> $TESTDIR/usercert.pem

	echo "Using ldapsearch to retrieve user key..."
	$LDAPSEARCH -b "$BABSDN" -D $MANAGERDN -H $URIP1 -w $PASSWD -s base -ZZ \
		'objectclass=*' 'userPrivateKey;binary' > $SEARCHOUT 2>&1
	RC=$?

	if test $RC != 0 ; then
		echo "ldapsearch failed ($RC)!"
		test $KILLSERVERS != no && kill -HUP $KILLPIDS
		exit $RC
	fi

	echo "Setting up user key..."
	echo "-----BEGIN PRIVATE KEY-----" > $TESTDIR/userkey.pem
	sed -e "/^dn:/d" -e "/^ dc=com/d" -e "s/userPrivateKey;binary:://" -e "/^$/d" $SEARCHOUT >> $TESTDIR/userkey.pem
	echo "-----END PRIVATE KEY-----" >> $TESTDIR/userkey.pem

	LDAPTLS_CERT=$TESTDIR/usercert.pem
	LDAPTLS_KEY=$TESTDIR/userkey.pem
	export LDAPTLS_CERT
	export LDAPTLS_KEY

	echo "Setting TLSVerifyClient to try..."
	$LDAPMODIFY -D cn=config -H $URIP1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
dn: cn=config
changetype: modify
replace: olcTLSVerifyClient
olcTLSVerifyClient: try
EOF
	RC=$?
	if test $RC != 0 ; then
		echo "ldapmodify failed for autoca config ($RC)!"
		test $KILLSERVERS != no && kill -HUP $KILLPIDS
		exit $RC
	fi

	$CLIENTDIR/ldapwhoami -Y EXTERNAL -H $URIP1 -ZZ

	if test $RC != 0 ; then
		echo "ldapwhoami failed ($RC)!"
		test $KILLSERVERS != no && kill -HUP $KILLPIDS
		exit $RC
	fi
fi

test $KILLSERVERS != no && kill -HUP $KILLPIDS

echo ">>>>> Test succeeded"

test $KILLSERVERS != no && wait

exit 0
