#!/bin/sh
### BEGIN INIT INFO
# Provides:          fetch-ldap-cert
# Required-Start:    $local_fs $remote_fs
# Required-Stop:     $local_fs $remote_fs
# Should-Start:      $network $syslog $named slapd
# Default-Start:     2 3 4 5
# Default-Stop:
# Short-Description: Fetch LDAP SSL public key from the server
# Description:
#   Start before krb5-kdc to give slapd time to become operational
#   before krb5-kdc try to connect to the LDAP server as a workaround
#   for #589915.
# X-Start-Before:    isc-dhcp-server krb5-kdc nslcd
### END INIT INFO
#
# Author: Petter Reinholdtsen <pere@hungry.com>
# Date:   2007-06-09

set -e

. /lib/lsb/init-functions

CERTFILE=/etc/ssl/certs/debian-edu-server.crt
BUNDLECRT=/etc/ssl/certs/debian-edu-bundle.crt
ROOTCACRT=/etc/ssl/certs/Debian-Edu_rootCA.crt

do_start() {

	# Locate LDAP server
	LDAPSERVER=$(debian-edu-ldapserver)
	LDAPPORT=636 # ldaps
	ERROR=false

	###
	### PHASE 1: RootCA / bundle-cert / LDAP server cert retrieval
	###

	if ( [ ! -f $CERTFILE ] || [ ! -f $ROOTCACRT ] ) && [ -f /etc/nslcd.conf ] &&
	    grep -q /etc/ssl/certs/debian-edu-server.crt /etc/nslcd.conf ; then

		# LDAP server host not known/found, bailing out...
		if [ -z "$LDAPSERVER" ] ; then
			msg="Failed to locate LDAP server"
			log_action_begin_msg "$msg"
			log_action_end_msg 1
			logger -t fetch-ldap-cert "$msg."
			return 1
		fi

		[ "$VERBOSE" != no ] && log_action_begin_msg "Fetching LDAP SSL certificate."

		# do an openssl connect to the LDAP server, and check whether its certificate
		# has been issued by the "Debian Edu RootCA", if not we are likely dealing with a
		# pre-Debian Edu 10 (aka buster) TJENER or with some other non-Debian-Edu LDAP
		# server.
		if echo | openssl s_client -connect "$LDAPSERVER:$LDAPPORT" 2>/dev/null | grep -q "Debian Edu RootCA" ; then

			# Since Debian Edu 10, the LDAP certificate (or the RootCA file) is distributed
			# over http (always via the host serving www.intern, by default: TJENER)
			#
			# We do an availability check for the webserver first, to provide proper
			# error reporting (see below). So, the following check merely discovers,
			# if the webserver is online at all.
			if curl -sfk --head -o /dev/null https://www.intern 2>/dev/null; then

				# Now let's see if the webserver has the "Debian Edu RootCA" file.
				# This has been the case for Debian Edu main servers (TJENER) since
				# Debian Edu 10.1.
				if curl -fk https://www.intern/Debian-Edu_rootCA.crt 1> $ROOTCACRT 2>/dev/null && \

				    grep -q CERTIFICATE $ROOTCACRT ; then

					# Obtained a RootCA-verified version of the LDAP server's server certificate.
					gnutls-cli --x509cafile $ROOTCACRT --save-cert=$CERTFILE.new $LDAPSERVER < /dev/null 1>/dev/null 2>/dev/null
					logger -t fetch-ldap-cert "Fetched rootCA certificate from www.intern."

					# If the host previously had got the BUNDLECERT file installed,
					# we make sure here to have it removed. From now on, the LTSP chroot
					# can operate on the ROOTCACRT file and the BUNDLECERT will never get
					# update anymore once the ROOTCACRT is available on www.intern.
					rm -f $BUNDLECRT
				else

					# If there is no Debian Edu RootCA available on www.intern, fallback to
					# debian-edu-bundle.crt download (an approach done by a Debian Edu 10.0
					# main server (aka TJENER) only and changed to RootCA provisioning in
					# in Debian Edu 10.1.

					# Drop the ROOTCACRT file, as it probably only contains some 404 http
					# error message in html.
					rm -f $ROOTCACRT

					# So, now let's see if the webserver has the "debian-edu-bundle.crt"
					# file. If so (and no Debian Edu RootCA file), then we are likely dealing
					# with a Debian Edu 10.0 main server.
					if curl -fk https://www.intern/debian-edu-bundle.crt 1> $BUNDLECRT 2>/dev/null && \
					    grep -q CERTIFICATE $BUNDLECRT ; then

						# Obtained a self-verified version of the LDAP server's server certificate.
						# (The BUNDLECERT file should already contain the LDAP server's certificate,
						# so having this cert file should allow us to successfully and "verified'ly"
						# connect to the LDAP server and let us retrieve that very same certificate).
						gnutls-cli --x509cafile $BUNDLECRT --save-cert=$CERTFILE.new $LDAPSERVER < /dev/null 1>/dev/null 2>/dev/null
						logger -t fetch-ldap-cert "Fetched bundle certificate from www.intern."
					else

						# We should never get here... If we do anyway, then something went
						# terribly wrong or the www.intern servicing server is misconfigured.

						# Drop the ROOTCACRT file, as it probably only contains some 404 http
						# error message in html.
						rm -f $BUNDLECRT

						logger -t fetch-ldap-cert "Failed to fetch certificates from www.intern."
					fi

				fi

			else

				# Report an error, if www.intern is down http-wise. This can happen and is probably
				# a temporary problem that needs an admin to fix it.
				log_action_end_msg 1
				logger -t fetch-ldap-cert "Failed to connect to www.intern, maybe the web server down."
				ERROR=true

			fi

		else

			# Fallback: Fetch LDAP certificate from a pre-Debian-Edu-10 (aka buster) LDAP server
			# (or some non-Debian-Edu LDAP server)
			/usr/share/debian-edu-config/tools/ldap-server-getcert $LDAPSERVER > $CERTFILE.new
			chmod 644 $CERTFILE.new
			logger -t fetch-ldap-cert "Fetched pre Buster LDAP server certificate."

			# FIXME: Add some error handling here:
			#   - LDAP server down
			#   - what-not-else...

		fi

		# By now, we should have obtained the LDAP server's CERTFILE (verified in two cases (10.0 or 10.1 TJENER),
		# simply downloaded from the LDAP server itself in the third case (pre-10.0 TJENER)
		if test -s $CERTFILE.new ; then
			mv $CERTFILE.new $CERTFILE
			[ "$VERBOSE" != no ] && log_action_end_msg 0
			if [ -f $BUNDLECRT ] || [ -f $ROOTCACRT ] ; then
				logger -t fetch-ldap-cert "Fetched and verified LDAP SSL certificate from $LDAPSERVER."
			else
				logger -t fetch-ldap-cert "Fetched LDAP SSL certificate from $LDAPSERVER."
			fi
		else

			# We obviously have failed in some other way, if the CERTFILE.new is empty (zero size)
			# Again, something went awfully wrong, if we end up here...
			rm -f $CERTFILE.new
			log_action_end_msg 1
			logger -t fetch-ldap-cert "Failed to fetch LDAP SSL certificate from $LDAPSERVER."
			ERROR=true

		fi

	fi

	###
	### PHASE 2: Deploy the obtained CERTFILE to LTSP chroots, if any are present.
	###

	if [ -d /opt/ltsp ] ; then

		# Loop over all to be found LTSP chroots...
		for ltsp_chroot in `find /opt/ltsp/ -mindepth 1 -maxdepth 1 -type d`; do

			if [ ! -d $ltsp_chroot/etc/ssl/certs/ ]; then
				# likely not a chroot dir, skipping...
				continue
			fi

			# Only install the CERTFILE into this chroot, if not already present...
			if [ ! -f $ltsp_chroot$CERTFILE ] && [ -f $ltsp_chroot/etc/nslcd.conf ] &&
			    grep -q /etc/ssl/certs/debian-edu-server.crt $ltsp_chroot/etc/nslcd.conf ; then

				# Copy the obtained CERTFILE into the LTSP chroot (containing the LDAP server's
				# certificate.
				log_action_begin_msg "Copying LDAP SSL certificate to ltsp-chroot $ltsp_chroot "
				[ "$VERBOSE" != no ] &&
				if test -s $CERTFILE; then
					cp $CERTFILE $ltsp_chroot$CERTFILE
					[ "$VERBOSE" != no ] && log_action_end_msg 0
				else
					log_action_end_msg 1
					ERROR=true
				fi
			fi

			if [ ! -f $ltsp_chroot$ROOTCACRT ]; then

				if test -e $ROOTCACRT; then

					# If we retrieved it, we also copy the obtained ROOTCACRT into the LTSP chroot
					# (containing the self-built rootCA of the Debian Edu site).
					log_action_begin_msg "Copying Debian Edu rootCA certificate to ltsp-chroot $ltsp_chroot "
					if test -s $ROOTCACRT; then

						# If the chroot previously had got the BUNDLECERT file installed,
						# we should make sure here to have it removed. From now on, the LTSP chroot
						# can operate on the ROOTCACRT file and the BUNDLECERT will never get
						# update anymore once the ROOTCACRT is available on www.intern.
						rm -f $ltsp_chroot$BUNDLECRT
						cp $ROOTCACRT $ltsp_chroot$ROOTCACRT
						[ "$VERBOSE" != no ] && log_action_end_msg 0

					else
						log_action_end_msg 1
						ERROR=true
					fi

				fi

			fi

			if [ ! -f $ltsp_chroot$BUNDLECRT ] && [ ! -f $ltsp_chroot$ROOTCACRT ]; then

				if test -e $BUNDLECRT; then
					# If we talked to a Debian Edu 10.0 main server (aka TJENER) above, then we
					# don't have the ROOTCACRT. We copy the BUNDLECRT file into the LTSP chroot
					# instead (containing all certificates ever issued for the Debian Edu site).
					# This is just a fallback, in fact, we need the Debian Edu RootCA.

					# If you end up here, then please upgrade your Debian Edu 10.0 server to a
					# a newer version (Debian Edu 10.1 and beyond).
					log_action_begin_msg "Copying TLS certificate bundle to ltsp-chroot $ltsp_chroot "
					if test -s $BUNDLECRT; then
						cp $BUNDLECRT $ltsp_chroot$BUNDLECRT
						[ "$VERBOSE" != no ] && log_action_end_msg 0
					else
						log_action_end_msg 1
						ERROR=true
					fi
				fi

			fi

		done
	fi

	if $ERROR; then
		return 1
	fi
}

case "$1" in
	start)
		do_start
		;;
	stop)
		;;
	restart|force-reload)
		;;
	*)
		echo "Usage: $0 {start|stop|restart|force-reload}"
		exit 2
esac
exit 0
