#!/bin/bash
#
# Univention Directory Replication
#  re-synchronize the local LDAP directory
#
# SPDX-FileCopyrightText: 2001-2025 Univention GmbH
# SPDX-License-Identifier: AGPL-3.0-only
# Univention LDAP Listener replication module

eval "$(univention-config-registry shell)"

UDL='univention-directory-listener'
LOG='/var/log/univention/ldap-replication-resync.log'

die () {
	echo "$1" >&2
	exit ${2:-1}
}

display_header () {
	echo ""
	echo "univention-directory-replication-resync: Resync local LDAP using a failed.ldif"
	echo "copyright (c) 2001-2025 Univention GmbH, Germany"
	echo "usage: $0 <failed.ldif>"
	echo ""
	exit ${1:-0}
}

getdns () {
	ldapsearch-wrapper <"$1" |
	while IFS=' ' read k v
	do
		case "$k" in
		dn::) echo "$v" | base64 -d ;;
		dn:) echo "$v"
		esac
	done | sort -u
}

case "${1:-}" in
-h|--help) display_header 0 ;;
esac
[ -n "${1:-}" ] || die "Missing argument: failed.ldif"
[ -f "$1" ] || die "Not a regular file: $1"
[ -r "$1" ] || die "File not readable: $1"

if ! pidof slapd > /dev/null 2>&1
	then
	echo "No slapd-process found, resync is not possible."
	echo "run /etc/init.d/slapd start"
	exit 1
fi

date >>"$LOG"
echo "Try to sync changes stored in $1 into local LDAP" | tee -a "$LOG"

try_stop_listener () {
	local pid=$$ lpid
	lpid=$(systemctl show --property MainPID --value univention-directory-listener.service)
	while pid="$(ps -o ppid:1= "$pid")"
	do
		case "$pid" in
		""|1) break ;;
		"$lpid")
			echo "Running from $UDL (PID $lpid) itself - skipping shutdown."
			return 0
			;;
		esac
	done
	echo -n "Shutting down ${UDL}."
	systemctl stop univention-directory-listener
	echo " DONE."
}
try_stop_listener
fuser -v "$1" && die "File still in use: $1"
if [ ! -s "$1" ]
then
	rm -f "$1"
	echo "systemctl stop univention-directory-listener; systemctl start univention-directory-listener" | at now
	die "Empty file removed: $1" 0
fi


echo "replay stored changes ..."
faileddns="$(mktemp)"
secret_file="$(mktemp)"
cleanup_secret_file() { rm -f "$secret_file" >>"$LOG" 2>&1; trap - EXIT; }
trap cleanup_secret_file EXIT
echo -n "$(cut -d\" -f2 /etc/ldap/rootpw.conf)" > "$secret_file"
if ldapmodify -x -y "$secret_file" -D "cn=update,${ldap_base}" -c -S "${faileddns}" -f "$1" >>"$LOG" 2>&1
then
	cleanup_secret_file
	echo ""
	dst="/var/lib/univention-directory-replication/replayed.ldif_$(date +%F-%X)"
	echo "Restored modifications successfully, the LDIF file will be moved to $dst"
	rm "${faileddns}"
	mv "$1" "$dst"
	chmod 600 "$dst"
	echo "systemctl stop univention-directory-listener; systemctl start univention-directory-listener" | at now
	exit 0
else
	cleanup_secret_file
	echo "some DNs have failed and have to be synced manually:"
	getdns "${faileddns}"
	echo ""
	echo "You can find the failed modifications in ${faileddns}"
	echo "Check them for being sync with the Primary LDAP, then delete $1 and start the listener again typing:"
	echo "systemctl start univention-directory-listener"
	exit 1
fi
