summaryrefslogtreecommitdiffstats
path: root/tests/scripts
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 17:54:12 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 17:54:12 +0000
commitb527294153be3b79563c82c66102adc0004736c0 (patch)
tree9b423a224848441885190b5ea7cf0feb23510c9d /tests/scripts
parentInitial commit. (diff)
downloadopenldap-b527294153be3b79563c82c66102adc0004736c0.tar.xz
openldap-b527294153be3b79563c82c66102adc0004736c0.zip
Adding upstream version 2.6.7+dfsg.upstream/2.6.7+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rwxr-xr-xtests/scripts/all117
-rwxr-xr-xtests/scripts/conf.sh98
-rwxr-xr-xtests/scripts/confdirsync.sh18
-rwxr-xr-xtests/scripts/defines.sh465
-rwxr-xr-xtests/scripts/functions.sh22
-rw-r--r--tests/scripts/gdb.py85
-rwxr-xr-xtests/scripts/grandchild_wrapper.py72
-rwxr-xr-xtests/scripts/its-all52
-rwxr-xr-xtests/scripts/lloadd-all116
-rwxr-xr-xtests/scripts/lloadd/test000-rootdse118
-rwxr-xr-xtests/scripts/lloadd/test001-backend-issues219
-rwxr-xr-xtests/scripts/lloadd/test002-load175
-rwxr-xr-xtests/scripts/lloadd/test003-cnconfig481
-rwxr-xr-xtests/scripts/lloadd/test004-monitor365
-rwxr-xr-xtests/scripts/lloadd/test005-tls272
-rwxr-xr-xtests/scripts/lloadd/test006-sasl252
-rwxr-xr-xtests/scripts/lloadd/test007-coherence508
-rwxr-xr-xtests/scripts/monitor_data.sh42
-rwxr-xr-xtests/scripts/passwd-search133
-rwxr-xr-xtests/scripts/relay395
-rwxr-xr-xtests/scripts/setup_kdc.sh158
-rwxr-xr-xtests/scripts/sql-all70
-rwxr-xr-xtests/scripts/sql-test000-read568
-rwxr-xr-xtests/scripts/sql-test001-concurrency138
-rwxr-xr-xtests/scripts/sql-test900-write573
-rwxr-xr-xtests/scripts/sql-test901-syncrepl692
-rwxr-xr-xtests/scripts/start-server63
-rwxr-xr-xtests/scripts/start-server-nolog63
-rwxr-xr-xtests/scripts/start-server242
-rwxr-xr-xtests/scripts/start-server2-nolog42
-rwxr-xr-xtests/scripts/startup_nis_ldap_server.sh56
-rwxr-xr-xtests/scripts/test000-rootdse82
-rwxr-xr-xtests/scripts/test001-slapadd146
-rwxr-xr-xtests/scripts/test002-populate83
-rwxr-xr-xtests/scripts/test003-search155
-rwxr-xr-xtests/scripts/test004-modify122
-rwxr-xr-xtests/scripts/test005-modrdn300
-rwxr-xr-xtests/scripts/test006-acls667
-rwxr-xr-xtests/scripts/test007-slapmodify90
-rwxr-xr-xtests/scripts/test008-concurrency99
-rwxr-xr-xtests/scripts/test009-referral181
-rwxr-xr-xtests/scripts/test010-passwd189
-rwxr-xr-xtests/scripts/test011-glue-slapadd98
-rwxr-xr-xtests/scripts/test012-glue-populate83
-rwxr-xr-xtests/scripts/test013-language117
-rwxr-xr-xtests/scripts/test014-whoami468
-rwxr-xr-xtests/scripts/test015-xsearch272
-rwxr-xr-xtests/scripts/test016-subref197
-rwxr-xr-xtests/scripts/test017-syncreplication-refresh356
-rwxr-xr-xtests/scripts/test018-syncreplication-persist548
-rwxr-xr-xtests/scripts/test019-syncreplication-cascade487
-rwxr-xr-xtests/scripts/test020-proxycache643
-rwxr-xr-xtests/scripts/test021-certificate325
-rwxr-xr-xtests/scripts/test022-ppolicy782
-rwxr-xr-xtests/scripts/test023-refint276
-rwxr-xr-xtests/scripts/test024-unique845
-rwxr-xr-xtests/scripts/test025-limits1420
-rwxr-xr-xtests/scripts/test026-dn180
-rwxr-xr-xtests/scripts/test027-emptydn175
-rwxr-xr-xtests/scripts/test028-idassert273
-rwxr-xr-xtests/scripts/test029-ldapglue224
-rwxr-xr-xtests/scripts/test030-relay98
-rwxr-xr-xtests/scripts/test031-component-filter330
-rwxr-xr-xtests/scripts/test032-chain340
-rwxr-xr-xtests/scripts/test033-glue-syncrepl189
-rwxr-xr-xtests/scripts/test034-translucent807
-rwxr-xr-xtests/scripts/test035-meta739
-rwxr-xr-xtests/scripts/test036-meta-concurrency225
-rwxr-xr-xtests/scripts/test037-manage219
-rwxr-xr-xtests/scripts/test038-retcode112
-rwxr-xr-xtests/scripts/test039-glue-ldap-concurrency231
-rwxr-xr-xtests/scripts/test040-subtree-rename209
-rwxr-xr-xtests/scripts/test041-aci258
-rwxr-xr-xtests/scripts/test042-valsort229
-rwxr-xr-xtests/scripts/test043-delta-syncrepl552
-rwxr-xr-xtests/scripts/test044-dynlist1124
-rwxr-xr-xtests/scripts/test045-syncreplication-proxied867
-rwxr-xr-xtests/scripts/test046-dds575
-rwxr-xr-xtests/scripts/test047-ldap754
-rwxr-xr-xtests/scripts/test048-syncrepl-multiproxy596
-rwxr-xr-xtests/scripts/test049-sync-config419
-rwxr-xr-xtests/scripts/test050-syncrepl-multiprovider794
-rwxr-xr-xtests/scripts/test051-config-undo117
-rwxr-xr-xtests/scripts/test052-memberof464
-rwxr-xr-xtests/scripts/test053-syncprov-glue517
-rwxr-xr-xtests/scripts/test054-syncreplication-parallel-load377
-rwxr-xr-xtests/scripts/test055-valregex117
-rwxr-xr-xtests/scripts/test056-monitor162
-rwxr-xr-xtests/scripts/test057-memberof-refint280
-rwxr-xr-xtests/scripts/test058-syncrepl-asymmetric2483
-rwxr-xr-xtests/scripts/test059-consumer-config451
-rwxr-xr-xtests/scripts/test060-mt-hot299
-rwxr-xr-xtests/scripts/test061-syncreplication-initiation674
-rwxr-xr-xtests/scripts/test062-config-delete183
-rwxr-xr-xtests/scripts/test063-delta-multiprovider619
-rwxr-xr-xtests/scripts/test064-constraint220
-rwxr-xr-xtests/scripts/test065-proxyauthz255
-rwxr-xr-xtests/scripts/test066-autoca345
-rwxr-xr-xtests/scripts/test067-tls304
-rwxr-xr-xtests/scripts/test068-sasl-tls-external129
-rwxr-xr-xtests/scripts/test069-delta-multiprovider-starttls581
-rwxr-xr-xtests/scripts/test070-delta-multiprovider-ldaps577
-rwxr-xr-xtests/scripts/test071-dirsync377
-rwxr-xr-xtests/scripts/test072-dsee-sync331
-rwxr-xr-xtests/scripts/test073-asyncmeta620
-rwxr-xr-xtests/scripts/test074-asyncmeta-concurrency226
-rwxr-xr-xtests/scripts/test075-dsee-persist421
-rwxr-xr-xtests/scripts/test076-authid-rewrite646
-rwxr-xr-xtests/scripts/test077-sasl-gssapi255
-rwxr-xr-xtests/scripts/test078-persistent-sessionlog652
-rwxr-xr-xtests/scripts/test079-proxy-timeout374
-rwxr-xr-xtests/scripts/test080-hotp295
-rwxr-xr-xtests/scripts/test081-totp143
-rwxr-xr-xtests/scripts/test081-totp.py182
-rwxr-xr-xtests/scripts/test082-remoteauth417
-rwxr-xr-xtests/scripts/test083-argon2159
-rwxr-xr-xtests/scripts/test084-deref94
-rwxr-xr-xtests/scripts/test085-homedir143
-rwxr-xr-xtests/scripts/test086-delta-consumer-config594
-rwxr-xr-xtests/scripts/test087-librewrite91
-rwxr-xr-xtests/scripts/test088-syncprov-glue-rwm574
121 files changed, 41768 insertions, 0 deletions
diff --git a/tests/scripts/all b/tests/scripts/all
new file mode 100755
index 0000000..c9528ee
--- /dev/null
+++ b/tests/scripts/all
@@ -0,0 +1,117 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+. $SRCDIR/scripts/defines.sh
+
+TB="" TN=""
+if test -t 1 ; then
+ TB=`$SHTOOL echo -e "%B" 2>/dev/null`
+ TN=`$SHTOOL echo -e "%b" 2>/dev/null`
+fi
+
+FAILCOUNT=0
+SKIPCOUNT=0
+SLEEPTIME=10
+
+# check for BSD vs GNU date
+date -j >/dev/null 2>&1
+RC=$?
+if [ $RC -ne 0 ]; then
+ DATEOPT="-d @"
+else
+ DATEOPT="-r "
+fi
+
+echo ">>>>> $(timer) Executing all LDAP tests for $BACKEND"
+
+if [ -n "$NOEXIT" ]; then
+ echo "Result Test" > $TESTWD/results
+fi
+
+for CMD in $SRCDIR/scripts/test*; do
+ case "$CMD" in
+ *~) continue;;
+ *.bak) continue;;
+ *.orig) continue;;
+ *.sav) continue;;
+ *.py) continue;;
+ *) test -f "$CMD" || continue;;
+ esac
+
+ # remove cruft from prior test
+ if test $PRESERVE = yes ; then
+ /bin/rm -rf $TESTDIR/db.*
+ else
+ /bin/rm -rf $TESTDIR
+ fi
+
+ BCMD=`basename $CMD`
+ if [ -x "$CMD" ]; then
+ MSG=">>>>> $(timer) Starting ${TB}$BCMD${TN} for $BACKEND..."
+ [ -n "$TESTINST" ] && echo "$MSG" >&2
+ echo "$MSG"
+ START=`date +%s`
+ if [ -n "$TESTINST" ]; then
+ $CMD 2>&1
+ else
+ $CMD
+ fi
+ RC=$?
+ END=`date +%s`
+
+ if test $RC -eq 0 ; then
+ MSG=">>>>> $(timer) Finished $BCMD for $BACKEND after $(( $END - $START )) seconds."
+ [ -n "$TESTINST" ] && echo "$MSG" >&2
+ echo "$MSG"
+ else
+ MSG=">>>>> $(timer) Failed $BCMD for $BACKEND after $(( $END - $START )) seconds"
+ [ -n "$TESTINST" ] && echo "$MSG" >&2
+ echo "$MSG"
+ FAILCOUNT=`expr $FAILCOUNT + 1`
+
+ if [ -n "$NOEXIT" ]; then
+ echo "Continuing."
+ else
+ echo "(exit $RC)"
+ exit $RC
+ fi
+ fi
+ else
+ MSG=">>>>> $(timer) Skipping ${TB}$BCMD${TN} for $BACKEND."
+ [ -n "$TESTINST" ] && echo "$MSG" >&2
+ echo "$MSG"
+ SKIPCOUNT=`expr $SKIPCOUNT + 1`
+ RC="-"
+ fi
+
+ if [ -n "$NOEXIT" ]; then
+ echo "$RC $BCMD" >> $TESTWD/results
+ fi
+
+# echo ">>>>> waiting $SLEEPTIME seconds for things to exit"
+# sleep $SLEEPTIME
+ echo ""
+done
+
+if [ -n "$NOEXIT" ]; then
+ if [ "$FAILCOUNT" -gt 0 ]; then
+ cat $TESTWD/results
+ echo "$FAILCOUNT tests for $BACKEND ${TB}failed${TN}. Please review the test log."
+ else
+ echo "All executed tests for $BACKEND ${TB}succeeded${TN}."
+ fi
+fi
+
+echo "$SKIPCOUNT tests for $BACKEND were ${TB}skipped${TN}."
diff --git a/tests/scripts/conf.sh b/tests/scripts/conf.sh
new file mode 100755
index 0000000..d166eba
--- /dev/null
+++ b/tests/scripts/conf.sh
@@ -0,0 +1,98 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+if [ x"$WITH_SASL" = x"yes" -a x"$USE_SASL" != x"no" ] ; then
+ SASL="sasl"
+ if [ x"$USE_SASL" = x"yes" ] ; then
+ USE_SASL=DIGEST-MD5
+ fi
+ SASL_MECH="\"saslmech=$USE_SASL\""
+else
+ SASL="nosasl"
+ SASL_MECH=
+fi
+sed -e "s/@BACKEND@/${BACKEND}/" \
+ -e "s/^#${BACKEND}#//" \
+ -e "/^#~/s/^#[^#]*~${BACKEND}~[^#]*#/#omit: /" \
+ -e "s/^#~[^#]*~#//" \
+ -e "s/@RELAY@/${RELAY}/" \
+ -e "s/^#relay-${RELAY}#//" \
+ -e "s/^#${BACKENDTYPE}#//" \
+ -e "s/^#${AC_TLS_TYPE}#//" \
+ -e "s/^#${AC_ldap}#//" \
+ -e "s/^#${AC_meta}#//" \
+ -e "s/^#${AC_asyncmeta}#//" \
+ -e "s/^#${AC_relay}#//" \
+ -e "s/^#${AC_sql}#//" \
+ -e "s/^#${RDBMS}#//" \
+ -e "s/^#${AC_accesslog}#//" \
+ -e "s/^#${AC_dds}#//" \
+ -e "s/^#${AC_deref}#//" \
+ -e "s/^#${AC_dynlist}#//" \
+ -e "s/^#${AC_homedir}#//" \
+ -e "s/^#${AC_memberof}#//" \
+ -e "s/^#${AC_pcache}#//" \
+ -e "s/^#${AC_ppolicy}#//" \
+ -e "s/^#${AC_refint}#//" \
+ -e "s/^#${AC_retcode}#//" \
+ -e "s/^#${AC_remoteauth}#//" \
+ -e "s/^#${AC_rwm}#//" \
+ -e "s/^#${AC_syncprov}#//" \
+ -e "s/^#${AC_translucent}#//" \
+ -e "s/^#${AC_unique}#//" \
+ -e "s/^#${AC_valsort}#//" \
+ -e "s/^#${INDEXDB}#//" \
+ -e "s/^#${MAINDB}#//" \
+ -e "s/^#${SASL}#//" \
+ -e "s/^#${ACI}#//" \
+ -e "s;@URI1@;${URI1};" \
+ -e "s;@URI2@;${URI2};" \
+ -e "s;@URI3@;${URI3};" \
+ -e "s;@URI4@;${URI4};" \
+ -e "s;@URI5@;${URI5};" \
+ -e "s;@URI6@;${URI6};" \
+ -e "s;@PORT1@;${PORT1};" \
+ -e "s;@PORT2@;${PORT2};" \
+ -e "s;@PORT3@;${PORT3};" \
+ -e "s;@PORT4@;${PORT4};" \
+ -e "s;@PORT5@;${PORT5};" \
+ -e "s;@PORT6@;${PORT6};" \
+ -e "s;@SURI1@;${SURI1};" \
+ -e "s;@SURI2@;${SURI2};" \
+ -e "s;@SURI3@;${SURI3};" \
+ -e "s;@SURI4@;${SURI4};" \
+ -e "s;@SURI5@;${SURI5};" \
+ -e "s;@SURI6@;${SURI6};" \
+ -e "s;@URIP1@;${URIP1};" \
+ -e "s;@URIP2@;${URIP2};" \
+ -e "s;@URIP3@;${URIP3};" \
+ -e "s;@URIP4@;${URIP4};" \
+ -e "s;@URIP5@;${URIP5};" \
+ -e "s;@URIP6@;${URIP6};" \
+ -e "s;@SURIP1@;${SURIP1};" \
+ -e "s;@SURIP2@;${SURIP2};" \
+ -e "s;@SURIP3@;${SURIP3};" \
+ -e "s;@SURIP4@;${SURIP4};" \
+ -e "s;@SURIP5@;${SURIP5};" \
+ -e "s;@SURIP6@;${SURIP6};" \
+ -e "s/@SASL_MECH@/${SASL_MECH}/" \
+ -e "s;@TESTDIR@;${TESTDIR};" \
+ -e "s;@TESTWD@;${TESTWD};" \
+ -e "s;@DATADIR@;${DATADIR};" \
+ -e "s;@SCHEMADIR@;${SCHEMADIR};" \
+ -e "s;@KRB5REALM@;${KRB5REALM};" \
+ -e "s;@KDCHOST@;${KDCHOST};" \
+ -e "s;@KDCPORT@;${KDCPORT};" \
+ -e "s;@TIMEOUT@;${TIMEOUT};" \
+ -e "/^#/d"
diff --git a/tests/scripts/confdirsync.sh b/tests/scripts/confdirsync.sh
new file mode 100755
index 0000000..25efb1e
--- /dev/null
+++ b/tests/scripts/confdirsync.sh
@@ -0,0 +1,18 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+sed -e "s/@BASEDN@/${BASEDN}/" \
+ -e "s/@MSAD_ADMINDN@/${MSAD_ADMINDN}/" \
+ -e "s/@MSAD_ADMINPW@/${MSAD_ADMINPW}/" \
+ -e "s/@MSAD_SUFFIX@/${MSAD_SUFFIX}/"
diff --git a/tests/scripts/defines.sh b/tests/scripts/defines.sh
new file mode 100755
index 0000000..670dea3
--- /dev/null
+++ b/tests/scripts/defines.sh
@@ -0,0 +1,465 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+umask 077
+
+TESTWD=`pwd`
+
+if [ -z "$STARTTIME" ]; then
+ STARTTIME=$(date +%s)
+fi
+export STARTTIME
+
+# per instance
+TESTDIR=${USER_TESTDIR-$TESTWD/testrun}
+BASEPORT=${SLAPD_BASEPORT-9010}
+if [ -n "$TESTINST" ]; then
+ TESTDIR="$TESTDIR.$TESTINST"
+ BASEPORT=`expr $BASEPORT + $TESTINST \* 10`
+fi
+
+# backends
+BACKLDAP=${AC_ldap-ldapno}
+BACKMETA=${AC_meta-metano}
+BACKASYNCMETA=${AC_asyncmeta-asyncmetano}
+BACKPERL=${AC_perl-perlno}
+BACKRELAY=${AC_relay-relayno}
+BACKSQL=${AC_sql-sqlno}
+ RDBMS=${SLAPD_USE_SQL-rdbmsno}
+ RDBMSWRITE=${SLAPD_USE_SQLWRITE-no}
+
+# overlays
+ACCESSLOG=${AC_accesslog-accesslogno}
+ARGON2=${AC_argon2-argon2no}
+AUDITLOG=${AC_auditlog-auditlogno}
+AUTOCA=${AC_autoca-autocano}
+CONSTRAINT=${AC_constraint-constraintno}
+DDS=${AC_dds-ddsno}
+DEREF=${AC_deref-derefno}
+DYNLIST=${AC_dynlist-dynlistno}
+HOMEDIR=${AC_homedir-homedirno}
+MEMBEROF=${AC_memberof-memberofno}
+OTP=${AC_otp-otpno}
+PROXYCACHE=${AC_pcache-pcacheno}
+PPOLICY=${AC_ppolicy-ppolicyno}
+REFINT=${AC_refint-refintno}
+REMOTEAUTH=${AC_remoteauth-remoteauthno}
+RETCODE=${AC_retcode-retcodeno}
+RWM=${AC_rwm-rwmno}
+SYNCPROV=${AC_syncprov-syncprovno}
+TRANSLUCENT=${AC_translucent-translucentno}
+UNIQUE=${AC_unique-uniqueno}
+VALSORT=${AC_valsort-valsortno}
+
+# misc
+WITH_SASL=${AC_WITH_SASL-no}
+USE_SASL=${SLAPD_USE_SASL-no}
+WITH_TLS=${AC_WITH_TLS-no}
+WITH_TLS_TYPE=${AC_TLS_TYPE-no}
+
+ACI=${AC_ACI_ENABLED-acino}
+SLEEP0=${SLEEP0-1}
+SLEEP1=${SLEEP1-7}
+SLEEP2=${SLEEP2-15}
+TIMEOUT=${TIMEOUT-8}
+
+# dirs
+PROGDIR="$OBJDIR/tests/progs"
+DATADIR=${USER_DATADIR-./testdata}
+SCHEMADIR=${USER_SCHEMADIR-./schema}
+case "$SCHEMADIR" in
+.*) ABS_SCHEMADIR="$TESTWD/$SCHEMADIR" ;;
+*) ABS_SCHEMADIR="$SCHEMADIR" ;;
+esac
+case "$SRCDIR" in
+.*) ABS_SRCDIR="$TESTWD/$SRCDIR" ;;
+*) ABS_SRCDIR="$SRCDIR" ;;
+esac
+export TESTDIR
+
+DBDIR1A=$TESTDIR/db.1.a
+DBDIR1B=$TESTDIR/db.1.b
+DBDIR1C=$TESTDIR/db.1.c
+DBDIR1D=$TESTDIR/db.1.d
+DBDIR1=$DBDIR1A
+DBDIR2A=$TESTDIR/db.2.a
+DBDIR2B=$TESTDIR/db.2.b
+DBDIR2C=$TESTDIR/db.2.c
+DBDIR2=$DBDIR2A
+DBDIR3=$TESTDIR/db.3.a
+DBDIR4=$TESTDIR/db.4.a
+DBDIR5=$TESTDIR/db.5.a
+DBDIR6=$TESTDIR/db.6.a
+SQLCONCURRENCYDIR=$DATADIR/sql-concurrency
+
+CLIENTDIR="$OBJDIR/clients/tools"
+#CLIENTDIR=/usr/local/bin
+
+# conf
+CONF=$DATADIR/slapd.conf
+CONFTWO=$DATADIR/slapd2.conf
+CONF2DB=$DATADIR/slapd-2db.conf
+MCONF=$DATADIR/slapd-provider.conf
+COMPCONF=$DATADIR/slapd-component.conf
+PWCONF=$DATADIR/slapd-pw.conf
+WHOAMICONF=$DATADIR/slapd-whoami.conf
+ACLCONF=$DATADIR/slapd-acl.conf
+RCONF=$DATADIR/slapd-referrals.conf
+SRPROVIDERCONF=$DATADIR/slapd-syncrepl-provider.conf
+DSRPROVIDERCONF=$DATADIR/slapd-deltasync-provider.conf
+DSRCONSUMERCONF=$DATADIR/slapd-deltasync-consumer.conf
+PPOLICYCONF=$DATADIR/slapd-ppolicy.conf
+PROXYCACHECONF=$DATADIR/slapd-proxycache.conf
+PROXYAUTHZCONF=$DATADIR/slapd-proxyauthz.conf
+CACHEPROVIDERCONF=$DATADIR/slapd-cache-provider.conf
+PROXYAUTHZPROVIDERCONF=$DATADIR/slapd-cache-provider-proxyauthz.conf
+R1SRCONSUMERCONF=$DATADIR/slapd-syncrepl-consumer-refresh1.conf
+R2SRCONSUMERCONF=$DATADIR/slapd-syncrepl-consumer-refresh2.conf
+P1SRCONSUMERCONF=$DATADIR/slapd-syncrepl-consumer-persist1.conf
+P2SRCONSUMERCONF=$DATADIR/slapd-syncrepl-consumer-persist2.conf
+P3SRCONSUMERCONF=$DATADIR/slapd-syncrepl-consumer-persist3.conf
+DIRSYNC1CONF=$DATADIR/slapd-dirsync1.conf
+DSEESYNC1CONF=$DATADIR/slapd-dsee-consumer1.conf
+DSEESYNC2CONF=$DATADIR/slapd-dsee-consumer2.conf
+REFCONSUMERCONF=$DATADIR/slapd-ref-consumer.conf
+SCHEMACONF=$DATADIR/slapd-schema.conf
+TLSCONF=$DATADIR/slapd-tls.conf
+TLSSASLCONF=$DATADIR/slapd-tls-sasl.conf
+GLUECONF=$DATADIR/slapd-glue.conf
+REFINTCONF=$DATADIR/slapd-refint.conf
+RETCODECONF=$DATADIR/slapd-retcode.conf
+UNIQUECONF=$DATADIR/slapd-unique.conf
+LIMITSCONF=$DATADIR/slapd-limits.conf
+DNCONF=$DATADIR/slapd-dn.conf
+EMPTYDNCONF=$DATADIR/slapd-emptydn.conf
+IDASSERTCONF=$DATADIR/slapd-idassert.conf
+LDAPGLUECONF1=$DATADIR/slapd-ldapglue.conf
+LDAPGLUECONF2=$DATADIR/slapd-ldapgluepeople.conf
+LDAPGLUECONF3=$DATADIR/slapd-ldapgluegroups.conf
+RELAYCONF=$DATADIR/slapd-relay.conf
+CHAINCONF1=$DATADIR/slapd-chain1.conf
+CHAINCONF2=$DATADIR/slapd-chain2.conf
+GLUESYNCCONF1=$DATADIR/slapd-glue-syncrepl1.conf
+GLUESYNCCONF2=$DATADIR/slapd-glue-syncrepl2.conf
+SQLCONF=$DATADIR/slapd-sql.conf
+SQLSRPROVIDERCONF=$DATADIR/slapd-sql-syncrepl-provider.conf
+TRANSLUCENTLOCALCONF=$DATADIR/slapd-translucent-local.conf
+TRANSLUCENTREMOTECONF=$DATADIR/slapd-translucent-remote.conf
+METACONF=$DATADIR/slapd-meta.conf
+METACONF1=$DATADIR/slapd-meta-target1.conf
+METACONF2=$DATADIR/slapd-meta-target2.conf
+ASYNCMETACONF=$DATADIR/slapd-asyncmeta.conf
+GLUELDAPCONF=$DATADIR/slapd-glue-ldap.conf
+ACICONF=$DATADIR/slapd-aci.conf
+VALSORTCONF=$DATADIR/slapd-valsort.conf
+DEREFCONF=$DATADIR/slapd-deref.conf
+DYNLISTCONF=$DATADIR/slapd-dynlist.conf
+HOMEDIRCONF=$DATADIR/slapd-homedir.conf
+RCONSUMERCONF=$DATADIR/slapd-repl-consumer-remote.conf
+PLSRCONSUMERCONF=$DATADIR/slapd-syncrepl-consumer-persist-ldap.conf
+PLSRPROVIDERCONF=$DATADIR/slapd-syncrepl-multiproxy.conf
+DDSCONF=$DATADIR/slapd-dds.conf
+PASSWDCONF=$DATADIR/slapd-passwd.conf
+UNDOCONF=$DATADIR/slapd-config-undo.conf
+NAKEDCONF=$DATADIR/slapd-config-naked.conf
+VALREGEXCONF=$DATADIR/slapd-valregex.conf
+
+DYNAMICCONF=$DATADIR/slapd-dynamic.ldif
+
+SLAPDLLOADCONF=$DATADIR/slapd-lload.conf
+LLOADDCONF=$DATADIR/lloadd.conf
+LLOADDEMPTYCONF=$DATADIR/lloadd-empty.conf
+LLOADDANONCONF=$DATADIR/lloadd-anon.conf
+LLOADDUNREACHABLECONF=$DATADIR/lloadd-backend-issues.conf
+LLOADDTLSCONF=$DATADIR/lloadd-tls.conf
+LLOADDSASLCONF=$DATADIR/lloadd-sasl.conf
+
+# generated files
+CONF1=$TESTDIR/slapd.1.conf
+CONF2=$TESTDIR/slapd.2.conf
+CONF3=$TESTDIR/slapd.3.conf
+CONF4=$TESTDIR/slapd.4.conf
+CONF5=$TESTDIR/slapd.5.conf
+CONF6=$TESTDIR/slapd.6.conf
+ADDCONF=$TESTDIR/slapadd.conf
+CONFLDIF=$TESTDIR/slapd-dynamic.ldif
+
+LOG1=$TESTDIR/slapd.1.log
+LOG2=$TESTDIR/slapd.2.log
+LOG3=$TESTDIR/slapd.3.log
+LOG4=$TESTDIR/slapd.4.log
+LOG5=$TESTDIR/slapd.5.log
+LOG6=$TESTDIR/slapd.6.log
+SLAPADDLOG1=$TESTDIR/slapadd.1.log
+SLURPLOG=$TESTDIR/slurp.log
+
+CONFIGPWF=$TESTDIR/configpw
+
+LIBTOOL="${LIBTOOL-$TESTWD/../libtool}"
+# wrappers (valgrind, gdb, environment variables, etc.)
+if [ -n "$WRAPPER" ]; then
+ : # skip
+elif [ "$SLAPD_COMMON_WRAPPER" = gdb ]; then
+ WRAPPER="$ABS_SRCDIR/scripts/grandchild_wrapper.py gdb -nx -x $ABS_SRCDIR/scripts/gdb.py -batch-silent -return-child-result --args"
+elif [ "$SLAPD_COMMON_WRAPPER" = valgrind ]; then
+ WRAPPER="valgrind --log-file=$TESTDIR/valgrind.%p.log --fullpath-after=`dirname $ABS_SRCDIR` --keep-debuginfo=yes --leak-check=full"
+elif [ "$SLAPD_COMMON_WRAPPER" = "valgrind-errstop" ]; then
+ WRAPPER="valgrind --log-file=$TESTDIR/valgrind.%p.log --vgdb=yes --vgdb-error=1"
+elif [ "$SLAPD_COMMON_WRAPPER" = vgdb ]; then
+ WRAPPER="valgrind --log-file=$TESTDIR/valgrind.%p.log --vgdb=yes --vgdb-error=0"
+fi
+
+if [ -n "$WRAPPER" ]; then
+ SLAPD_WRAPPER="$LIBTOOL --mode=execute env $WRAPPER"
+fi
+
+# args
+SASLARGS="-Q"
+TOOLARGS="-x $LDAP_TOOLARGS"
+TOOLPROTO="-P 3"
+
+# cmds
+CONFFILTER=$SRCDIR/scripts/conf.sh
+CONFDIRSYNC=$SRCDIR/scripts/confdirsync.sh
+
+MONITORDATA=$SRCDIR/scripts/monitor_data.sh
+
+SLAPDBIN="$OBJDIR/servers/slapd/slapd"
+SLAPADD="$SLAPD_WRAPPER $SLAPDBIN -Ta -d 0 $LDAP_VERBOSE"
+SLAPCAT="$SLAPD_WRAPPER $SLAPDBIN -Tc -d 0 $LDAP_VERBOSE"
+SLAPINDEX="$SLAPD_WRAPPER $SLAPDBIN -Ti -d 0 $LDAP_VERBOSE"
+SLAPMODIFY="$SLAPD_WRAPPER $SLAPDBIN -Tm -d 0 $LDAP_VERBOSE"
+SLAPPASSWD="$SLAPD_WRAPPER $SLAPDBIN -Tpasswd"
+
+unset DIFF_OPTIONS
+# NOTE: -u/-c is not that portable...
+DIFF="diff -i"
+CMP="diff -i"
+BCMP="diff -iB"
+CMPOUT=/dev/null
+SLAPD="$SLAPD_WRAPPER $SLAPDBIN -s0"
+LLOADD="$SLAPD_WRAPPER $OBJDIR/servers/lloadd/lloadd -s0"
+LDAPPASSWD="$CLIENTDIR/ldappasswd $TOOLARGS"
+LDAPSASLSEARCH="$CLIENTDIR/ldapsearch $SASLARGS $TOOLPROTO $LDAP_TOOLARGS -LLL"
+LDAPSASLWHOAMI="$CLIENTDIR/ldapwhoami $SASLARGS $LDAP_TOOLARGS"
+LDAPSEARCH="$CLIENTDIR/ldapsearch $TOOLPROTO $TOOLARGS -LLL"
+LDAPRSEARCH="$CLIENTDIR/ldapsearch $TOOLPROTO $TOOLARGS"
+LDAPDELETE="$CLIENTDIR/ldapdelete $TOOLPROTO $TOOLARGS"
+LDAPMODIFY="$CLIENTDIR/ldapmodify $TOOLPROTO $TOOLARGS"
+LDAPADD="$CLIENTDIR/ldapmodify -a $TOOLPROTO $TOOLARGS"
+LDAPMODRDN="$CLIENTDIR/ldapmodrdn $TOOLPROTO $TOOLARGS"
+LDAPWHOAMI="$CLIENTDIR/ldapwhoami $TOOLARGS"
+LDAPCOMPARE="$CLIENTDIR/ldapcompare $TOOLARGS"
+LDAPEXOP="$CLIENTDIR/ldapexop $TOOLARGS"
+SLAPDTESTER=$PROGDIR/slapd-tester
+LDIFFILTER=$PROGDIR/ldif-filter
+SLAPDMTREAD=$PROGDIR/slapd-mtread
+LVL=${SLAPD_DEBUG-0x4105}
+LOCALHOST=localhost
+LOCALIP=127.0.0.1
+PORT1=`expr $BASEPORT + 1`
+PORT2=`expr $BASEPORT + 2`
+PORT3=`expr $BASEPORT + 3`
+PORT4=`expr $BASEPORT + 4`
+PORT5=`expr $BASEPORT + 5`
+PORT6=`expr $BASEPORT + 6`
+KDCPORT=`expr $BASEPORT + 7`
+URI1="ldap://${LOCALHOST}:$PORT1/"
+URIP1="ldap://${LOCALIP}:$PORT1/"
+URI2="ldap://${LOCALHOST}:$PORT2/"
+URIP2="ldap://${LOCALIP}:$PORT2/"
+URI3="ldap://${LOCALHOST}:$PORT3/"
+URIP3="ldap://${LOCALIP}:$PORT3/"
+URI4="ldap://${LOCALHOST}:$PORT4/"
+URIP4="ldap://${LOCALIP}:$PORT4/"
+URI5="ldap://${LOCALHOST}:$PORT5/"
+URIP5="ldap://${LOCALIP}:$PORT5/"
+URI6="ldap://${LOCALHOST}:$PORT6/"
+URIP6="ldap://${LOCALIP}:$PORT6/"
+SURI1="ldaps://${LOCALHOST}:$PORT1/"
+SURIP1="ldaps://${LOCALIP}:$PORT1/"
+SURI2="ldaps://${LOCALHOST}:$PORT2/"
+SURIP2="ldaps://${LOCALIP}:$PORT2/"
+SURI3="ldaps://${LOCALHOST}:$PORT3/"
+SURIP3="ldaps://${LOCALIP}:$PORT3/"
+SURI4="ldaps://${LOCALHOST}:$PORT4/"
+SURIP4="ldaps://${LOCALIP}:$PORT4/"
+SURI5="ldaps://${LOCALHOST}:$PORT5/"
+SURIP5="ldaps://${LOCALIP}:$PORT5/"
+SURI6="ldaps://${LOCALHOST}:$PORT6/"
+SURIP6="ldaps://${LOCALIP}:$PORT6/"
+
+KRB5REALM="K5.REALM"
+KDCHOST=$LOCALHOST
+
+# LDIF
+LDIF=$DATADIR/test.ldif
+LDIFADD1=$DATADIR/do_add.1
+LDIFGLUED=$DATADIR/test-glued.ldif
+LDIFORDERED=$DATADIR/test-ordered.ldif
+LDIFORDEREDCP=$DATADIR/test-ordered-cp.ldif
+LDIFORDEREDNOCP=$DATADIR/test-ordered-nocp.ldif
+LDIFBASE=$DATADIR/test-base.ldif
+LDIFPASSWD=$DATADIR/passwd.ldif
+LDIFWHOAMI=$DATADIR/test-whoami.ldif
+LDIFPASSWDOUT=$DATADIR/passwd-out.ldif
+LDIFPPOLICY=$DATADIR/ppolicy.ldif
+LDIFLANG=$DATADIR/test-lang.ldif
+LDIFLANGOUT=$DATADIR/lang-out.ldif
+LDIFREF=$DATADIR/referrals.ldif
+LDIFREFINT=$DATADIR/test-refint.ldif
+LDIFUNIQUE=$DATADIR/test-unique.ldif
+LDIFLIMITS=$DATADIR/test-limits.ldif
+LDIFDN=$DATADIR/test-dn.ldif
+LDIFEMPTYDN1=$DATADIR/test-emptydn1.ldif
+LDIFEMPTYDN2=$DATADIR/test-emptydn2.ldif
+LDIFIDASSERT1=$DATADIR/test-idassert1.ldif
+LDIFIDASSERT2=$DATADIR/test-idassert2.ldif
+LDIFLDAPGLUE1=$DATADIR/test-ldapglue.ldif
+LDIFLDAPGLUE2=$DATADIR/test-ldapgluepeople.ldif
+LDIFLDAPGLUE3=$DATADIR/test-ldapgluegroups.ldif
+LDIFCOMPMATCH=$DATADIR/test-compmatch.ldif
+LDIFCHAIN1=$DATADIR/test-chain1.ldif
+LDIFCHAIN2=$DATADIR/test-chain2.ldif
+LDIFTRANSLUCENTDATA=$DATADIR/test-translucent-data.ldif
+LDIFTRANSLUCENTCONFIG=$DATADIR/test-translucent-config.ldif
+LDIFTRANSLUCENTADD=$DATADIR/test-translucent-add.ldif
+LDIFTRANSLUCENTMERGED=$DATADIR/test-translucent-merged.ldif
+LDIFMETA=$DATADIR/test-meta.ldif
+LDIFDEREF=$DATADIR/test-deref.ldif
+LDIFVALSORT=$DATADIR/test-valsort.ldif
+SQLADD=$DATADIR/sql-add.ldif
+LDIFUNORDERED=$DATADIR/test-unordered.ldif
+LDIFREORDERED=$DATADIR/test-reordered.ldif
+LDIFMODIFY=$DATADIR/test-modify.ldif
+LDIFDIRSYNCCP=$DATADIR/test-dirsync-cp.ldif
+LDIFDIRSYNCNOCP=$DATADIR/test-dirsync-nocp.ldif
+
+# strings
+MONITOR=""
+REFDN="c=US"
+BASEDN="dc=example,dc=com"
+MANAGERDN="cn=Manager,$BASEDN"
+UPDATEDN="cn=consumer,$BASEDN"
+PASSWD=secret
+BABSDN="cn=Barbara Jensen,ou=Information Technology DivisioN,ou=People,$BASEDN"
+BJORNSDN="cn=Bjorn Jensen,ou=Information Technology DivisioN,ou=People,$BASEDN"
+BADBJORNSDN="cn=Bjorn JensenNotReally,ou=Information Technology DivisioN,ou=People,$BASEDN"
+JAJDN="cn=James A Jones 1,ou=Alumni Association,ou=People,$BASEDN"
+JOHNDDN="cn=John Doe,ou=Information Technology Division,ou=People,$BASEDN"
+MELLIOTDN="cn=Mark Elliot,ou=Alumni Association,ou=People,$BASEDN"
+REFINTDN="cn=Manager,o=refint"
+RETCODEDN="ou=RetCodes,$BASEDN"
+UNIQUEDN="cn=Manager,o=unique"
+EMPTYDNDN="cn=Manager,c=US"
+TRANSLUCENTROOT="o=translucent"
+TRANSLUCENTUSER="ou=users,o=translucent"
+TRANSLUCENTDN="uid=binder,o=translucent"
+TRANSLUCENTPASSWD="bindtest"
+METABASEDN="ou=Meta,$BASEDN"
+METAMANAGERDN="cn=Manager,$METABASEDN"
+DEREFDN="cn=Manager,o=deref"
+DEREFBASEDN="o=deref"
+VALSORTDN="cn=Manager,o=valsort"
+VALSORTBASEDN="o=valsort"
+MONITORDN="cn=Monitor"
+OPERATIONSMONITORDN="cn=Operations,$MONITORDN"
+CONNECTIONSMONITORDN="cn=Connections,$MONITORDN"
+DATABASESMONITORDN="cn=Databases,$MONITORDN"
+STATISTICSMONITORDN="cn=Statistics,$MONITORDN"
+
+# generated outputs
+SEARCHOUT=$TESTDIR/ldapsearch.out
+SEARCHOUT2=$TESTDIR/ldapsearch2.out
+SEARCHFLT=$TESTDIR/ldapsearch.flt
+SEARCHFLT2=$TESTDIR/ldapsearch2.flt
+LDIFFLT=$TESTDIR/ldif.flt
+LDIFFLT2=$TESTDIR/ldif2.flt
+TESTOUT=$TESTDIR/test.out
+INITOUT=$TESTDIR/init.out
+VALSORTOUT1=$DATADIR/valsort1.out
+VALSORTOUT2=$DATADIR/valsort2.out
+VALSORTOUT3=$DATADIR/valsort3.out
+MONITOROUT1=$DATADIR/monitor1.out
+MONITOROUT2=$DATADIR/monitor2.out
+MONITOROUT3=$DATADIR/monitor3.out
+MONITOROUT4=$DATADIR/monitor4.out
+
+SERVER1OUT=$TESTDIR/server1.out
+SERVER1FLT=$TESTDIR/server1.flt
+SERVER2OUT=$TESTDIR/server2.out
+SERVER2FLT=$TESTDIR/server2.flt
+SERVER3OUT=$TESTDIR/server3.out
+SERVER3FLT=$TESTDIR/server3.flt
+SERVER4OUT=$TESTDIR/server4.out
+SERVER4FLT=$TESTDIR/server4.flt
+SERVER5OUT=$TESTDIR/server5.out
+SERVER5FLT=$TESTDIR/server5.flt
+SERVER6OUT=$TESTDIR/server6.out
+SERVER6FLT=$TESTDIR/server6.flt
+
+PROVIDEROUT=$SERVER1OUT
+PROVIDERFLT=$SERVER1FLT
+CONSUMEROUT=$SERVER2OUT
+CONSUMER2OUT=$SERVER3OUT
+CONSUMERFLT=$SERVER2FLT
+CONSUMER2FLT=$SERVER3FLT
+
+MTREADOUT=$TESTDIR/mtread.out
+
+# original outputs for cmp
+PROXYCACHEOUT=$DATADIR/proxycache.out
+REFERRALOUT=$DATADIR/referrals.out
+SEARCHOUTPROVIDER=$DATADIR/search.out.provider
+SEARCHOUTX=$DATADIR/search.out.xsearch
+COMPSEARCHOUT=$DATADIR/compsearch.out
+MODIFYOUTPROVIDER=$DATADIR/modify.out.provider
+ADDDELOUTPROVIDER=$DATADIR/adddel.out.provider
+MODRDNOUTPROVIDER0=$DATADIR/modrdn.out.provider.0
+MODRDNOUTPROVIDER1=$DATADIR/modrdn.out.provider.1
+MODRDNOUTPROVIDER2=$DATADIR/modrdn.out.provider.2
+MODRDNOUTPROVIDER3=$DATADIR/modrdn.out.provider.3
+ACLOUTPROVIDER=$DATADIR/acl.out.provider
+REPLOUTPROVIDER=$DATADIR/repl.out.provider
+MODSRCHFILTERS=$DATADIR/modify.search.filters
+CERTIFICATETLS=$DATADIR/certificate.tls
+CERTIFICATEOUT=$DATADIR/certificate.out
+DNOUT=$DATADIR/dn.out
+EMPTYDNOUT1=$DATADIR/emptydn.out.slapadd
+EMPTYDNOUT2=$DATADIR/emptydn.out
+IDASSERTOUT=$DATADIR/idassert.out
+LDAPGLUEOUT=$DATADIR/ldapglue.out
+LDAPGLUEANONYMOUSOUT=$DATADIR/ldapglueanonymous.out
+RELAYOUT=$DATADIR/relay.out
+CHAINOUT=$DATADIR/chain.out
+CHAINREFOUT=$DATADIR/chainref.out
+CHAINMODOUT=$DATADIR/chainmod.out
+GLUESYNCOUT=$DATADIR/gluesync.out
+SQLREAD=$DATADIR/sql-read.out
+SQLWRITE=$DATADIR/sql-write.out
+TRANSLUCENTOUT=$DATADIR/translucent.search.out
+METAOUT=$DATADIR/meta.out
+METACONCURRENCYOUT=$DATADIR/metaconcurrency.out
+MANAGEOUT=$DATADIR/manage.out
+SUBTREERENAMEOUT=$DATADIR/subtree-rename.out
+ACIOUT=$DATADIR/aci.out
+DYNLISTOUT=$DATADIR/dynlist.out
+DDSOUT=$DATADIR/dds.out
+DEREFOUT=$DATADIR/deref.out
+MEMBEROFOUT=$DATADIR/memberof.out
+MEMBEROFREFINTOUT=$DATADIR/memberof-refint.out
+SHTOOL="$TOPSRCDIR/build/shtool"
+
+. $ABS_SRCDIR/scripts/functions.sh
diff --git a/tests/scripts/functions.sh b/tests/scripts/functions.sh
new file mode 100755
index 0000000..7e6615f
--- /dev/null
+++ b/tests/scripts/functions.sh
@@ -0,0 +1,22 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2022 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>.
+
+timer() {
+ if [ -n "$STARTTIME" ]; then
+ now=`date +%s`
+ delta=`expr $now - $STARTTIME`
+ date -u $DATEOPT$delta +%T
+ fi
+}
diff --git a/tests/scripts/gdb.py b/tests/scripts/gdb.py
new file mode 100644
index 0000000..50b5fa9
--- /dev/null
+++ b/tests/scripts/gdb.py
@@ -0,0 +1,85 @@
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2020-2022 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>.
+"""
+This GDB script sets up the debugger to run the program and see if it finishes
+of its own accord or is terminated by a signal (like SIGABRT/SIGSEGV). In the
+latter case, it saves a full backtrace and core file.
+
+These signals are considered part of normal operation and will not trigger the
+above handling:
+- SIGPIPE: normal in a networked environment
+- SIGHUP: normally used to tell a process to shut down
+"""
+
+import os
+import os.path
+
+import gdb
+
+
+def format_program(inferior=None, thread=None):
+ "Format program name and p(t)id"
+
+ if thread:
+ inferior = thread.inferior
+ elif inferior is None:
+ inferior = gdb.selected_inferior()
+
+ try:
+ name = os.path.basename(inferior.progspace.filename)
+ except AttributeError: # inferior has died already
+ name = "unknown"
+
+ if thread:
+ pid = ".".join(tid for tid in thread.ptid if tid)
+ else:
+ pid = inferior.pid
+
+ return "{}.{}".format(name, pid)
+
+
+def stop_handler(event):
+ "Inferior stopped on a signal, record core, backtrace and exit"
+
+ if not isinstance(event, gdb.SignalEvent):
+ # Ignore breakpoints
+ return
+
+ thread = event.inferior_thread
+
+ identifier = format_program(thread=thread)
+ prefix = os.path.expandvars("${TESTDIR}/") + identifier
+
+ if event.stop_signal == "SIGHUP":
+ # TODO: start a timer to catch shutdown issues/deadlocks
+ gdb.execute("continue")
+ return
+
+ gdb.execute('generate-core-file {}.core'.format(prefix))
+
+ with open(prefix + ".backtrace", "w") as bt_file:
+ backtrace = gdb.execute("thread apply all backtrace full",
+ to_string=True)
+ bt_file.write(backtrace)
+
+ gdb.execute("continue")
+
+
+# We or we could allow the runner to disable randomisation
+gdb.execute("set disable-randomization off")
+
+gdb.execute("handle SIGPIPE noprint")
+gdb.execute("handle SIGINT pass")
+gdb.events.stop.connect(stop_handler)
+gdb.execute("run")
diff --git a/tests/scripts/grandchild_wrapper.py b/tests/scripts/grandchild_wrapper.py
new file mode 100755
index 0000000..b5e7194
--- /dev/null
+++ b/tests/scripts/grandchild_wrapper.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2020-2022 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>.
+"""
+Running slapd under GDB in our testsuite, KILLPIDS would record gdb's PID
+rather than slapd's. When we want the server to shut down, SIGHUP is sent to
+KILLPIDS but GDB cannot handle being signalled directly and the entire thing is
+terminated immediately. There might be tests that rely on slapd being given the
+chance to shut down gracefully, to do this, we need to make sure the signal is
+actually sent to slapd.
+
+This script attempts to address this shortcoming in our test suite, serving as
+the front for gdb/other wrappers, catching SIGHUPs and redirecting them to the
+oldest living grandchild. The way we start up gdb, that process should be
+slapd, our intended target.
+
+This requires the pgrep utility provided by the procps package on Debian
+systems.
+"""
+
+import asyncio
+import os
+import signal
+import sys
+
+
+async def signal_to_grandchild(child):
+ # Get the first child, that should be the one we're after
+ pgrep = await asyncio.create_subprocess_exec(
+ "pgrep", "-o", "--parent", str(child.pid),
+ stdout=asyncio.subprocess.PIPE)
+
+ stdout, _ = await pgrep.communicate()
+ if not stdout:
+ return
+
+ grandchild = [int(pid) for pid in stdout.split()][0]
+
+ os.kill(grandchild, signal.SIGHUP)
+
+
+def sighup_handler(child):
+ asyncio.create_task(signal_to_grandchild(child))
+
+
+async def main(args=None):
+ if args is None:
+ args = sys.argv[1:]
+
+ child = await asyncio.create_subprocess_exec(*args)
+
+ # If we got a SIGHUP before we got the child fully started, there's no
+ # point signalling anyway
+ loop = asyncio.get_running_loop()
+ loop.add_signal_handler(signal.SIGHUP, sighup_handler, child)
+
+ raise SystemExit(await child.wait())
+
+
+if __name__ == '__main__':
+ asyncio.run(main())
diff --git a/tests/scripts/its-all b/tests/scripts/its-all
new file mode 100755
index 0000000..f92a373
--- /dev/null
+++ b/tests/scripts/its-all
@@ -0,0 +1,52 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+SHTOOL="$SRCDIR/../build/shtool"
+
+TB="" TN=""
+if test -t 1 ; then
+ TB=`$SHTOOL echo -e "%B" 2>/dev/null`
+ TN=`$SHTOOL echo -e "%b" 2>/dev/null`
+fi
+
+echo "#######################################################################"
+echo "### ###"
+echo "### regression tests ###"
+echo "### ###"
+echo "#######################################################################"
+echo "###"
+
+echo ">>>>> Executing all LDAP ITS regression tests"
+
+for CMD in $SRCDIR/data/regressions/its*/its*; do
+ # remove cruft from prior test
+ if test $PRESERVE = yes ; then
+ /bin/rm -rf testrun/db.*
+ else
+ /bin/rm -rf testrun
+ fi
+
+ echo ">>>>> Starting ${TB}`basename $CMD`${TN} ..."
+ $CMD
+ RC=$?
+ if test $RC -eq 0 ; then
+ echo ">>>>> $CMD completed ${TB}OK${TN}."
+ else
+ echo ">>>>> $CMD ${TB}failed${TN} (exit $RC)"
+ exit $RC
+ fi
+
+ echo ""
+done
diff --git a/tests/scripts/lloadd-all b/tests/scripts/lloadd-all
new file mode 100755
index 0000000..34a2d87
--- /dev/null
+++ b/tests/scripts/lloadd-all
@@ -0,0 +1,116 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+. $SRCDIR/scripts/defines.sh
+
+TB="" TN=""
+if test -t 1 ; then
+ TB=`$SHTOOL echo -e "%B" 2>/dev/null`
+ TN=`$SHTOOL echo -e "%b" 2>/dev/null`
+fi
+
+FAILCOUNT=0
+SKIPCOUNT=0
+SLEEPTIME=10
+
+# check for BSD vs GNU date
+date -j >/dev/null 2>&1
+RC=$?
+if [ $RC -ne 0 ]; then
+ DATEOPT="-d @"
+else
+ DATEOPT="-r "
+fi
+
+echo ">>>>> $(timer) Executing all LDAP tests for the Load Balancer"
+
+if [ -n "$NOEXIT" ]; then
+ echo "Result Test" > $TESTWD/results
+fi
+
+for CMD in $SRCDIR/scripts/lloadd/test*; do
+ case "$CMD" in
+ *~) continue;;
+ *.bak) continue;;
+ *.orig) continue;;
+ *.sav) continue;;
+ *) test -f "$CMD" || continue;;
+ esac
+
+ # remove cruft from prior test
+ if test $PRESERVE = yes ; then
+ /bin/rm -rf $TESTDIR/db.*
+ else
+ /bin/rm -rf $TESTDIR
+ fi
+
+ BCMD=`basename $CMD`
+ if [ -x "$CMD" ]; then
+ MSG=">>>>> $(timer) Starting ${TB}$BCMD${TN} for lloadd+$BACKEND..."
+ [ -n "$TESTINST" ] && echo "$MSG" >&2
+ echo "$MSG"
+ START=`date +%s`
+ if [ -n "$TESTINST" ]; then
+ $CMD 2>&1
+ else
+ $CMD
+ fi
+ RC=$?
+ END=`date +%s`
+
+ if test $RC -eq 0 ; then
+ MSG=">>>>> $(timer) Finished $BCMD for lloadd+$BACKEND after $(( $END - $START )) seconds."
+ [ -n "$TESTINST" ] && echo "$MSG" >&2
+ echo "$MSG"
+ else
+ MSG=">>>>> $(timer) Failed $BCMD for lloadd+$BACKEND after $(( $END - $START )) seconds"
+ [ -n "$TESTINST" ] && echo "$MSG" >&2
+ echo "$MSG"
+ FAILCOUNT=`expr $FAILCOUNT + 1`
+
+ if [ -n "$NOEXIT" ]; then
+ echo "Continuing."
+ else
+ echo "(exit $RC)"
+ exit $RC
+ fi
+ fi
+ else
+ MSG=">>>>> $(timer) Skipping ${TB}$BCMD${TN} for lloadd+$BACKEND."
+ [ -n "$TESTINST" ] && echo "$MSG" >&2
+ echo "$MSG"
+ SKIPCOUNT=`expr $SKIPCOUNT + 1`
+ RC="-"
+ fi
+
+ if [ -n "$NOEXIT" ]; then
+ echo "$RC $BCMD" >> $TESTWD/results
+ fi
+
+# echo ">>>>> waiting $SLEEPTIME seconds for things to exit"
+# sleep $SLEEPTIME
+ echo ""
+done
+
+if [ -n "$NOEXIT" ]; then
+ if [ "$FAILCOUNT" -gt 0 ]; then
+ cat $TESTWD/results
+ echo "$FAILCOUNT tests for $BACKEND ${TB}failed${TN}. Please review the test log."
+ else
+ echo "All executed tests for $BACKEND ${TB}succeeded${TN}."
+ fi
+fi
+
+echo "$SKIPCOUNT tests for the Load Balancer were ${TB}skipped${TN}."
diff --git a/tests/scripts/lloadd/test000-rootdse b/tests/scripts/lloadd/test000-rootdse
new file mode 100755
index 0000000..9046b16
--- /dev/null
+++ b/tests/scripts/lloadd/test000-rootdse
@@ -0,0 +1,118 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2 $DBDIR3
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+echo "Starting slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $SCHEMACONF > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+echo "Starting a second slapd on TCP/IP port $PORT3..."
+sed -e "s,$DBDIR1,$DBDIR2," < $CONF2 > $CONF3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+echo "Starting a third slapd on TCP/IP port $PORT4..."
+sed -e "s,$DBDIR1,$DBDIR3," < $CONF2 > $CONF4
+$SLAPD -f $CONF4 -h $URI4 -d $LVL > $LOG4 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+echo "Starting lloadd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $LLOADDANONCONF > $CONF1.lloadd
+if test $AC_lloadd = lloaddyes; then
+ $LLOADD -f $CONF1.lloadd -h $URI1 -d $LVL > $LOG1 2>&1 &
+else
+ . $CONFFILTER $BACKEND < $SLAPDLLOADCONF > $CONF1.slapd
+ # FIXME: this won't work on Windows, but lloadd doesn't support Windows yet
+ $SLAPD -f $CONF1.slapd -h $URI6 -d $LVL > $LOG1 2>&1 &
+fi
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+sleep $SLEEP0
+
+echo "Using ldapsearch to retrieve the root DSE..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -b "" -s base -H $URI1 \
+ '@extensibleObject' > $SEARCHOUT 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for lloadd to start..."
+ sleep $SLEEP1
+done
+
+if test $RC = 0 ; then
+ echo "Using ldapsearch to retrieve the cn=Subschema..."
+ $LDAPSEARCH -b "cn=Subschema" -s base -H $URI1 \
+ '(&(objectClasses=top)(objectClasses=2.5.6.0))' cn objectClass \
+ >> $SEARCHOUT 2>&1
+ RC=$?
+
+fi
+
+if test $RC = 0 ; then
+ echo "Using ldapsearch to retrieve the cn=Monitor..."
+ $LDAPSEARCH -b "cn=Monitor" -s base -H $URI1 \
+ '@monitor' >> $SEARCHOUT 2>&1
+ RC=$?
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+count=3
+if test $RC != 0 ; then
+ echo ">>>>> Test failed"
+else
+ RC=`grep '^dn:' $SEARCHOUT | wc -l`
+ if test $RC != $count ; then
+ echo ">>>>> Test failed: expected $count entries, got" $RC
+ RC=1
+ else
+ echo ">>>>> Test succeeded"
+ RC=0
+ fi
+fi
+
+test $KILLSERVERS != no && wait
+
+exit $RC
diff --git a/tests/scripts/lloadd/test001-backend-issues b/tests/scripts/lloadd/test001-backend-issues
new file mode 100755
index 0000000..b7f99fc
--- /dev/null
+++ b/tests/scripts/lloadd/test001-backend-issues
@@ -0,0 +1,219 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+echo "Starting an empty slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $SCHEMACONF > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+PID2="$PID"
+KILLPIDS="$PID"
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONFTWO > $CONF3
+$SLAPADD -f $CONF3 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+$SLAPINDEX -f $CONF3
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+echo "Starting second slapd on TCP/IP port $PORT3..."
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+PID3="$PID"
+KILLPIDS="$KILLPIDS $PID"
+
+sleep $SLEEP0
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI3 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting lloadd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $LLOADDUNREACHABLECONF > $CONF1.lloadd
+if test $AC_lloadd = lloaddyes; then
+ $LLOADD -f $CONF1.lloadd -h $URI1 -d $LVL > $LOG1 2>&1 &
+else
+ . $CONFFILTER $BACKEND < $SLAPDLLOADCONF > $CONF1.slapd
+ $SLAPD -f $CONF1.slapd -h $URI6 -d $LVL > $LOG1 2>&1 &
+fi
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for lloadd to start..."
+ sleep $SLEEP1
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing exact searching..."
+echo "# Testing exact searching..." > $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn=jENSEN)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing approximate searching..."
+echo "# Testing approximate searching..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn~=jENSEN)' name >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing OR searching..."
+echo "# Testing OR searching..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(|(givenname=Xx*yY*Z)(cn=)(undef=*)(objectclass=groupofnames)(sn=jones)(member=cn=Manager,dc=example,dc=com)(uniqueMember=cn=Manager,dc=example,dc=com))' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing AND matching and ends-with searching..."
+echo "# Testing AND matching and ends-with searching..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "ou=groups,$BASEDN" -s one -H $URI1 \
+ '(&(objectclass=groupofnames)(cn=A*)(member=cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com))' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing NOT searching..."
+echo "# Testing NOT searching..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(!(objectclass=pilotPerson))' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing objectClass/attributeType inheritance ..."
+echo "# Testing objectClass/attributeType inheritance ..." >> $SEARCHOUT
+$LDAPSEARCH -M -a never -S "" -b "$BASEDN" -H $URI1 \
+ '(&(objectClass=inetorgperson)(userid=uham))' \
+ "2.5.4.0" "userid" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$SEARCHOUTPROVIDER
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/lloadd/test002-load b/tests/scripts/lloadd/test002-load
new file mode 100755
index 0000000..2de04d6
--- /dev/null
+++ b/tests/scripts/lloadd/test002-load
@@ -0,0 +1,175 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 x$TESTLOOPS = x ; then
+ TESTLOOPS=50
+fi
+
+if test x$TESTCHILDREN = x ; then
+ TESTCHILDREN=20
+fi
+
+if test x$MAXRETRIES = x ; then
+ MAXRETRIES=5
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $CONF2
+$SLAPADD -f $CONF2 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting a slapd on TCP/IP port $PORT2..."
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+PID2="$PID"
+KILLPIDS="$PID"
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONFTWO > $CONF3
+$SLAPADD -f $CONF3 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+$SLAPINDEX -f $CONF3
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+echo "Starting second slapd on TCP/IP port $PORT3..."
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+PID2="$PID"
+KILLPIDS="$KILLPIDS $PID"
+
+sleep $SLEEP0
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI3 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting lloadd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $LLOADDCONF > $CONF1.lloadd
+if test $AC_lloadd = lloaddyes; then
+ $LLOADD -f $CONF1.lloadd -h $URI1 -d $LVL > $LOG1 2>&1 &
+else
+ . $CONFFILTER $BACKEND < $SLAPDLLOADCONF > $CONF1.slapd
+ # FIXME: this won't work on Windows, but lloadd doesn't support Windows yet
+ $SLAPD -f $CONF1.slapd -h $URI6 -d $LVL > $LOG1 2>&1 &
+fi
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for lloadd to start..."
+ sleep $SLEEP1
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# fix test data to include back-monitor, if available
+# NOTE: copies do_* files from $DATADIR to $TESTDIR
+$MONITORDATA "$DATADIR" "$TESTDIR"
+
+
+echo "Using tester for concurrent server access ($TESTCHILDREN x $TESTLOOPS ops)..."
+$SLAPDTESTER -P "$PROGDIR" -d "$TESTDIR" \
+ -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -t 1 -l $TESTLOOPS -r $MAXRETRIES -j $TESTCHILDREN \
+ -i '*INVALID_CREDENTIALS,*BUSY,UNWILLING_TO_PERFORM'
+RC=$?
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $RC != 0 ; then
+ echo "slapd-tester failed ($RC)!"
+ exit $RC
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/lloadd/test003-cnconfig b/tests/scripts/lloadd/test003-cnconfig
new file mode 100755
index 0000000..373b5bb
--- /dev/null
+++ b/tests/scripts/lloadd/test003-cnconfig
@@ -0,0 +1,481 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $CONF1.d $DBDIR1 $DBDIR2 $CFDIR
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+if test $AC_lloadd = lloaddyes ; then
+ echo "Load balancer module not available, skipping..."
+ exit 0
+fi
+
+echo "Starting the first slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $CONF > $CONF2
+$SLAPADD -f $CONF2 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+$SLAPINDEX -f $CONF2
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+PID2="$PID"
+KILLPIDS="$PID"
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONFTWO > $CONF3
+$SLAPADD -f $CONF3 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+$SLAPINDEX -f $CONF3
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+echo "Starting second slapd on TCP/IP port $PORT3..."
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+PID3="$PID"
+KILLPIDS="$KILLPIDS $PID"
+
+sleep $SLEEP0
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI3 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting lloadd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $LLOADDUNREACHABLECONF > $CONF1.lloadd
+. $CONFFILTER $BACKEND < $SLAPDLLOADCONF > $CONF1.slapd
+$SLAPD -Tt -f $CONF1.slapd -F $CONF1.d -d $LVL > $LOG1 2>&1
+$SLAPD -F $CONF1.d -h $URI6 -d $LVL >> $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+echo "Testing lloadd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for lloadd to start..."
+ sleep $SLEEP1
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+
+echo "Testing cn=config searching..."
+$LDAPSEARCH -H $URI6 -D cn=config -y $CONFIGPWF \
+ -s sub -b "olcBackend={0}lload,cn=config" '(objectclass=*)' > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Deleting backends"
+
+# weighted backends are sorted before we get to _cfadd to create their entries
+for i in 3 2 4 1 ; do
+ echo "cn={0}server $i,cn={1}tier 2,olcBackend={0}lload,cn=config"
+ $LDAPDELETE -H $URI6 -D cn=config -y $CONFIGPWF \
+ "cn={0}server $i,cn={1}tier 2,olcBackend={0}lload,cn=config" > /dev/null 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "deleting server failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+done
+
+echo "Testing cn=config searching..."
+$LDAPSEARCH -H $URI6 -D cn=config -y $CONFIGPWF \
+ -s sub -b "olcBackend={0}lload,cn=config" '(objectclass=*)' > /dev/null 2>&1
+
+echo "Deleting tiers"
+
+for i in 1 2; do
+ echo "cn={0}tier $i,olcBackend={0}lload,cn=config"
+ $LDAPDELETE -H $URI6 -D cn=config -y $CONFIGPWF \
+ "cn={0}tier $i,olcBackend={0}lload,cn=config" > /dev/null 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "deleting server failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+done
+
+echo "Testing cn=config searching..."
+$LDAPSEARCH -H $URI6 -D cn=config -y $CONFIGPWF \
+ -s sub -b "olcBackend={0}lload,cn=config" '(objectclass=*)' > /dev/null 2>&1
+
+
+echo "# Testing exact searching..."
+
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn=jENSEN)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 52 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing adding a tier"
+$LDAPADD -D cn=config -H $URI6 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: cn=roundrobin tier,olcBackend={0}lload,cn=config
+objectClass: olcBkLloadTierConfig
+olcBkLloadTierType: roundrobin
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for cn=roundrobin tier ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing adding a weighted tier"
+$LDAPADD -D cn=config -H $URI6 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: cn=weighted tier,olcBackend={0}lload,cn=config
+objectClass: olcBkLloadTierConfig
+olcBkLloadTierType: weighted
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for cn=weighted tier ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing adding a backend server"
+$LDAPADD -D cn=config -H $URI6 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: cn=server 7,cn={1}weighted tier,olcBackend={0}lload,cn=config
+objectClass: olcBkLloadBackendConfig
+cn: server 7
+olcBkLloadBackendUri: $URI3
+olcBkLloadBindconns: 2
+olcBkLloadMaxPendingConns: 3
+olcBkLloadMaxPendingOps: 5
+olcBkLloadNumconns: 3
+olcBkLloadRetry: 5000
+olcBkLloadWeight: 10
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for cn=server 7 ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Verifying balancer operation..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn=jENSEN)' >> $SEARCHOUT 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for backend to start..."
+ sleep $SLEEP1
+done
+
+echo "Testing bindconf modify"
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcBackend={0}lload,cn=config
+changetype: modify
+replace: olcBkLloadBindconf
+olcBkLloadBindconf: bindmethod=simple timeout=0 network-timeout=0 binddn="cn=wrongmanager,dc=example,dc=com" credentials="secret"
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "modify failed for bindconf ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "# Sending a search request..."
+
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn=jENSEN)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 52 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Restoring bindconf value"
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcBackend={0}lload,cn=config
+changetype: modify
+replace: olcBkLloadBindconf
+olcBkLloadBindconf: bindmethod=simple timeout=0 network-timeout=0 binddn="cn=Manager,dc=example,dc=com" credentials="secret"
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "modify failed for bindconf ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+
+echo "Verifying balancer operation..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn=jENSEN)' >> $SEARCHOUT 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for backend to start..."
+ sleep $SLEEP1
+done
+
+echo "Testing global attributes"
+echo "Testing olcBkLloadMaxPDUPerCycle modify"
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcBackend={0}lload,cn=config
+changetype: modify
+replace: olcBkLloadMaxPDUPerCycle
+olcBkLloadMaxPDUPerCycle: 0
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "modify failed for olcBkLloadMaxPDUPerCycle($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Sending a search request..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn=jENSEN)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing olcBkLloadSockbufMaxClient modify"
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcBackend={0}lload,cn=config
+changetype: modify
+replace: olcBkLloadSockbufMaxClient
+olcBkLloadSockbufMaxClient: 20000
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "modify failed for olcBkLloadSockbufMaxClient($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Sending a search request..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn=jENSEN)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing olcBkLloadSockbufMaxUpstream modify"
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcBackend={0}lload,cn=config
+changetype: modify
+replace: olcBkLloadSockbufMaxUpstream
+olcBkLloadSockbufMaxUpstream: 200000
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "modify failed for olcBkLloadSockbufMaxUpstream($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Sending a search request..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn=jENSEN)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing olcBkLloadIOTimeout modify"
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcBackend={0}lload,cn=config
+changetype: modify
+replace: olcBkLloadIOTimeout
+olcBkLloadIOTimeout: 20000
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "modify failed for olcBkLloadWriteTimeout($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Sending a search request..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn=jENSEN)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing backend attributes"
+echo "Testing olcBkLloadBindconns modify"
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn={0}server 7,cn={1}weighted tier,olcBackend={0}lload,cn=config
+changetype: modify
+replace: olcBkLloadBindconns
+olcBkLloadBindconns: 20
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "modify failed for olcBkLloadBindconns($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing exact searching..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn=jENSEN)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+
+echo "Testing olcBkLloadMaxPendingConns modify"
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn={0}server 7,cn={1}weighted tier,olcBackend={0}lload,cn=config
+changetype: modify
+replace: olcBkLloadMaxPendingConns
+olcBkLloadMaxPendingConns: 30
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "modify failed for olcBkLloadMaxPendingConns($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing exact searching..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn=jENSEN)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/lloadd/test004-monitor b/tests/scripts/lloadd/test004-monitor
new file mode 100755
index 0000000..ef308b2
--- /dev/null
+++ b/tests/scripts/lloadd/test004-monitor
@@ -0,0 +1,365 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+if test $AC_lloadd = lloaddyes ; then
+ echo "Load balancer module not available, skipping..."
+ exit 0
+fi
+
+# Monitor counts are unstable in the face of concurrency, since different
+# clients may get different upstreams assigned for their operations. This might
+# also change later when tiered load balancing is available.
+# Another constraint is that some global counts are updated by the statistics
+# collection task scheduled to run every second.
+#
+# This test assumes current round-robin policy:
+# - default backend is rotated every time we successfully pick an upstream
+# - upstream connections within the same backend are rotated in the same way
+# - the monitor entry order for upstream connections reflects the connection
+# order within its CIRCLEQ_
+
+echo "Starting the first slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $CONF > $CONF2
+$SLAPADD -f $CONF2 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+$SLAPINDEX -f $CONF2
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+PID2="$PID"
+KILLPIDS="$PID"
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONFTWO > $CONF3
+$SLAPADD -f $CONF3 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+$SLAPINDEX -f $CONF3
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+echo "Starting second slapd on TCP/IP port $PORT3..."
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+PID3="$PID"
+KILLPIDS="$KILLPIDS $PID"
+
+sleep $SLEEP0
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI3 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting lloadd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $LLOADDEMPTYCONF > $CONF1.lloadd
+. $CONFFILTER $BACKEND < $SLAPDLLOADCONF > $CONF1.slapd
+$SLAPD -f $CONF1.slapd -h $URI6 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI6 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for lloadd to start..."
+ sleep $SLEEP1
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Sending a search request to prime the counters..."
+$LDAPSEARCH -b "$BASEDN" -s base -H $URI1 >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 52 ; then
+ echo "ldapsearch should have failed ($RC != 52)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Retrieving data from cn=monitor..."
+echo "# Retrieving data from an empty lload's cn=monitor..." >>$SEARCHOUT
+echo "# Operations received:" >>$SEARCHOUT
+echo "# Bind: 1 (0 forwarded)" >>$SEARCHOUT
+echo "# Search: 0" >>$SEARCHOUT
+echo "# Unbind: 1" >>$SEARCHOUT
+$LDAPSEARCH -b "cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ olmBalancer olmBalancerServer olmBalancerOperation olmBalancerConnection >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding first tier..."
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=first,olcBackend={0}lload,cn=config
+changetype: add
+objectClass: olcBkLloadTierConfig
+olcBkLloadTierType: roundrobin
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for backend ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding first backend server..."
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=backend,cn={0}first,olcBackend={0}lload,cn=config
+changetype: add
+objectClass: olcBkLloadBackendConfig
+olcBkLloadBackendUri: $URI2
+olcBkLloadMaxPendingConns: 3
+olcBkLloadMaxPendingOps: 5
+olcBkLloadRetry: 1000
+olcBkLloadNumconns: 2
+olcBkLloadBindconns: 2
+olcBkLloadWeight: 1
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for backend ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# At the moment, the global counters are updated by a recurring job,
+# wait for it to settle
+echo "Waiting until connections are established..."
+for i in 0 1 2 3 4 5; do
+ $LDAPCOMPARE "cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ 'olmOutgoingConnections:4' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 6 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds until connections are established..."
+ sleep $SLEEP1
+done
+if test $RC != 6 ; then
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Retrieving data from cn=monitor again..."
+echo >>$SEARCHOUT
+echo "# Retrieving data from lload's cn=monitor..." >>$SEARCHOUT
+$LDAPSEARCH -b "cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ olmBalancer olmBalancerServer olmBalancerOperation olmBalancerConnection >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding another backend server..."
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=server 2,cn={0}first,olcBackend={0}lload,cn=config
+changetype: add
+objectClass: olcBkLloadBackendConfig
+olcBkLloadBackendUri: $URI3
+olcBkLloadMaxPendingConns: 3
+olcBkLloadMaxPendingOps: 5
+olcBkLloadRetry: 1000
+olcBkLloadNumconns: 4
+olcBkLloadBindconns: 5
+olcBkLloadWeight: 1
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for backend ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# At the moment, the global counters are updated by a recurring job,
+# wait for it to settle
+echo "Waiting until connections are established..."
+for i in 0 1 2 3 4 5; do
+ $LDAPCOMPARE "cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ 'olmOutgoingConnections:13' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 6 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds until connections are established..."
+ sleep $SLEEP1
+done
+if test $RC != 6 ; then
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Sending another search request..."
+$LDAPSEARCH -b "$BASEDN" -s base -H $URI1 >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Sending a WhoAmI? request..."
+$LDAPWHOAMI -D "$BABSDN" -w bjensen -H $URI1 >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# At the moment, the global counters are updated by a recurring job,
+# wait for it to settle
+echo "Waiting until global counters are updated..."
+for i in 0 1 2 3 4 5; do
+ $LDAPCOMPARE "cn=Other,cn=Operations,cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ 'olmCompletedOps:2' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 6 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds until counters are updated..."
+ sleep $SLEEP1
+done
+if test $RC != 6 ; then
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Retrieving data from cn=monitor again..."
+echo >>$SEARCHOUT
+echo "# Retrieving data after a search+WhoAmI?..." >>$SEARCHOUT
+echo "# Operations received:" >>$SEARCHOUT
+echo "# Bind: 3 (2 forwarded)" >>$SEARCHOUT
+echo "# Search: 1" >>$SEARCHOUT
+echo "# Extended: 1 (WhoAmI?)" >>$SEARCHOUT
+echo "# Unbind: 3" >>$SEARCHOUT
+$LDAPSEARCH -b "cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ olmBalancer olmBalancerServer olmBalancerOperation olmBalancerConnection >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$DATADIR/lloadd/monitor.ldif
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER -s e < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER -s e < $LDIF | sed \
+ -e "s|@URI2@|$URI2|g" \
+ -e "s|@URI3@|$URI3|g" \
+ > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/lloadd/test005-tls b/tests/scripts/lloadd/test005-tls
new file mode 100755
index 0000000..7d6f87c
--- /dev/null
+++ b/tests/scripts/lloadd/test005-tls
@@ -0,0 +1,272 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $WITH_TLS = no ; then
+ echo "TLS support not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+cp -r $DATADIR/tls $TESTDIR
+
+cd $TESTWD
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $TLSSASLCONF > $CONF2
+$SLAPADD -f $CONF2 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting a slapd on TCP/IP port $PORT3..."
+$SLAPD -f $CONF2 -h $URI3 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+PID2="$PID"
+KILLPIDS="$PID"
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI3 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONFTWO > $CONF3
+# FIXME: Hack!
+echo "TLSCertificateKeyFile $TESTDIR/tls/private/localhost.key" >>$CONF3
+echo "TLSCertificateFile $TESTDIR/tls/certs/localhost.crt" >>$CONF3
+echo 'authz-regexp "email=([^,]*),cn=[^,]*,ou=OpenLDAP,o=OpenLDAP Foundation,st=CA,c=US" ldap:///ou=People,dc=example,dc=com??sub?(mail=$1)' >>$CONF3
+$SLAPADD -f $CONF3 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+$SLAPINDEX -f $CONF3
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+echo "Starting second slapd on TCP/IP port $PORT4 w/ ldaps..."
+$SLAPD -f $CONF3 -h $SURI4 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+PID2="$PID"
+KILLPIDS="$KILLPIDS $PID"
+
+sleep $SLEEP0
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -o tls-reqcert=never -s base -b "$MONITOR" -H $SURI4 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting lloadd on TCP/IP port $PORT1 and ldaps $PORT2..."
+. $CONFFILTER $BACKEND < $LLOADDTLSCONF > $CONF1.lloadd
+if test $AC_lloadd = lloaddyes; then
+ $LLOADD -f $CONF1.lloadd -h "$URI1 $SURI2" -d $LVL > $LOG1 2>&1 &
+else
+ . $CONFFILTER $BACKEND < $SLAPDLLOADCONF | sed -e "s,listen.*,listen \"$URI1 $SURI2\"," > $CONF1.slapd
+ $SLAPD -f $CONF1.slapd -h $URI6 -d $LVL > $LOG1 2>&1 &
+fi
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for lloadd to start..."
+ sleep $SLEEP1
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo -n "Using ldapsearch with startTLS with no server cert validation...."
+$LDAPSEARCH -o tls-reqcert=never -ZZ -b "" -s base -H $URIP1 \
+ '@extensibleObject' > $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch (startTLS) failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+else
+ echo "success"
+fi
+
+echo -n "Using ldapsearch with startTLS with hard require cert...."
+$LDAPSEARCH -o tls-cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -o tls-reqcert=hard -ZZ -b "" -s base -H $URIP1 \
+ '@extensibleObject' > $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch (startTLS) failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+else
+ echo "success"
+fi
+
+if test $WITH_TLS_TYPE = openssl ; then
+ echo -n "Using ldapsearch with startTLS and specific protocol version...."
+ $LDAPSEARCH -o tls-cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -o tls-reqcert=hard -o tls-protocol-min=3.3 -ZZ -b "" -s base -H $URIP1 \
+ '@extensibleObject' > $SEARCHOUT 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch (protocol-min) failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ else
+ echo "success"
+ fi
+fi
+
+echo -n "Using ldapsearch on $SURI2 with no server cert validation..."
+$LDAPSEARCH -o tls-reqcert=never -b "cn=Subschema" -s base -H $SURIP2 \
+ '(&(objectClasses=top)(objectClasses=2.5.6.0))' cn objectClass \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch (ldaps) failed($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+else
+ echo "success"
+fi
+
+echo -n "Using ldapsearch on $SURI2 with reqcert HARD and no CA cert. Should fail..."
+$LDAPSEARCH -o tls-reqcert=hard -b "cn=Subschema" -s base -H $SURIP2 \
+ '(&(objectClasses=top)(objectClasses=2.5.6.0))' cn objectClass \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "ldapsearch (ldaps) succeeded when it should have failed($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+else
+ echo "failed correctly with error code ($RC)"
+fi
+
+echo -n "Using ldapsearch on $SURI2 with CA cert and reqcert HARD..."
+$LDAPSEARCH -o tls-cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt \
+ -o tls-reqcert=hard -b "cn=Subschema" -s base -H $SURIP2 \
+ '(&(objectClasses=top)(objectClasses=2.5.6.0))' cn objectClass \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch (ldaps) failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+else
+ echo "success"
+fi
+
+if test $WITH_SASL = no ; then
+ echo "SASL support not available, skipping client cert authentication"
+else
+ echo -n "Using ldapwhoami with SASL/EXTERNAL...."
+ $LDAPSASLWHOAMI -o tls-cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -o tls-reqcert=hard \
+ -o tls-cert=$TESTDIR/tls/certs/bjensen@mailgw.example.com.crt \
+ -o tls-key=$TESTDIR/tls/private/bjensen@mailgw.example.com.key \
+ -ZZ -Y EXTERNAL -H $URIP1 \
+ > $TESTOUT 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapwhoami (startTLS) failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ else
+ echo "success"
+ fi
+
+ echo -n "Validating mapped SASL ID..."
+ echo 'dn:cn=barbara jensen,ou=information technology division,ou=people,dc=example,dc=com' > $TESTDIR/dn.out
+ $CMP $TESTDIR/dn.out $TESTOUT > $CMPOUT
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "Comparison failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ else
+ echo "success"
+ fi
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $RC != 0 ; then
+ echo ">>>>> Test failed"
+else
+ echo ">>>>> Test succeeded"
+ RC=0
+fi
+
+test $KILLSERVERS != no && wait
+
+exit $RC
diff --git a/tests/scripts/lloadd/test006-sasl b/tests/scripts/lloadd/test006-sasl
new file mode 100755
index 0000000..a49dbbb
--- /dev/null
+++ b/tests/scripts/lloadd/test006-sasl
@@ -0,0 +1,252 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $WITH_SASL = "yes" ; then
+ if test $USE_SASL = "no" ; then
+ echo "Not asked to test SASL, skipping test, set SLAPD_USE_SASL to enable..."
+ exit 0
+ fi
+ if test $USE_SASL = "yes" ; then
+ MECH="DIGEST-MD5"
+ else
+ MECH="$USE_SASL"
+ fi
+ echo "Using SASL authc[/authz] with mech=$MECH; unset SLAPD_USE_SASL to disable"
+else
+ echo "SASL support not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+cp -r $DATADIR/tls $TESTDIR
+
+cd $TESTWD
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $TLSSASLCONF > $CONF2
+echo 'authz-regexp "^uid=([^,]*),.+" ldap:///dc=example,dc=com??sub?(|(cn=$1)(uid=$1))' >>$CONF2
+$SLAPADD -f $CONF2 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting a slapd on TCP/IP port $PORT2..."
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+PID2="$PID"
+KILLPIDS="$PID"
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONFTWO > $CONF3
+echo 'authz-regexp "^uid=([^,]*),.+" ldap:///dc=example,dc=com??sub?(|(cn=$1)(uid=$1))' >>$CONF3
+$SLAPADD -f $CONF3 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+$SLAPINDEX -f $CONF3
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+echo "Starting second slapd on TCP/IP port $PORT3..."
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+PID2="$PID"
+KILLPIDS="$KILLPIDS $PID"
+
+sleep $SLEEP0
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI3 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting lloadd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $LLOADDSASLCONF > $CONF1.lloadd
+if test $AC_lloadd = lloaddyes; then
+ $LLOADD -f $CONF1.lloadd -h $URI1 -d $LVL > $LOG1 2>&1 &
+else
+ . $CONFFILTER $BACKEND < $SLAPDLLOADCONF > $CONF1.slapd
+ $SLAPD -f $CONF1.slapd -h $URI6 -d $LVL > $LOG1 2>&1 &
+fi
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+echo "Testing lloadd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for lloadd to start..."
+ sleep $SLEEP1
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Checking whether $MECH is supported..."
+$LDAPSEARCH -s base -b "" -H $URI1 \
+ 'objectClass=*' supportedSASLMechanisms > $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+grep "supportedSASLMechanisms: $MECH" $SEARCHOUT > $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "SASL mechanism $MECH is not available, test skipped"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+fi
+
+AUTHZID="u:bjorn"
+echo "Testing lloadd's identity can assert any authzid..."
+$LDAPWHOAMI -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ -e\!"authzid=$AUTHZID" > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+AUTHZID="u:bjorn"
+echo "Testing a different identity cannot do the same thing..."
+$LDAPWHOAMI -D "$BABSDN" -H $URI1 -w bjensen \
+ -e\!"authzid=$AUTHZID" >> $TESTOUT 2>/dev/null
+RC=$?
+if test $RC != 1 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Validating WhoAmI? results..."
+echo 'dn:cn=bjorn jensen,ou=information technology division,ou=people,dc=example,dc=com' > $TESTDIR/whoami.out
+echo 'Result: Protocol error (2)
+Additional info: proxy authorization control specified multiple times' >> $TESTDIR/whoami.out
+$CMP $TESTDIR/whoami.out $TESTOUT > $CMPOUT
+
+RC=$?
+if test $RC != 0 ; then
+ echo "Comparison failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+else
+ echo "Success"
+fi
+
+
+ID="jaj"
+echo "Testing ldapsearch as $ID for \"$BASEDN\" with SASL bind and identity assertion..."
+$LDAPSASLSEARCH -H $URI1 -b "$BASEDN" \
+ -Q -Y $MECH -O maxbufsize=0 -U "$ID" -w jaj > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER -s e < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER -s e < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - search with SASL bind and identity assertion didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $RC != 0 ; then
+ echo ">>>>> Test failed"
+else
+ echo ">>>>> Test succeeded"
+ RC=0
+fi
+
+test $KILLSERVERS != no && wait
+
+exit $RC
diff --git a/tests/scripts/lloadd/test007-coherence b/tests/scripts/lloadd/test007-coherence
new file mode 100755
index 0000000..cda6dea
--- /dev/null
+++ b/tests/scripts/lloadd/test007-coherence
@@ -0,0 +1,508 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+# Cannot assess where operations went without monitor yet
+if test $AC_lloadd = lloaddyes ; then
+ echo "Load balancer module not available, skipping..."
+ exit 0
+fi
+
+# Monitor counts are unstable in the face of concurrency, since different
+# clients may get different upstreams assigned for their operations.
+# Another constraint is that some global counts are updated by the statistics
+# collection task scheduled to run every second.
+#
+# This test assumes current round-robin policy:
+# - default backend is rotated every time we successfully pick an upstream
+# (except when already linked)
+# - upstream connections within the same backend are rotated in the same way
+# - the monitor entry order for upstream connections reflects the connection
+# order within its CIRCLEQ_
+
+echo "Starting the first slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $CONF > $CONF2
+$SLAPADD -f $CONF2 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+$SLAPINDEX -f $CONF2
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+PID2="$PID"
+KILLPIDS="$PID"
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONFTWO > $CONF3
+$SLAPADD -f $CONF3 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+$SLAPINDEX -f $CONF3
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+echo "Starting second slapd on TCP/IP port $PORT3..."
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+PID3="$PID"
+KILLPIDS="$KILLPIDS $PID"
+
+sleep $SLEEP0
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI3 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting lloadd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $LLOADDEMPTYCONF > $CONF1.lloadd
+. $CONFFILTER $BACKEND < $SLAPDLLOADCONF > $CONF1.slapd
+$SLAPD -f $CONF1.slapd -h $URI6 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI6 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for lloadd to start..."
+ sleep $SLEEP1
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Setting up restrictions..."
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcBackend={0}lload,cn=config
+changetype: modify
+replace: olcBkLloadWriteCoherence
+olcBkLloadWriteCoherence: 3
+-
+add: olcBkLloadRestrictExop
+# Modify Password Exop
+olcBkLloadRestrictExop: 1.3.6.1.4.1.4203.1.11.1 write
+# LDAP Transaction Exop
+olcBkLloadRestrictExop: 1.3.6.1.1.21.1 connection
+# Cancel Exop
+olcBkLloadRestrictExop: 1.3.6.1.1.8 reject
+-
+add: olcBkLloadRestrictControl
+# assert control
+olcBkLloadRestrictControl: 1.3.6.1.1.12 backend
+# paged results control
+olcBkLloadRestrictControl: 1.2.840.113556.1.4.319 connection
+# dontUseCopy control
+olcBkLloadRestrictControl: 1.3.6.1.1.22 reject
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for backend ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Sending a search request to prime the counters..."
+$LDAPSEARCH -b "$BASEDN" -s base -H $URI1 >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 52 ; then
+ echo "ldapsearch should have failed ($RC != 52)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding first tier..."
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=first,olcBackend={0}lload,cn=config
+changetype: add
+objectClass: olcBkLloadTierConfig
+olcBkLloadTierType: roundrobin
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for backend ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding first backend server..."
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=backend,cn={0}first,olcBackend={0}lload,cn=config
+changetype: add
+objectClass: olcBkLloadBackendConfig
+olcBkLloadBackendUri: $URI2
+olcBkLloadMaxPendingConns: 3
+olcBkLloadMaxPendingOps: 5
+olcBkLloadRetry: 1000
+olcBkLloadNumconns: 2
+olcBkLloadBindconns: 2
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for backend ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# At the moment, the global counters are updated by a recurring job,
+# wait for it to settle
+echo "Waiting until connections are established..."
+for i in 0 1 2 3 4 5; do
+ $LDAPCOMPARE "cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ 'olmOutgoingConnections:4' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 6 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds until connections are established..."
+ sleep $SLEEP1
+done
+if test $RC != 6 ; then
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Retrieving data from cn=monitor..."
+echo "# Retrieving data from lload's cn=monitor..." >>$SEARCHOUT
+echo "# Operations received:" >>$SEARCHOUT
+echo "# Bind: 1 (0 forwarded)" >>$SEARCHOUT
+echo "# Unbind: 1" >>$SEARCHOUT
+$LDAPSEARCH -b "cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ olmBalancer olmBalancerServer olmBalancerOperation olmBalancerConnection >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding another backend server..."
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=server 2,cn={0}first,olcBackend={0}lload,cn=config
+changetype: add
+objectClass: olcBkLloadBackendConfig
+olcBkLloadBackendUri: $URI3
+olcBkLloadMaxPendingConns: 3
+olcBkLloadMaxPendingOps: 5
+olcBkLloadRetry: 1000
+olcBkLloadNumconns: 4
+olcBkLloadBindconns: 5
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for backend ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# At the moment, the global counters are updated by a recurring job,
+# wait for it to settle
+echo "Waiting until connections are established..."
+for i in 0 1 2 3 4 5; do
+ $LDAPCOMPARE "cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ 'olmOutgoingConnections:13' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 6 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds until connections are established..."
+ sleep $SLEEP1
+done
+if test $RC != 6 ; then
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Sending a search request with dontUseCopy (fails with Unwilling to Perform)..."
+$LDAPSEARCH -b "$BASEDN" -s base -H $URI1 -E '!dontUseCopy' >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 53 ; then
+ echo "ldapsearch should have failed ($RC != 53)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Sending a search request with paged results=1 (19 requests forwarded over the same connection)..."
+$LDAPSEARCH -b "$BASEDN" -H $URI1 -E '!pr=1/noprompt' >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Sending a passmod request..."
+$LDAPPASSWD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -s bjensen2 "$BABSDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# At the moment, the global counters are updated by a recurring job,
+# wait for it to settle
+echo "Waiting until global counters are updated..."
+for i in 0 1 2 3 4 5; do
+ $LDAPCOMPARE "cn=Other,cn=Operations,cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ 'olmCompletedOps:20' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 6 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds until counters are updated..."
+ sleep $SLEEP1
+done
+if test $RC != 6 ; then
+ echo "ldapcompare failed ($RC)!"
+ echo >>$SEARCHOUT
+ $LDAPSEARCH -b "cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ olmBalancer olmBalancerServer olmBalancerOperation olmBalancerConnection >> $SEARCHOUT 2>&1
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Retrieving data from cn=monitor again..."
+echo >>$SEARCHOUT
+echo "# Retrieving data after recent ops..." >>$SEARCHOUT
+echo "# Operations now received:" >>$SEARCHOUT
+echo "# Bind: +3 (+3 forwarded)" >>$SEARCHOUT
+echo "# Search: +20" >>$SEARCHOUT
+echo "# Extended: +1 (Password modify)" >>$SEARCHOUT
+echo "# Unbind: +3" >>$SEARCHOUT
+$LDAPSEARCH -b "cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ olmBalancer olmBalancerServer olmBalancerOperation olmBalancerConnection >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Sending a few writes (some of them will stick to the same backend)..."
+{
+cat <<EOMOD
+dn: $BABSDN
+changetype: modify
+replace: description
+description: changed
+
+dn: $BJORNSDN
+changetype: modify
+replace: description
+description: changed too
+
+EOMOD
+# If we had full control over the connection, we'd know when the last operation
+# finished and so when the grace period ends. We only write to a pipe, just
+# have to wait a bit longer than necessary...
+sleep 5
+cat <<EOMOD
+dn: $JAJDN
+changetype: modify
+replace: description
+description: modified
+
+EOMOD
+} | \
+$LDAPMODIFY -D "$MANAGERDN" -w $PASSWD -H $URI1 >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Sending a few writes within a TXN..."
+{
+cat <<EOMOD
+dn: $BABSDN
+changetype: modify
+replace: description
+description: changed
+
+dn: $BJORNSDN
+changetype: modify
+replace: description
+description: changed too
+
+EOMOD
+sleep 4
+cat <<EOMOD
+dn: $JAJDN
+changetype: modify
+replace: description
+description: modified
+
+EOMOD
+} | \
+$LDAPMODIFY -D "$MANAGERDN" -w $PASSWD -H $URI1 \
+ -e assert='(objectclass=*)' -E txn=abort >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# At the moment, the global counters are updated by a recurring job,
+# wait for it to settle
+echo "Waiting until global counters are updated..."
+for i in 0 1 2 3 4 5; do
+ $LDAPCOMPARE "cn=Other,cn=Operations,cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ 'olmCompletedOps:28' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 6 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds until counters are updated..."
+ sleep $SLEEP1
+done
+if test $RC != 6 ; then
+ echo "ldapcompare failed ($RC)!"
+ echo >>$SEARCHOUT
+ $LDAPSEARCH -b "cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ olmBalancer olmBalancerServer olmBalancerOperation olmBalancerConnection >> $SEARCHOUT 2>&1
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Retrieving data from cn=monitor again..."
+echo >>$SEARCHOUT
+echo "# Retrieving data after recent writes..." >>$SEARCHOUT
+echo "# Operations received:" >>$SEARCHOUT
+echo "# Bind: +2 (+2 forwarded)" >>$SEARCHOUT
+echo "# Modify: +6" >>$SEARCHOUT
+echo "# Extended: +2 (TXN+TXN Abort)" >>$SEARCHOUT
+echo "# Unbind: +2" >>$SEARCHOUT
+$LDAPSEARCH -b "cn=Load Balancer,cn=Backends,cn=monitor" -H $URI6 \
+ olmBalancer olmBalancerServer olmBalancerOperation olmBalancerConnection >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$DATADIR/lloadd/test007-monitor.ldif
+
+echo "Filtering ldapsearch results..."
+# For now, we don't make sure olmIncomingConnections is reflective of current
+# state (=no connections open) since olmIncomingConnections can be != 0 for a
+# second after it's closed
+$LDIFFILTER < $SEARCHOUT | grep -v '^olmIncomingConnections:' > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF | sed \
+ -e "s|@URI2@|$URI2|g" \
+ -e "s|@URI3@|$URI3|g" \
+ > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/monitor_data.sh b/tests/scripts/monitor_data.sh
new file mode 100755
index 0000000..7d08eda
--- /dev/null
+++ b/tests/scripts/monitor_data.sh
@@ -0,0 +1,42 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+SRCDIR="$1"
+DSTDIR="$2"
+
+echo "SRCDIR $SRCDIR"
+echo "DSTDIR $DSTDIR"
+echo "pwd `pwd`"
+
+# copy test data
+cp "$SRCDIR"/do_* "$DSTDIR"
+
+# add back-monitor testing data
+cat >> "$DSTDIR/do_search.0" << EOF
+cn=Monitor
+(objectClass=*)
+cn=Monitor
+(objectClass=*)
+cn=Monitor
+(objectClass=*)
+cn=Monitor
+(objectClass=*)
+EOF
+
+cat >> "$DSTDIR/do_read.0" << EOF
+cn=Backend 1,cn=Backends,cn=Monitor
+cn=Entries,cn=Statistics,cn=Monitor
+cn=Database 1,cn=Databases,cn=Monitor
+EOF
diff --git a/tests/scripts/passwd-search b/tests/scripts/passwd-search
new file mode 100755
index 0000000..ecb07e9
--- /dev/null
+++ b/tests/scripts/passwd-search
@@ -0,0 +1,133 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+if test $# -eq 0 ; then
+ test -z "$SRCDIR" && SRCDIR="."
+else
+ SRCDIR=$1; shift
+fi
+if test $# -eq 1 ; then
+ BACKEND=$1; shift
+fi
+
+echo "running defines.sh $SRCDIR $BACKEND"
+. $SRCDIR/scripts/defines.sh
+
+if test -d "$TESTDIR"; then
+ echo "Cleaning up in $TESTDIR..."
+ /bin/rm -rf $TESTDIR/db.*
+fi
+mkdir -p $TESTDIR
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $PASSWDCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test ${WAIT-0} != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -L -b "$BASEDN" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 1 ; then
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+ fi
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed!"
+ test "$KILLSERVERS" != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+cat /dev/null > $TESTOUT
+
+echo "Testing base suffix searching..."
+$LDAPSEARCH -L -S "" -b "$BASEDN" -s base -H $URI1 \
+ '(objectclass=*)' >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed!"
+ test "$KILLSERVERS" != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo " ------------ " >> $TESTOUT
+
+echo "Testing user searching..."
+$LDAPSEARCH -L -S "" -b "uid=root,$BASEDN" -s base -H $URI1 \
+ '(objectclass=*)' >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed!"
+ test "$KILLSERVERS" != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo " ------------ " >> $TESTOUT
+
+echo "Testing exact searching..."
+$LDAPSEARCH -L -S "" -b "$BASEDN" -H $URI1 \
+ '(uid=root)' >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed!"
+ test "$KILLSERVERS" != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo " ------------ " >> $TESTOUT
+
+echo "Testing OR searching..."
+$LDAPSEARCH -L -S "" -b "$BASEDN" -H $URI1 \
+ '(|(objectclass=person)(cn=root))' >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed!"
+ test "$KILLSERVERS" != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo " ------------ " >> $TESTOUT
+
+echo "Testing AND searching..."
+$LDAPSEARCH -L -S "" -b "$BASEDN" -H $URI1 \
+ '(&(objectclass=person)(cn=root))' >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed!"
+ test "$KILLSERVERS" != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test "$KILLSERVERS" != no && kill -HUP $KILLPIDS
+
+echo "Assuming everything is fine."
+#echo "Comparing results"
+#$CMP $TESTOUT $SEARCHOUTPROVIDER
+#if test $? != 0 ; then
+# echo "Comparison failed"
+# exit 1
+#fi
+
+echo ">>>>> Test succeeded"
+
+exit 0
diff --git a/tests/scripts/relay b/tests/scripts/relay
new file mode 100755
index 0000000..c0e6181
--- /dev/null
+++ b/tests/scripts/relay
@@ -0,0 +1,395 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 "Using $RELAY backend..."
+echo ""
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+echo "======== Starting slapd with $RELAY backend ========" >> $LOG1
+. $CONFFILTER $BACKEND < $RELAYCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL >> $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ '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 "Using ldapadd to populate the database..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDERED > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+cat /dev/null > $SEARCHOUT
+
+BASEDN="dc=example,dc=com"
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S '' -H $URI1 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BASEDN="o=Example,c=US"
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S '' -H $URI1 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BASEDN="o=Esempio,c=IT"
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S '' -H $URI1 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BASEDN="o=Beispiel,c=DE"
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S '' -H $URI1 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#
+# Do some modifications
+#
+
+BASEDN="o=Beispiel,c=DE"
+echo "Modifying database \"$BASEDN\"..."
+$LDAPMODIFY -v -D "cn=Manager,$BASEDN" -H $URI1 -w $PASSWD \
+ -M >> $TESTOUT 2>&1 << EOMODS
+dn: cn=Added User,ou=Alumni Association,ou=People,$BASEDN
+changetype: add
+objectClass: OpenLDAPperson
+cn: Added User
+sn: User
+uid: auser
+seealso: cn=All Staff,ou=Groups,$BASEDN
+homephone: +49 1234567890
+drink: Beer
+mail: auser@mail.alumni.example.com
+telephonenumber: +49 1234-567-890
+description: Just added in o=Beispiel,c=DE naming context
+
+dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,$BASEDN
+changetype: modify
+add: seeAlso
+seeAlso: cn=Ursula Hampster,ou=Alumni Association,ou=People,$BASEDN
+-
+add: description
+description: Just added self to seeAlso in $BASEDN virtual naming context
+-
+
+dn: cn=Mark Elliot,ou=Alumni Association,ou=People,$BASEDN
+changetype: delete
+
+dn: cn=John Doe,ou=Information Technology Division,ou=People,$BASEDN
+changetype: modrdn
+newrdn: cn=John P. Doe
+deleteoldrdn: 1
+
+dn: cn=Jane Doe,ou=Alumni Association,ou=People,$BASEDN
+changetype: modrdn
+newrdn: cn=Jane Q. Doe
+deleteoldrdn: 1
+newsuperior: ou=Information Technology Division,ou=People,$BASEDN
+
+dn: cn=Jane Q. Doe,ou=Information Technology Division,ou=People,$BASEDN
+changetype: modify
+add: cn
+cn: Jane Qissapaolo Doe
+-
+# This operation (delete of DN-valued attribute) triggered ITS#3498
+delete: seeAlso
+-
+
+dn: cn=Jane Q. Doe,ou=Information Technology Division,ou=People,$BASEDN
+changetype: modify
+add: seeAlso
+seeAlso: cn=All Staff,ou=Groups,$BASEDN
+-
+
+dn: ou=Referrals,$BASEDN
+changetype: add
+objectclass: referral
+objectclass: extensibleObject
+ou: Referrals
+ref: ldap://localhost.localdomain/ou=Referrals,$BASEDN
+description: Just added as ldap://localhost.localdomain:389/ou=Referrals,$BASEDN
+
+dn: ou=Referrals,$BASEDN
+changetype: modify
+replace: ref
+ref: ldap://localhost:9012/ou=Referrals,$BASEDN
+-
+add: description
+description: ...and modified as ldap://localhost:9012/ou=Referrals,$BASEDN
+-
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "Modify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BASEDN="o=Example,c=US"
+echo "Modifying database \"$BASEDN\"..."
+$LDAPMODIFY -v -D "cn=Manager,$BASEDN" -H $URI1 -w $PASSWD \
+ -M >> $TESTOUT 2>&1 << EOMODS
+# These operations (updates with objectClass mapping) triggered ITS#3499
+dn: cn=Added Group,ou=Groups,$BASEDN
+changetype: add
+objectClass: groupOfNames
+objectClass: uidObject
+cn: Added Group
+member: cn=Added Group,ou=Groups,$BASEDN
+uid: added
+
+dn: cn=Another Added Group,ou=Groups,$BASEDN
+changetype: add
+objectClass: groupOfNames
+cn: Another Added Group
+member: cn=Added Group,ou=Groups,$BASEDN
+member: cn=Another Added Group,ou=Groups,$BASEDN
+
+dn: cn=Another Added Group,ou=Groups,$BASEDN
+changetype: modify
+add: objectClass
+objectClass: uidObject
+-
+add: uid
+uid: added
+-
+
+dn: cn=Added Group,ou=Groups,$BASEDN
+changetype: modify
+delete: objectClass
+objectClass: uidObject
+-
+delete: uid
+-
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "Modify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S '' -H $URI1 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BASEDN="o=Esempio,c=IT"
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S '' -H $URI1 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(objectClass=referral)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"'*' ref\""
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"'*' ref\"" >> $SEARCHOUT
+
+BASEDN="dc=example,dc=com"
+echo " base=\"$BASEDN\"..."
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S '' -H $URI1 -b "$BASEDN" -M "$FILTER" '*' ref \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BASEDN="o=Example,c=US"
+echo " base=\"$BASEDN\"..."
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S '' -H $URI1 -b "$BASEDN" -M "$FILTER" '*' ref \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BASEDN="o=Esempio,c=IT"
+echo " base=\"$BASEDN\"..."
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S '' -H $URI1 -b "$BASEDN" -M "$FILTER" '*' ref \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BASEDN="o=Example,c=US"
+FILTER="(seeAlso=cn=all staff,ou=Groups,$BASEDN)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"seeAlso\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"seeAlso\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S '' -H $URI1 -b "$BASEDN" "$FILTER" seeAlso \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(uid=example)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"uid\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"uid\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S '' -H $URI1 -b "$BASEDN" "$FILTER" uid \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(member=cn=Another Added Group,ou=Groups,$BASEDN)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"member\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"member\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S '' -H $URI1 -b "$BASEDN" "$FILTER" member \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $RELAYOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - relay search/modification didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+BASEDN="o=Example,c=US"
+echo "Changing password to database \"$BASEDN\"..."
+$LDAPPASSWD -H $URI1 -D "cn=Manager,$BASEDN" -w $PASSWD \
+ -s $PASSWD "cn=Added User,ou=Alumni Association,ou=People,$BASEDN" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Passwd ExOp failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BASEDN="o=Beispiel,c=DE"
+echo "Binding with newly changed password to database \"$BASEDN\"..."
+$LDAPWHOAMI -H $URI1 \
+ -D "cn=Added User,ou=Alumni Association,ou=People,$BASEDN" \
+ -w $PASSWD >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "WhoAmI failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BASEDN="o=Esempio,c=IT"
+echo "Comparing to database \"$BASEDN\"..."
+$LDAPCOMPARE -H $URI1 \
+ "cn=Added User,ou=Alumni Association,ou=People,$BASEDN" \
+ "seeAlso:cn=All Staff,ou=Groups,$BASEDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 6 && test $RC,$BACKEND != 5,null ; then
+ echo "Compare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
diff --git a/tests/scripts/setup_kdc.sh b/tests/scripts/setup_kdc.sh
new file mode 100755
index 0000000..3402f45
--- /dev/null
+++ b/tests/scripts/setup_kdc.sh
@@ -0,0 +1,158 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+KRB5_TRACE=$TESTDIR/k5_trace
+KRB5_CONFIG=$TESTDIR/krb5.conf
+KRB5_KDC_PROFILE=$KRB5_CONFIG
+KRB5_KTNAME=$TESTDIR/server.kt
+KRB5_CLIENT_KTNAME=$TESTDIR/client.kt
+KRB5CCNAME=$TESTDIR/client.ccache
+
+export KRB5_TRACE KRB5_CONFIG KRB5_KDC_PROFILE KRB5_KTNAME KRB5_CLIENT_KTNAME KRB5CCNAME
+
+KDCLOG=$TESTDIR/setup_kdc.log
+KSERVICE=ldap/$LOCALHOST
+KUSER=kuser
+
+. $CONFFILTER < $DATADIR/krb5.conf > $KRB5_CONFIG
+
+PATH=${PATH}:/usr/lib/heimdal-servers:/usr/sbin:/usr/local/sbin
+
+echo "Trying Heimdal KDC..."
+
+command -v kdc >/dev/null 2>&1
+if test $? = 0 ; then
+ kstash --random-key > $KDCLOG 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "Heimdal: kstash failed, skipping GSSAPI tests"
+ exit 0
+ fi
+
+ flags="--realm-max-ticket-life=1h --realm-max-renewable-life=1h"
+ kadmin -l init $flags $KRB5REALM > $KDCLOG 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "Heimdal: kadmin init failed, skipping GSSAPI tests"
+ exit 0
+ fi
+
+ kadmin -l add --random-key --use-defaults $KSERVICE > $KDCLOG 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "Heimdal: kadmin add failed, skipping GSSAPI tests"
+ exit 0
+ fi
+
+ kadmin -l ext -k $KRB5_KTNAME $KSERVICE > $KDCLOG 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "Heimdal: kadmin ext failed, skipping GSSAPI tests"
+ exit 0
+ fi
+
+ kadmin -l add --random-key --use-defaults $KUSER > $KDCLOG 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "Heimdal: kadmin add failed, skipping GSSAPI tests"
+ exit 0
+ fi
+
+ kadmin -l ext -k $KRB5_CLIENT_KTNAME $KUSER > $KDCLOG 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "Heimdal: kadmin ext failed, skipping GSSAPI tests"
+ exit 0
+ fi
+
+ kdc --addresses=$LOCALIP --ports="$KDCPORT/udp" > $KDCLOG 2>&1 &
+else
+ echo "Trying MIT KDC..."
+
+ command -v krb5kdc >/dev/null 2>&1
+ if test $? != 0; then
+ echo "No KDC available, skipping GSSAPI tests"
+ exit 0
+ fi
+
+ kdb5_util create -r $KRB5REALM -s -P password > $KDCLOG 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "MIT: kdb5_util create failed, skipping GSSAPI tests"
+ exit 0
+ fi
+
+ kadmin.local -q "addprinc -randkey $KSERVICE" > $KDCLOG 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "MIT: admin addprinc failed, skipping GSSAPI tests"
+ exit 0
+ fi
+
+ kadmin.local -q "ktadd -k $KRB5_KTNAME $KSERVICE" > $KDCLOG 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "MIT: kadmin ktadd failed, skipping GSSAPI tests"
+ exit 0
+ fi
+
+ kadmin.local -q "addprinc -randkey $KUSER" > $KDCLOG 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "MIT: kadmin addprinc failed, skipping GSSAPI tests"
+ exit 0
+ fi
+
+ kadmin.local -q "ktadd -k $KRB5_CLIENT_KTNAME $KUSER" > $KDCLOG 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "MIT: kadmin ktadd failed, skipping GSSAPI tests"
+ exit 0
+ fi
+
+ krb5kdc -n > $KDCLOG 2>&1 &
+fi
+
+KDCPROC=$!
+sleep 1
+
+kinit -kt $KRB5_CLIENT_KTNAME $KUSER > $KDCLOG 2>&1
+RC=$?
+if test $RC != 0 ; then
+ kill $KDCPROC
+ echo "SASL/GSSAPI: kinit failed, skipping GSSAPI tests"
+ exit 0
+fi
+
+pluginviewer -m GSSAPI > $TESTDIR/plugin_out 2>/dev/null
+RC=$?
+if test $RC != 0 ; then
+
+ saslpluginviewer -m GSSAPI > $TESTDIR/plugin_out 2>/dev/null
+ RC=$?
+ if test $RC != 0 ; then
+ kill $KDCPROC
+ echo "cyrus-sasl has no GSSAPI support, test skipped"
+ exit 0
+ fi
+fi
+
+HAVE_SASL_GSS_CBIND=no
+
+grep CHANNEL_BINDING $TESTDIR/plugin_out > /dev/null 2>&1
+RC=$?
+if test $RC = 0 ; then
+ HAVE_SASL_GSS_CBIND=yes
+fi
diff --git a/tests/scripts/sql-all b/tests/scripts/sql-all
new file mode 100755
index 0000000..c462c3c
--- /dev/null
+++ b/tests/scripts/sql-all
@@ -0,0 +1,70 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+SHTOOL="$SRCDIR/../build/shtool"
+
+TB="" TN=""
+if test -t 1 ; then
+ TB=`$SHTOOL echo -e "%B" 2>/dev/null`
+ TN=`$SHTOOL echo -e "%b" 2>/dev/null`
+fi
+
+SLEEPTIME=10
+
+echo "#######################################################################"
+echo "### ###"
+echo "### SQL tests ###"
+echo "### ###"
+echo "#######################################################################"
+echo "###"
+echo "### SQL tests require the sql backend, a properly configured"
+echo "### ODBC and a database populated with data from the applicable"
+echo "### servers/slapd/back-sql/rdbms_depend/* files."
+echo "###"
+echo "### Set SLAPD_USE_SQL to the desired RDBMS to enable this test;"
+echo "###"
+echo "### Currently supported RDBMSes are:"
+echo "### ibmdb2, mysql, pgsql"
+echo "###"
+echo "### Set SLAPD_USE_SQLWRITE=yes to enable the write tests"
+echo "###"
+echo "### See servers/slapd/back-sql/rdbms_depend/README for more "
+echo "### details on how to set up the RDBMS and the ODBC"
+echo "###"
+
+echo ">>>>> Executing all LDAP tests for $BACKEND"
+
+for CMD in $SRCDIR/scripts/sql-test*; do
+ # remove cruft from prior test
+ if test $PRESERVE = yes ; then
+ /bin/rm -rf testrun/db.*
+ else
+ /bin/rm -rf testrun
+ fi
+
+ echo ">>>>> Starting ${TB}`basename $CMD`${TN} ..."
+ $CMD
+ RC=$?
+ if test $RC -eq 0 ; then
+ echo ">>>>> $CMD completed ${TB}OK${TN}."
+ else
+ echo ">>>>> $CMD ${TB}failed${TN} (exit $RC)"
+ exit $RC
+ fi
+
+ echo ">>>>> waiting $SLEEPTIME seconds for things to exit"
+ sleep $SLEEPTIME
+ echo ""
+done
diff --git a/tests/scripts/sql-test000-read b/tests/scripts/sql-test000-read
new file mode 100755
index 0000000..6d1d766
--- /dev/null
+++ b/tests/scripts/sql-test000-read
@@ -0,0 +1,568 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $BACKSQL = "sqlno" ; then
+ echo "SQL backend not available, test skipped"
+ exit 0
+fi
+
+if test $RDBMS = "rdbmsno" ; then
+ echo "SQL test not requested, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $SQLCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+echo "Testing SQL backend read operations..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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
+
+BASEDN="dc=example,dc=com"
+BINDDN="cn=Mitya Kovalev,${BASEDN}"
+BINDPW="mit"
+echo -n "Testing correct bind... "
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo -n "Testing incorrect bind (should fail)... "
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w "XXX"
+RC=$?
+if test $RC = 0 ; then
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing baseobject search..."
+echo "# Testing baseobject search..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -s base -S "" \
+ >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing onelevel search..."
+echo "# Testing onelevel search..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -s one -S "" \
+ >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing subtree search..."
+echo "# Testing subtree search..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing subtree search with manageDSAit..."
+echo "# Testing subtree search with manageDSAit..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -M -S "" '*' ref \
+ >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing invalid filter..."
+echo "# Testing invalid filter..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" "(foo=)" \
+ >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing exact search..."
+echo "# Testing exact search..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" "(sn=Kovalev)" \
+ >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing substrings initial search..."
+echo "# Testing substrings initial search..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" "(cn=m*)" \
+ >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing substrings any search..."
+echo "# Testing substrings any search..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" "(cn=*m*)" \
+ >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing substrings final search..."
+echo "# Testing substrings final search..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" "(cn=*v)" \
+ >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing approx search..."
+echo "# Testing approx search..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" "(sn~=kovalev)" \
+ >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing extensible filter search..."
+echo "# Testing extensible filter search..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ "(sn:caseExactMatch:=Kovalev)" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing search for telephoneNumber..."
+echo "# Testing search for telephoneNumber..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ "(telephoneNumber=3322334)" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing AND search..."
+echo "# Testing AND search..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ "(&(sn=kovalev)(givenName=mitya))" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing AND search on objectClass..."
+echo "# Testing AND search on objectClass..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ "(&(objectClass=organization)(objectClass=dcObject))" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing OR search..."
+echo "# Testing OR search..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ "(|(sn=kovalev)(givenName=mitya))" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing OR search on objectClass..."
+echo "# Testing OR search on objectClass..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ "(|(objectClass=document)(objectClass=organization))" \
+ >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing NOT search..."
+echo "# Testing NOT search..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ '(!(sn=kovalev))' >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing NOT search on objectClass..."
+echo "# Testing NOT search on objectClass..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ '(!(objectClass=inetOrgPerson))' >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing NOT search on \"auxiliary\" objectClass..."
+echo "# Testing NOT search on \"auxiliary\" objectClass..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ '(!(objectClass=dcObject))' >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#### Needs work...
+echo "Testing NOT presence search... (disabled)"
+###echo "# Testing NOT presence search..." >> $SEARCHOUT
+###$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+### '(!(sn=*))' >> $SEARCHOUT 2>&1
+###
+###RC=$?
+###if test $RC != 0 ; then
+### echo "ldapsearch failed ($RC)!"
+### test $KILLSERVERS != no && kill -HUP $KILLPIDS
+### exit $RC
+###fi
+
+echo "Testing attribute inheritance in filter..."
+echo "# Testing attribute inheritance in filter..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ "(name=example)" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# ITS#4604
+echo "Testing undefined attribute in filter..."
+echo "# Testing undefined attribute in filter..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ "(|(o=example)(foobar=x))" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing objectClass inheritance in filter..."
+echo "# Testing objectClass inheritance in filter..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ "(objectClass=person)" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing \"auxiliary\" objectClass in filter..."
+echo "# Testing \"auxiliary\" objectClass in filter..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ "(objectClass=dcObject)" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing hasSubordinates in filter..."
+echo "# Testing hasSubordinates in filter..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ "(hasSubordinates=TRUE)" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing entryUUID in filter..."
+echo "# Testing entryUUID in filter..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ "(entryUUID=00000001-0000-0001-0000-000000000000)" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing attribute inheritance in requested attributes..."
+echo "# Testing attribute inheritance in requested attributes..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ "(sn=kovalev)" name >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing objectClass in requested attributes..."
+echo "# Testing objectClass in requested attributes..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ objectClass >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing operational attributes in request..."
+echo "# Testing operational attributes in request..." >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" \
+ '+' 2>&1 > $SEARCHFLT
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+grep -v '^entryCSN:' $SEARCHFLT >> $SEARCHOUT
+
+SIZELIMIT=4
+echo "Testing size limit..."
+$LDAPRSEARCH -H $URI1 -b "$BASEDN" \
+ -z $SIZELIMIT -S "" '(objectClass=*)' >$SEARCHFLT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHFLT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" -gt "$SIZELIMIT" ; then
+ echo "...error: got $COUNT entries instead of the requested $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ echo "...didn't bump into the requested size limit ($SIZELIMIT; got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" = "$SIZELIMIT" ; then
+ echo "...bumped into requested size limit ($SIZELIMIT)"
+ else
+ echo "...error: got $COUNT entries with a requested sizelimit of $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo -n "Testing compare (should be TRUE)... "
+$LDAPCOMPARE -H $URI1 "$BINDDN" \
+ "sn:kovalev" >> $TESTOUT 2>&1
+
+RC=$?
+case $RC in
+6)
+ echo "TRUE"
+ ;;
+5) echo "FALSE!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+*) echo "failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+esac
+
+echo -n "Testing compare (should be FALSE)... "
+$LDAPCOMPARE -H $URI1 "$BINDDN" \
+ "cn:foobar" >> $TESTOUT 2>&1
+
+RC=$?
+case $RC in
+6)
+ echo "TRUE!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+5) echo "FALSE"
+ ;;
+*) echo "failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+esac
+
+echo -n "Testing compare (should be UNDEFINED)... "
+$LDAPCOMPARE -H $URI1 "$BINDDN" \
+ "o:example" >> $TESTOUT 2>&1
+
+RC=$?
+case $RC in
+6)
+ echo "TRUE!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+5) echo "FALSE!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+*) echo "failed ($RC)"
+ ;;
+esac
+
+echo -n "Testing compare on hasSubordinates (should be TRUE)... "
+$LDAPCOMPARE -H $URI1 "$BASEDN" \
+ "hasSubordinates:TRUE" >> $TESTOUT 2>&1
+
+RC=$?
+case $RC in
+6)
+ echo "TRUE"
+ ;;
+5) echo "FALSE!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+*) echo "failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+esac
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif..."
+$LDIFFILTER < $SQLREAD > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - SQL search didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+exit 0
diff --git a/tests/scripts/sql-test001-concurrency b/tests/scripts/sql-test001-concurrency
new file mode 100755
index 0000000..d474070
--- /dev/null
+++ b/tests/scripts/sql-test001-concurrency
@@ -0,0 +1,138 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $BACKSQL = "sqlno" ; then
+ echo "SQL backend not available, test skipped"
+ exit 0
+fi
+
+if test $RDBMS = "rdbmsno" ; then
+ echo "SQL test not requested, test skipped"
+ exit 0
+fi
+
+if test "x$TESTLOOPS" = "x" ; then
+ TESTLOOPS=5
+fi
+
+if test "x$CHILDREN" = "x" ; then
+ CHILDREN="-j 4"
+else
+ CHILDREN="-j $CHILDREN"
+fi
+
+SQLDATADIR=$TESTDIR/sql-concurrency
+mkdir -p $TESTDIR $SQLDATADIR
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $SQLCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+echo "Testing SQL backend concurrency..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Using ldapsearch to retrieve all the entries..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $SEARCHOUT > $LDIFFLT
+
+if test "${RDBMSWRITE}" != "yes"; then
+ echo "write test disabled for ${RDBMS}; set SLAPD_USE_SQLWRITE=yes to enable"
+ cp $SQLCONCURRENCYDIR/do_read* $SQLCONCURRENCYDIR/do_search* \
+ $SQLCONCURRENCYDIR/do_bind* $SQLDATADIR
+else
+ case ${RDBMS} in
+ # list here the RDBMSes whose mapping allows writes
+ pgsql|ibmdb2)
+ cp $SQLCONCURRENCYDIR/do_* $SQLDATADIR
+ ;;
+ *)
+ echo "write is not supported for ${RDBMS}; performing read-only concurrency test"
+ cp $SQLCONCURRENCYDIR/do_read* $SQLCONCURRENCYDIR/do_search* \
+ $SQLCONCURRENCYDIR/do_bind* $SQLDATADIR
+ ;;
+ esac
+fi
+
+echo "Using tester for concurrent server access..."
+$SLAPDTESTER -P "$PROGDIR" -d "$SQLDATADIR" \
+ -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -l $TESTLOOPS $CHILDREN -FF
+RC=$?
+
+if test $RC != 0 ; then
+ echo "slapd-tester failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to retrieve all the entries..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - database was not created correctly"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+exit 0
+
diff --git a/tests/scripts/sql-test900-write b/tests/scripts/sql-test900-write
new file mode 100755
index 0000000..983d350
--- /dev/null
+++ b/tests/scripts/sql-test900-write
@@ -0,0 +1,573 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $BACKSQL = "sqlno" ; then
+ echo "SQL backend not available, test skipped"
+ exit 0
+fi
+
+if test $RDBMS = "rdbmsno" ; then
+ echo "SQL test not requested, test skipped"
+ exit 0
+fi
+
+if test "${RDBMSWRITE}" != "yes"; then
+ echo "write test disabled for ${RDBMS}; set SLAPD_USE_SQLWRITE=yes to enable"
+ exit 0
+fi
+
+mkdir -p $TESTDIR
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $SQLCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+echo "Testing SQL backend write operations..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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
+
+cat /dev/null > $SEARCHOUT
+
+BASEDN="dc=example,dc=com"
+
+echo "Using ldapsearch to retrieve all the entries..."
+echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" \
+ "objectClass=*" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+case ${RDBMS} in
+ # list here the RDBMSes whose mapping allows writes
+pgsql|ibmdb2)
+ MANAGERDN="cn=Manager,${BASEDN}"
+ echo "Testing add..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+# Adding an organization...
+dn: o=An Org,${BASEDN}
+changetype: add
+objectClass: organization
+o: An Org
+
+# Adding an organization with an "auxiliary" objectClass..
+dn: dc=subnet,${BASEDN}
+changetype: add
+objectClass: organization
+objectClass: dcObject
+o: SubNet
+dc: subnet
+
+# Adding another organization with an "auxiliary" objectClass..
+dn: dc=subnet2,${BASEDN}
+changetype: add
+objectClass: organization
+objectClass: dcObject
+o: SubNet 2
+dc: subnet2
+
+# Adding a person...
+dn: cn=Lev Tolstoij,${BASEDN}
+changetype: add
+objectClass: inetOrgPerson
+cn: Lev Tolstoij
+sn: Tolstoij
+givenName: Lev
+telephoneNumber: +39 02 XXXX YYYY
+telephoneNumber: +39 02 XXXX ZZZZ
+userPassword: tanja
+
+# Adding a person with an "auxiliary" objectClass...
+dn: cn=Some One,${BASEDN}
+changetype: add
+objectClass: inetOrgPerson
+objectClass: simpleSecurityObject
+cn: Some One
+sn: One
+givenName: Some
+telephoneNumber: +1 800 900 1234
+telephoneNumber: +1 800 900 1235
+userPassword: someone
+
+# Adding a person in another subtree...
+dn: cn=SubNet User,dc=subnet,${BASEDN}
+changetype: add
+objectClass: inetOrgPerson
+cn: SubNet User
+sn: User
+givenName: SubNet
+
+# Adding a document...
+dn: documentTitle=War and Peace,${BASEDN}
+changetype: add
+objectClass: document
+description: Historical novel
+documentTitle: War and Peace
+documentAuthor: cn=Lev Tolstoij,dc=example,dc=com
+documentIdentifier: document 3
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to retrieve all the entries..."
+ echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" \
+ "objectClass=*" >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Testing modify..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+# Deleting all telephone numbers...
+dn: cn=Some One,${BASEDN}
+changetype: modify
+delete: telephoneNumber
+-
+
+# Adding a telephone number...
+dn: cn=Mitya Kovalev,${BASEDN}
+changetype: modify
+add: telephoneNumber
+telephoneNumber: +1 800 123 4567
+-
+
+# Deleting a specific telephone number and adding a new one...
+dn: cn=Lev Tolstoij,${BASEDN}
+changetype: modify
+delete: telephoneNumber
+telephoneNumber: +39 02 XXXX YYYY
+-
+add: telephoneNumber
+telephoneNumber: +39 333 ZZZ 1234
+-
+
+# Adding an author to a document...
+dn: documentTitle=book1,${BASEDN}
+changetype: modify
+add: documentAuthor
+documentAuthor: cn=Lev Tolstoij,${BASEDN}
+-
+
+# Adding an author to another document...
+dn: documentTitle=book2,${BASEDN}
+changetype: modify
+add: documentAuthor
+documentAuthor: cn=Lev Tolstoij,${BASEDN}
+-
+
+# Adding an "auxiliary" objectClass...
+dn: cn=Mitya Kovalev,${BASEDN}
+changetype: modify
+add: objectClass
+objectClass: simpleSecurityObject
+-
+
+# Deleting an "auxiliary" objectClass...
+dn: cn=Some One,${BASEDN}
+changetype: modify
+delete: objectClass
+objectClass: simpleSecurityObject
+-
+
+# Deleting userPasswords
+dn: cn=Lev Tolstoij,${BASEDN}
+changetype: modify
+delete: userPassword
+-
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to retrieve all the entries..."
+ echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" \
+ "objectClass=*" >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Testing delete..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+# Deleting a person...
+dn: cn=Torvlobnor Puzdoy,${BASEDN}
+changetype: delete
+
+# Deleting a document...
+dn: documentTitle=book1,${BASEDN}
+changetype: delete
+
+# Deleting an organization with an "auxiliary" objectClass...
+dn: dc=subnet2,${BASEDN}
+changetype: delete
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to retrieve all the entries..."
+ echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" \
+ "objectClass=*" >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Testing rename..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+# Renaming an organization...
+dn: o=An Org,${BASEDN}
+changetype: modrdn
+newrdn: o=Renamed Org
+deleteoldrdn: 1
+
+# Moving a person to another subtree...
+dn: cn=Lev Tolstoij,${BASEDN}
+changetype: modrdn
+newrdn: cn=Lev Tolstoij
+deleteoldrdn: 0
+newsuperior: dc=subnet,${BASEDN}
+
+# Renaming a book...
+dn: documentTitle=book2,${BASEDN}
+changetype: modrdn
+newrdn: documentTitle=Renamed Book
+deleteoldrdn: 1
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to retrieve all the entries..."
+ echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" \
+ "objectClass=*" >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Adding a child to a referral (should fail)..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: cn=Should Fail,ou=Referral,${BASEDN}
+changetype: add
+objectClass: inetOrgPerson
+cn: Should Fail
+sn: Fail
+telephoneNumber: +39 02 23456789
+EOMODS
+
+ RC=$?
+ if test $RC = 0 ; then
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ echo "Modifying a referral (should fail)..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: ou=Referral,${BASEDN}
+changetype: modify
+replace: ref
+ref: ldap://localhost:9009/
+-
+EOMODS
+
+ RC=$?
+ if test $RC = 0 ; then
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ echo "Renaming a referral (should fail)..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: ou=Referral,${BASEDN}
+changetype: modrdn
+newrdn: ou=Renamed Referral
+deleteoldrdn: 1
+EOMODS
+
+ RC=$?
+ if test $RC = 0 ; then
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ echo "Deleting a referral (should fail)..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: ou=Referral,${BASEDN}
+changetype: delete
+EOMODS
+
+ RC=$?
+ if test $RC = 0 ; then
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ echo "Adding a referral..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 -M >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: ou=Another Referral,${BASEDN}
+changetype: add
+objectClass: referral
+objectClass: extensibleObject
+ou: Another Referral
+ref: ldap://localhost:9009/
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Modifying a referral with manageDSAit..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 -M >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: ou=Referral,${BASEDN}
+changetype: modify
+replace: ref
+ref: ldap://localhost:9009/
+-
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to retrieve the modified entry..."
+ echo "# Using ldapsearch to retrieve the modified entry..." >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "ou=Referral,$BASEDN" -M \
+ "objectClass=*" '*' ref >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Renaming a referral with manageDSAit..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 -M >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: ou=Referral,${BASEDN}
+changetype: modrdn
+newrdn: ou=Renamed Referral
+deleteoldrdn: 1
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to retrieve the renamed entry..."
+ echo "# Using ldapsearch to retrieve the renamed entry..." >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "ou=Renamed Referral,$BASEDN" -M \
+ "objectClass=*" '*' ref >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Deleting a referral with manageDSAit..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 -M >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: ou=Renamed Referral,${BASEDN}
+changetype: delete
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ BINDDN="cn=Mitya Kovalev,${BASEDN}"
+ BINDPW="mit"
+ NEWPW="newsecret"
+ echo "Testing passwd change..."
+ $LDAPPASSWD -H $URI1 \
+ -D "${BINDDN}" -w ${BINDPW} -s ${NEWPW} \
+ "$BINDDN" >> $TESTOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo -n "Testing bind with new secret... "
+ $LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $NEWPW
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ BINDDN="cn=Some One,${BASEDN}"
+ BINDPW="someone"
+ echo -n "Testing bind with newly added user... "
+ $LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to retrieve all the entries..."
+ echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" \
+ "objectClass=*" >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Filtering ldapsearch results..."
+ $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+ echo "Filtering modified ldif..."
+ $LDIFFILTER < $SQLWRITE > $LDIFFLT
+ echo "Comparing filter output..."
+ $CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+ if test $? != 0 ; then
+ echo "comparison failed - SQL mods search didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+
+*)
+ echo "apparently ${RDBMS} does not support writes; skipping..."
+ ;;
+esac
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+exit 0
diff --git a/tests/scripts/sql-test901-syncrepl b/tests/scripts/sql-test901-syncrepl
new file mode 100755
index 0000000..db94271
--- /dev/null
+++ b/tests/scripts/sql-test901-syncrepl
@@ -0,0 +1,692 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $BACKSQL = "sqlno" ; then
+ echo "SQL backend not available, test skipped"
+ exit 0
+fi
+
+if test $RDBMS = "rdbmsno" ; then
+ echo "SQL test not requested, test skipped"
+ exit 0
+fi
+
+if test "${RDBMSWRITE}" != "yes"; then
+ echo "write test disabled for ${RDBMS}; set SLAPD_USE_SQLWRITE=yes to enable"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR2A
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $SQLSRPROVIDERCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+echo "Testing SQL backend write operations..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Starting consumer slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $R1SRCONSUMERCONF > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+echo "Using ldapsearch to check that consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '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
+
+cat /dev/null > $SEARCHOUT
+
+echo "Using ldapsearch to retrieve all the entries from the provider..."
+echo "# Using ldapsearch to retrieve all the entries from the provider..." \
+ >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" \
+ -D "$MANAGERDN" -w $PASSWD \
+ "(!(objectClass=referral))" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+cat /dev/null > $SEARCHOUT2
+
+echo "Using ldapsearch to retrieve all the entries from the consumer..."
+echo "# Using ldapsearch to retrieve all the entries from the consumer..." \
+ >> $SEARCHOUT2
+$LDAPSEARCH -S "" -H $URI2 -b "$BASEDN" \
+ -D "$UPDATEDN" -w $PASSWD \
+ "(objectClass=*)" >> $SEARCHOUT2 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results from provider..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering ldapsearch results from consumer..."
+$LDIFFILTER < $SEARCHOUT2 > $SEARCHFLT2
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $SEARCHFLT2 > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+cat /dev/null > $SEARCHOUT
+
+echo "Using ldapsearch to retrieve all the entries..."
+echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" \
+ "objectClass=*" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+case ${RDBMS} in
+ # list here the RDBMSes whose mapping allows writes
+pgsql|ibmdb2)
+ MANAGERDN="cn=Manager,${BASEDN}"
+ echo "Testing add..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+# Adding an organization...
+dn: o=An Org,${BASEDN}
+changetype: add
+objectClass: organization
+o: An Org
+
+# Adding an organization with an "auxiliary" objectClass..
+dn: dc=subnet,${BASEDN}
+changetype: add
+objectClass: organization
+objectClass: dcObject
+o: SubNet
+dc: subnet
+
+# Adding another organization with an "auxiliary" objectClass..
+dn: dc=subnet2,${BASEDN}
+changetype: add
+objectClass: organization
+objectClass: dcObject
+o: SubNet 2
+dc: subnet2
+
+# Adding a person...
+dn: cn=Lev Tolstoij,${BASEDN}
+changetype: add
+objectClass: inetOrgPerson
+cn: Lev Tolstoij
+sn: Tolstoij
+givenName: Lev
+telephoneNumber: +39 02 XXXX YYYY
+telephoneNumber: +39 02 XXXX ZZZZ
+userPassword: tanja
+
+# Adding a person with an "auxiliary" objectClass...
+dn: cn=Some One,${BASEDN}
+changetype: add
+objectClass: inetOrgPerson
+objectClass: simpleSecurityObject
+cn: Some One
+sn: One
+givenName: Some
+telephoneNumber: +1 800 900 1234
+telephoneNumber: +1 800 900 1235
+userPassword: someone
+
+# Adding a person in another subtree...
+dn: cn=SubNet User,dc=subnet,${BASEDN}
+changetype: add
+objectClass: inetOrgPerson
+cn: SubNet User
+sn: User
+givenName: SubNet
+
+# Adding a document...
+dn: documentTitle=War and Peace,${BASEDN}
+changetype: add
+objectClass: document
+description: Historical novel
+documentTitle: War and Peace
+documentAuthor: cn=Lev Tolstoij,dc=example,dc=com
+documentIdentifier: document 3
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to retrieve all the entries..."
+ echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" \
+ "objectClass=*" >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Testing modify..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+# Deleting all telephone numbers...
+dn: cn=Some One,${BASEDN}
+changetype: modify
+delete: telephoneNumber
+-
+
+# Adding a telephone number...
+dn: cn=Mitya Kovalev,${BASEDN}
+changetype: modify
+add: telephoneNumber
+telephoneNumber: +1 800 123 4567
+-
+
+# Deleting a specific telephone number and adding a new one...
+dn: cn=Lev Tolstoij,${BASEDN}
+changetype: modify
+delete: telephoneNumber
+telephoneNumber: +39 02 XXXX YYYY
+-
+add: telephoneNumber
+telephoneNumber: +39 333 ZZZ 1234
+-
+
+# Adding an author to a document...
+dn: documentTitle=book1,${BASEDN}
+changetype: modify
+add: documentAuthor
+documentAuthor: cn=Lev Tolstoij,${BASEDN}
+-
+
+# Adding an author to another document...
+dn: documentTitle=book2,${BASEDN}
+changetype: modify
+add: documentAuthor
+documentAuthor: cn=Lev Tolstoij,${BASEDN}
+-
+
+# Adding an "auxiliary" objectClass...
+dn: cn=Mitya Kovalev,${BASEDN}
+changetype: modify
+add: objectClass
+objectClass: simpleSecurityObject
+-
+
+# Deleting an "auxiliary" objectClass...
+dn: cn=Some One,${BASEDN}
+changetype: modify
+delete: objectClass
+objectClass: simpleSecurityObject
+-
+
+# Deleting userPasswords
+dn: cn=Lev Tolstoij,${BASEDN}
+changetype: modify
+delete: userPassword
+-
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to retrieve all the entries..."
+ echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" \
+ "objectClass=*" >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Testing delete..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+# Deleting a person...
+dn: cn=Torvlobnor Puzdoy,${BASEDN}
+changetype: delete
+
+# Deleting a document...
+dn: documentTitle=book1,${BASEDN}
+changetype: delete
+
+# Deleting an organization with an "auxiliary" objectClass...
+dn: dc=subnet2,${BASEDN}
+changetype: delete
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to retrieve all the entries..."
+ echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" \
+ "objectClass=*" >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Testing rename..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+# Renaming an organization...
+dn: o=An Org,${BASEDN}
+changetype: modrdn
+newrdn: o=Renamed Org
+deleteoldrdn: 1
+
+# Moving a person to another subtree...
+dn: cn=Lev Tolstoij,${BASEDN}
+changetype: modrdn
+newrdn: cn=Lev Tolstoij
+deleteoldrdn: 0
+newsuperior: dc=subnet,${BASEDN}
+
+# Renaming a book...
+dn: documentTitle=book2,${BASEDN}
+changetype: modrdn
+newrdn: documentTitle=Renamed Book
+deleteoldrdn: 1
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to retrieve all the entries..."
+ echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" \
+ "objectClass=*" >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Adding a child to a referral (should fail)..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: cn=Should Fail,ou=Referral,${BASEDN}
+changetype: add
+objectClass: inetOrgPerson
+cn: Should Fail
+sn: Fail
+telephoneNumber: +39 02 23456789
+EOMODS
+
+ RC=$?
+ if test $RC = 0 ; then
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ echo "Modifying a referral (should fail)..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: ou=Referral,${BASEDN}
+changetype: modify
+replace: ref
+ref: ldap://localhost:9009/
+-
+EOMODS
+
+ RC=$?
+ if test $RC = 0 ; then
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ echo "Renaming a referral (should fail)..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: ou=Referral,${BASEDN}
+changetype: modrdn
+newrdn: ou=Renamed Referral
+deleteoldrdn: 1
+EOMODS
+
+ RC=$?
+ if test $RC = 0 ; then
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ echo "Deleting a referral (should fail)..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: ou=Referral,${BASEDN}
+changetype: delete
+EOMODS
+
+ RC=$?
+ if test $RC = 0 ; then
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ echo "Adding a referral..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 -M >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: ou=Another Referral,${BASEDN}
+changetype: add
+objectClass: referral
+objectClass: extensibleObject
+ou: Another Referral
+ref: ldap://localhost:9009/
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Modifying a referral with manageDSAit..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 -M >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: ou=Referral,${BASEDN}
+changetype: modify
+replace: ref
+ref: ldap://localhost:9009/
+-
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to retrieve the modified entry..."
+ echo "# Using ldapsearch to retrieve the modified entry..." >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "ou=Referral,$BASEDN" -M \
+ "objectClass=*" '*' ref >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Renaming a referral with manageDSAit..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 -M >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: ou=Referral,${BASEDN}
+changetype: modrdn
+newrdn: ou=Renamed Referral
+deleteoldrdn: 1
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to retrieve the renamed entry..."
+ echo "# Using ldapsearch to retrieve the renamed entry..." >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "ou=Renamed Referral,$BASEDN" -M \
+ "objectClass=*" '*' ref >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Deleting a referral with manageDSAit..."
+ $LDAPMODIFY -v -c -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 -M >> $TESTOUT 2>&1 << EOMODS
+version: 1
+
+dn: ou=Renamed Referral,${BASEDN}
+changetype: delete
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ BINDDN="cn=Mitya Kovalev,${BASEDN}"
+ BINDPW="mit"
+ NEWPW="newsecret"
+ echo "Testing passwd change..."
+ $LDAPPASSWD -H $URI1 \
+ -D "${BINDDN}" -w ${BINDPW} -s ${NEWPW} \
+ "$BINDDN" >> $TESTOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo -n "Testing bind with new secret... "
+ $LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $NEWPW
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ BINDDN="cn=Some One,${BASEDN}"
+ BINDPW="someone"
+ echo -n "Testing bind with newly added user... "
+ $LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to retrieve all the entries..."
+ echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" \
+ "objectClass=*" >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Filtering ldapsearch results..."
+ $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+ echo "Filtering modified ldif..."
+ $LDIFFILTER < $SQLWRITE > $LDIFFLT
+ echo "Comparing filter output..."
+ $CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+ if test $? != 0 ; then
+ echo "comparison failed - SQL mods search didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ echo "Waiting 25 seconds for provider to send changes..."
+ sleep 25
+
+ cat /dev/null > $SEARCHOUT
+
+ echo "Using ldapsearch to retrieve all the entries from the provider..."
+ echo "# Using ldapsearch to retrieve all the entries from the provider..." \
+ >> $SEARCHOUT
+ $LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" \
+ -D "$MANAGERDN" -w $PASSWD \
+ "(!(objectClass=referral))" >> $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ cat /dev/null > $SEARCHOUT2
+
+ echo "Using ldapsearch to retrieve all the entries from the consumer..."
+ echo "# Using ldapsearch to retrieve all the entries from the consumer..." \
+ >> $SEARCHOUT2
+ $LDAPSEARCH -S "" -H $URI2 -b "$BASEDN" \
+ -D "$UPDATEDN" -w $PASSWD \
+ "(objectClass=*)" >> $SEARCHOUT2 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Filtering ldapsearch results from provider..."
+ $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+ echo "Filtering ldapsearch results from consumer..."
+ $LDIFFILTER < $SEARCHOUT2 > $SEARCHFLT2
+ echo "Comparing filter output..."
+ $CMP $SEARCHFLT $SEARCHFLT2 > $CMPOUT
+
+ if test $? != 0 ; then
+ echo "Comparison failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+
+*)
+ echo "apparently ${RDBMS} does not support writes; skipping..."
+ ;;
+esac
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+exit 0
diff --git a/tests/scripts/start-server b/tests/scripts/start-server
new file mode 100755
index 0000000..aa8ea93
--- /dev/null
+++ b/tests/scripts/start-server
@@ -0,0 +1,63 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+
+echo "Using ldapsearch to retrieve all the entries..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 > $SEARCHOUT 2>&1
+ RC=$?
+ if test $RC = 1 ; then
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+ fi
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - database was not created correctly"
+ exit 1
+fi
+
+echo ">>>>> Server1 (pid=$PID) started"
+exit 0
diff --git a/tests/scripts/start-server-nolog b/tests/scripts/start-server-nolog
new file mode 100755
index 0000000..a183d54
--- /dev/null
+++ b/tests/scripts/start-server-nolog
@@ -0,0 +1,63 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL >> /dev/null 2>&1 &
+PID=$!
+
+echo "Using ldapsearch to retrieve all the entries..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 > $SEARCHOUT 2>&1
+ RC=$?
+ if test $RC = 1 ; then
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+ fi
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - database was not created correctly"
+ exit 1
+fi
+
+echo ">>>>> Server1 (pid=$PID) started"
+exit 0
diff --git a/tests/scripts/start-server2 b/tests/scripts/start-server2
new file mode 100755
index 0000000..044ef8e
--- /dev/null
+++ b/tests/scripts/start-server2
@@ -0,0 +1,42 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR2
+
+echo "Starting slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $CONFTWO > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+
+echo "Using ldapsearch to retrieve all the entries..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -S "" -b "" -s base -H $URI2 > $SERVER2OUT 2>&1
+ RC=$?
+ if test $RC = 1 ; then
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+ fi
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+echo ">>>>> Server2 (pid=$PID) started"
+exit 0
diff --git a/tests/scripts/start-server2-nolog b/tests/scripts/start-server2-nolog
new file mode 100755
index 0000000..965c2c4
--- /dev/null
+++ b/tests/scripts/start-server2-nolog
@@ -0,0 +1,42 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR2
+
+echo "Starting slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $CONFTWO > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > /dev/null 2>&1 &
+PID=$!
+
+echo "Using ldapsearch to retrieve all the entries..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -S "" -b "" -s base -H $URI2 > $SERVER2OUT 2>&1
+ RC=$?
+ if test $RC = 1 ; then
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+ fi
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+echo ">>>>> Server2 (pid=$PID) started"
+exit 0
diff --git a/tests/scripts/startup_nis_ldap_server.sh b/tests/scripts/startup_nis_ldap_server.sh
new file mode 100755
index 0000000..0830f20
--- /dev/null
+++ b/tests/scripts/startup_nis_ldap_server.sh
@@ -0,0 +1,56 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+if [ $# -eq 0 ]; then
+ SRCDIR="."
+else
+ SRCDIR=$1; shift
+fi
+if [ $# -eq 1 ]; then
+ BDB2=$1; shift
+fi
+
+. $SRCDIR/scripts/defines.sh $SRCDIR $BDB2
+
+# Sample NIS database in LDIF format
+NIS_LDIF=$SRCDIR/data/nis_sample.ldif
+
+# Sample configuration file for your LDAP server
+if test "$BACKEND" = "bdb2" ; then
+ NIS_CONF=$DATADIR/slapd-bdb2-nis-provider.conf
+else
+ NIS_CONF=$DATADIR/slapd-nis-provider.conf
+fi
+
+echo "Cleaning up in $DBDIR..."
+
+rm -f $DBDIR/[!C]*
+
+echo "Running slapadd to build slapd database..."
+$SLAPADD -f $NIS_CONF -l $NIS_LDIF
+RC=$?
+if [ $RC != 0 ]; then
+ echo "slapadd failed!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT..."
+$SLAPD -f $NIS_CONF -p $PORT -d $LVL > $PROVIDERLOG 2>&1 &
+PID=$!
+
+echo ">>>>> LDAP server with NIS schema is up! PID=$PID"
+
+
+exit 0
diff --git a/tests/scripts/test000-rootdse b/tests/scripts/test000-rootdse
new file mode 100755
index 0000000..e01d7ae
--- /dev/null
+++ b/tests/scripts/test000-rootdse
@@ -0,0 +1,82 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $SCHEMACONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to retrieve the root DSE..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -b "" -s base -H $URI1 \
+ '@extensibleObject' > $SEARCHOUT 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 "Using ldapsearch to retrieve the cn=Subschema..."
+ $LDAPSEARCH -b "cn=Subschema" -s base -H $URI1 \
+ '(&(objectClasses=top)(objectClasses=2.5.6.0))' cn objectClass \
+ >> $SEARCHOUT 2>&1
+ RC=$?
+
+fi
+
+if test $RC = 0 ; then
+ echo "Using ldapsearch to retrieve the cn=Monitor..."
+ $LDAPSEARCH -b "cn=Monitor" -s base -H $URI1 \
+ '@monitor' >> $SEARCHOUT 2>&1
+ RC=$?
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+cat $SEARCHOUT
+
+
+count=3
+if test $RC != 0 ; then
+ echo ">>>>> Test failed"
+else
+ RC=`grep '^dn:' $SEARCHOUT | wc -l`
+ if test $RC != $count ; then
+ echo ">>>>> Test failed: expected $count entries, got" $RC
+ RC=1
+ else
+ echo ">>>>> Test succeeded"
+ RC=0
+ fi
+fi
+
+test $KILLSERVERS != no && wait
+
+exit $RC
diff --git a/tests/scripts/test001-slapadd b/tests/scripts/test001-slapadd
new file mode 100755
index 0000000..fd5be88
--- /dev/null
+++ b/tests/scripts/test001-slapadd
@@ -0,0 +1,146 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to retrieve all the entries..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 > $SEARCHOUT 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 "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - database was not created correctly"
+ echo $SEARCHFLT $LDIFFLT
+ $DIFF $SEARCHFLT $LDIFFLT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+if test $BACKEND = ldif ; then
+ echo "Skipping test of unordered slapadd (unsupported in ldif backend)"
+else
+
+kill -HUP $KILLPIDS
+wait
+rm -f $DBDIR1/*
+
+BASE2="ou=test,dc=example,dc=com"
+sed -e "s;$BASEDN;$BASE2;" $ADDCONF > ${ADDCONF}2
+mv ${ADDCONF}2 $ADDCONF
+sed -e "s;$BASEDN;$BASE2;" $CONF1 > ${CONF1}2
+mv ${CONF1}2 $CONF1
+echo "Running slapadd with unordered LDIF..."
+$SLAPADD -f $ADDCONF -l $LDIFUNORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to retrieve all the entries..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -b "$BASE2" -H $URI1 > $SEARCHOUT 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 "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIFREORDERED > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - database was not created correctly"
+ echo $SEARCHFLT $LDIFFLT
+ $DIFF $SEARCHFLT $LDIFFLT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test002-populate b/tests/scripts/test002-populate
new file mode 100755
index 0000000..4ff45c7
--- /dev/null
+++ b/tests/scripts/test002-populate
@@ -0,0 +1,83 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+echo "Using ldapadd to populate the database..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDERED > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ 'objectclass=*' > $SEARCHOUT 2>&1
+RC=$?
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - database was not created correctly"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test003-search b/tests/scripts/test003-search
new file mode 100755
index 0000000..8ef54e5
--- /dev/null
+++ b/tests/scripts/test003-search
@@ -0,0 +1,155 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $MCONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPINDEX -f $CONF1
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(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 "Testing exact searching..."
+echo "# Testing exact searching..." > $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn=jENSEN)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing approximate searching..."
+echo "# Testing approximate searching..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn~=jENSEN)' name >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing OR searching..."
+echo "# Testing OR searching..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(|(givenname=Xx*yY*Z)(cn=)(undef=*)(objectclass=groupofnames)(sn=jones)(member=cn=Manager,dc=example,dc=com)(uniqueMember=cn=Manager,dc=example,dc=com))' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing AND matching and ends-with searching..."
+echo "# Testing AND matching and ends-with searching..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "ou=groups,$BASEDN" -s one -H $URI1 \
+ '(&(objectclass=groupofnames)(cn=A*)(member=cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com))' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing NOT searching..."
+echo "# Testing NOT searching..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(!(objectclass=pilotPerson))' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing objectClass/attributeType inheritance ..."
+echo "# Testing objectClass/attributeType inheritance ..." >> $SEARCHOUT
+$LDAPSEARCH -M -a never -S "" -b "$BASEDN" -H $URI1 \
+ '(&(objectClass=inetorgperson)(userid=uham))' \
+ "2.5.4.0" "userid" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$SEARCHOUTPROVIDER
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test004-modify b/tests/scripts/test004-modify
new file mode 100755
index 0000000..178346e
--- /dev/null
+++ b/tests/scripts/test004-modify
@@ -0,0 +1,122 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd modify operations..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Testing modify, add, and delete..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT -f $LDIFMODIFY
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapmodify to add an empty entry (should fail with protocolError)..."
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: cn=Foo Bar,dc=example,dc=com
+changetype: add
+# EMPTY SEQUENCE OF ATTRS
+EOMODS
+
+RC=$?
+case $RC in
+2)
+ echo " ldapmodify failed ($RC)"
+ ;;
+0)
+ echo " ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo " ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Using ldapsearch to retrieve all the entries..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ 'objectClass=*' > $SEARCHOUT 2>&1
+RC=$?
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+LDIF=$MODIFYOUTPROVIDER
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - modify operations did not complete correctly"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test005-modrdn b/tests/scripts/test005-modrdn
new file mode 100755
index 0000000..e05da81
--- /dev/null
+++ b/tests/scripts/test005-modrdn
@@ -0,0 +1,300 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1A $DBDIR1B
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONF2DB > $CONF1
+$SLAPADD -f $CONF1 -b "$BASEDN" -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd modrdn operations..."
+
+# Make sure we can search the database
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ 'objectClass=*' > $INITOUT 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
+
+# -r used to do remove of old rdn
+
+echo "Testing modrdn(deleteoldrdn=0)..."
+$LDAPMODRDN -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 'cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example, dc=com' 'cn=James A Jones III'
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodrdn failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing modrdn(deleteoldrdn=1)..."
+$LDAPMODRDN -D "$MANAGERDN" -r -H $URI1 -w $PASSWD >> \
+ $TESTOUT 2>&1 'cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example, dc=com' 'cn=James A Jones II'
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodrdn failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Ensure the new rdn's can be found
+
+echo "Using ldapsearch to retrieve entries using new rdn (cn=James A Jones III)..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ 'cn=James A Jones III' > $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+
+LDIF=$MODRDNOUTPROVIDER1
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - modrdn operations did not complete correctly"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+
+echo "Using ldapsearch to retrieve entries using new rdn (cn=James A Jones II)..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ 'cn=James A Jones II' > $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+
+LDIF=$MODRDNOUTPROVIDER2
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - modrdn operations did not complete correctly"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+# Ensure that you cannot find the entry for which the rdn was deleted as
+# an attribute.
+
+echo "Using ldapsearch to retrieve entries using removed rdn (cn=James A Jones 2)..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ 'cn=James A Jones 2' > $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+$CMP $SEARCHOUT - < /dev/null > $CMPOUT
+if test $? != 0 ; then
+ echo "failure: ldapsearch found attribute that was to be removed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Using ldapsearch to retrieve all the entries..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ 'objectClass=*' > $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+LDIF=$MODRDNOUTPROVIDER0
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - modrdn operations did not complete correctly"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+# Test that you can use modrdn with an attribute value which was previously
+# present
+
+echo "Testing modrdn(deleteoldrdn=1), modrdn with new rdn already an att val..."
+$LDAPMODRDN -D "$MANAGERDN" -r -H $URI1 -w $PASSWD > \
+ /dev/null 2>&1 'cn=James A Jones III, ou=Alumni Association, ou=People, dc=example, dc=com' 'cn=James A Jones 1'
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodrdn failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to retrieve entries using new rdn (cn=James A Jones 1)..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ 'cn=James A Jones 1' > $SEARCHOUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+LDIF=$MODRDNOUTPROVIDER3
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - modrdn operations did not complete correctly"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing modrdn to another database (should fail with affectsMultipleDSAs)"
+$LDAPMODRDN -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 'cn=All Staff,ou=Groups,dc=example,dc=com' 'cn=Everyone'
+RC=$?
+case $RC in
+0)
+ echo "ldapmodrdn succeeded, should have failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+71)
+ ;;
+*)
+ echo "ldapmodrdn failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing modrdn with newSuperior = target (should fail with unwillingToPerform)"
+$LDAPMODRDN -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 -s 'cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example, dc=com' \
+ 'cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example, dc=com' 'cn=James A Jones 1'
+
+RC=$?
+case $RC in
+0)
+ echo "ldapmodrdn succeeded, should have failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+53)
+ ;;
+*)
+ echo "ldapmodrdn failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing modrdn with newRdn exact same as target..."
+$LDAPMODRDN -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 'cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example, dc=com' 'cn=James A Jones 1'
+
+RC=$?
+case $RC in
+0)
+ ;;
+*)
+ echo "ldapmodrdn failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing modrdn with newRdn same as target, changed case..."
+$LDAPMODRDN -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 'cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example, dc=com' 'cn=James A JONES 1'
+
+RC=$?
+case $RC in
+0)
+ ;;
+*)
+ echo "ldapmodrdn failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test006-acls b/tests/scripts/test006-acls
new file mode 100755
index 0000000..18afbd4
--- /dev/null
+++ b/tests/scripts/test006-acls
@@ -0,0 +1,667 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+case "$BACKEND" in ldif | null)
+ echo "$BACKEND backend does not support access controls, test skipped"
+ exit 0
+esac
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $ACLCONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd access control..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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
+
+cat /dev/null > $SEARCHOUT
+
+echo "# Try to read an entry inside the Alumni Association container.
+# It should give us noSuchObject if we're not bound..." \
+>> $SEARCHOUT
+# FIXME: temporarily remove the "No such object" message to make
+# the test succeed even if SLAP_ACL_HONOR_DISCLOSE is not #define'd
+$LDAPSEARCH -b "$JAJDN" -H $URI1 "(objectclass=*)" \
+ 2>&1 | grep -v "No such object" >> $SEARCHOUT
+
+echo "# ... and should return all attributes if we're bound as anyone
+# under Example." \
+>> $SEARCHOUT
+$LDAPSEARCH -b "$JAJDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen "(objectclass=*)" >> $SEARCHOUT 2>&1
+
+# ITS#4253, ITS#4255
+echo "# Checking exact/regex attrval clause" >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ -b "$MELLIOTDN" -s base "(objectclass=*)" cn >> $SEARCHOUT 2>&1
+$LDAPSEARCH -H $URI1 \
+ -D "$BJORNSDN" -w bjorn \
+ -b "$MELLIOTDN" -s base "(objectclass=*)" cn >> $SEARCHOUT 2>&1
+
+$LDAPSEARCH -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ -b "$JOHNDDN" -s base "(objectclass=*)" cn >> $SEARCHOUT 2>&1
+$LDAPSEARCH -H $URI1 \
+ -D "$BJORNSDN" -w bjorn \
+ -b "$JOHNDDN" -s base "(objectclass=*)" cn >> $SEARCHOUT 2>&1
+
+$LDAPSEARCH -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ -b "$BJORNSDN" -s base "(objectclass=*)" cn >> $SEARCHOUT 2>&1
+$LDAPSEARCH -H $URI1 \
+ -D "$BJORNSDN" -w bjorn \
+ -b "$BABSDN" -s base "(objectclass=*)" cn >> $SEARCHOUT 2>&1
+
+# check selfwrite access (ITS#4587). 6 attempts are made:
+# 1) delete someone else (should fail)
+# 2) delete self (should succeed)
+# 3) add someone else (should fail)
+# 4) add someone else and self (should fail)
+# 5) add self and someone else (should fail)
+# 6) add self (should succeed)
+#
+$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: member
+member: $BABSDN
+EOMODS
+RC=$?
+case $RC in
+50)
+ ;;
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: member
+member: $JAJDN
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+add: member
+member: cn=Foo,ou=Bar
+EOMODS
+RC=$?
+case $RC in
+50)
+ ;;
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+add: member
+member: cn=Foo,ou=Bar
+member: $JAJDN
+EOMODS
+RC=$?
+case $RC in
+50)
+ ;;
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+add: member
+member: $JAJDN
+member: cn=Foo,ou=Bar
+EOMODS
+RC=$?
+case $RC in
+50)
+ ;;
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+add: member
+member: $JAJDN
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#
+# Check group access. Try to modify Babs' entry. Two attempts:
+# 1) bound as "James A Jones 1" - should fail
+# 2) bound as "Bjorn Jensen" - should succeed
+
+$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \
+ $TESTOUT 2>&1 << EOMODS5
+dn: $BABSDN
+changetype: modify
+replace: drink
+drink: wine
+EOMODS5
+RC=$?
+case $RC in
+50)
+ ;;
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$BJORNSDN" -H $URI1 -w bjorn >> \
+ $TESTOUT 2>&1 << EOMODS6
+dn: $BABSDN
+changetype: modify
+add: homephone
+homephone: +1 313 555 5444
+EOMODS6
+RC=$?
+case $RC in
+0)
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+#
+# Try to add a "member" attribute to the "ITD Staff" group. It should
+# fail when we add some DN other than our own, and should succeed when
+# we add our own DN.
+# bjensen
+$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \
+ $TESTOUT 2>&1 << EOMODS1
+version: 1
+dn: cn=ITD Staff, ou=Groups, dc=example, dc=com
+changetype: modify
+add: uniquemember
+uniquemember: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com
+EOMODS1
+RC=$?
+case $RC in
+50)
+ ;;
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \
+ $TESTOUT 2>&1 << EOMODS2
+version: 1
+
+dn: cn=ITD Staff, ou=Groups, dc=example, dc=com
+changetype: modify
+add: uniquemember
+uniquemember: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example, dc=com
+EOMODS2
+RC=$?
+case $RC in
+0)
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+#
+# Try to modify the "ITD Staff" group. Two attempts are made:
+# 1) bound as "James A Jones 1" - should fail
+# 2) bound as "Bjorn Jensen" - should succeed
+#
+$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \
+ $TESTOUT 2>&1 << EOMODS3
+
+dn: cn=ITD Staff, ou=Groups, dc=example, dc=com
+changetype: modify
+delete: description
+EOMODS3
+RC=$?
+case $RC in
+50)
+ ;;
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$BJORNSDN" -H $URI1 -w bjorn >> \
+ $TESTOUT 2>&1 << EOMODS4
+# COMMENT
+version: 1
+# comment
+dn: cn=ITD Staff, ou=Groups, dc=example, dc=com
+# comment
+changetype: modify
+# comment
+add: ou
+# comment
+ou: Groups
+# comment
+EOMODS4
+RC=$?
+case $RC in
+0)
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+#
+# Try to modify the "ITD Staff" group. Two attempts are made:
+# 1) bound as "James A Jones 1" - should succeed
+# 2) bound as "Barbara Jensen" - should fail
+# should exploit sets
+#
+$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \
+ $TESTOUT 2>&1 << EOMODS5
+dn: cn=Alumni Assoc Staff, ou=Groups, dc=example, dc=com
+changetype: modify
+add: description
+description: added by jaj (should succeed)
+-
+EOMODS5
+RC=$?
+case $RC in
+0)
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$BABSDN" -H $URI1 -w bjensen >> \
+ $TESTOUT 2>&1 << EOMODS6
+dn: cn=Alumni Assoc Staff, ou=Groups, dc=example, dc=com
+changetype: modify
+add: description
+description: added by bjensen (should fail)
+-
+EOMODS6
+RC=$?
+case $RC in
+50)
+ ;;
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \
+ $TESTOUT 2>&1 << EOMODS7
+dn: ou=Add & Delete,dc=example,dc=com
+changetype: add
+objectClass: organizationalUnit
+ou: Add & Delete
+EOMODS7
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$BABSDN" -H $URI1 -w bjensen >> \
+ $TESTOUT 2>&1 << EOMODS8
+dn: cn=Added by Babs (must fail),ou=Add & Delete,dc=example,dc=com
+changetype: add
+objectClass: inetOrgPerson
+cn: Added by Babs (must fail)
+sn: None
+EOMODS8
+RC=$?
+case $RC in
+50)
+ ;;
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$BJORNSDN" -H $URI1 -w bjorn >> \
+ $TESTOUT 2>&1 << EOMODS9
+dn: cn=Added by Bjorn (must succeed),ou=Add & Delete,dc=example,dc=com
+changetype: add
+objectClass: inetOrgPerson
+cn: Added by Bjorn (must succeed)
+sn: None
+
+dn: cn=Added by Bjorn (will be deleted),ou=Add & Delete,dc=example,dc=com
+changetype: add
+objectClass: inetOrgPerson
+cn: Added by Bjorn (will be deleted)
+sn: None
+
+dn: cn=Added by Bjorn (will be renamed),ou=Add & Delete,dc=example,dc=com
+changetype: add
+objectClass: inetOrgPerson
+cn: Added by Bjorn (will be renamed)
+sn: None
+
+dn: cn=Added by Bjorn (must succeed),ou=Add & Delete,dc=example,dc=com
+changetype: modify
+add: description
+description: this attribute value has been added __after__entry creation
+description: this attribute value will be deleted by Babs (must succeed)
+description: Bjorn will try to delete this attribute value (should fail)
+-
+EOMODS9
+RC=$?
+case $RC in
+0)
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$BJORNSDN" -H $URI1 -w bjorn >> \
+ $TESTOUT 2>&1 << EOMODS10
+dn: cn=Added by Bjorn (will be deleted),ou=Add & Delete,dc=example,dc=com
+changetype: delete
+EOMODS10
+RC=$?
+case $RC in
+50)
+ ;;
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$BJORNSDN" -H $URI1 -w bjorn >> \
+ $TESTOUT 2>&1 << EOMODS11
+dn: cn=Added by Bjorn (will be renamed),ou=Add & Delete,dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Added by Bjorn (renamed by Bjorn)
+deleteoldrdn: 1
+EOMODS11
+RC=$?
+case $RC in
+50)
+ ;;
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$BABSDN" -H $URI1 -w bjensen >> \
+ $TESTOUT 2>&1 << EOMODS12
+dn: cn=Added by Bjorn (will be renamed),ou=Add & Delete,dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Added by Bjorn (renamed by Babs)
+deleteoldrdn: 1
+EOMODS12
+RC=$?
+case $RC in
+50)
+ ;;
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \
+ $TESTOUT 2>&1 << EOMODS13
+dn: cn=Added by Bjorn (will be renamed),ou=Add & Delete,dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Added by Bjorn (renamed by Jaj)
+deleteoldrdn: 1
+EOMODS13
+RC=$?
+case $RC in
+0)
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$BJORNSDN" -H $URI1 -w bjorn >> \
+ $TESTOUT 2>&1 << EOMODS14
+dn: cn=Added by Bjorn (must succeed),ou=Add & Delete,dc=example,dc=com
+changetype: modify
+delete: description
+description: Bjorn will try to delete this attribute value (should fail)
+-
+EOMODS14
+RC=$?
+case $RC in
+50)
+ ;;
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+$LDAPMODIFY -D "$BABSDN" -H $URI1 -w bjensen >> \
+ $TESTOUT 2>&1 << EOMODS15
+dn: cn=Added by Bjorn (will be deleted),ou=Add & Delete,dc=example,dc=com
+changetype: delete
+
+dn: cn=Added by Bjorn (must succeed),ou=Add & Delete,dc=example,dc=com
+changetype: modify
+delete: description
+description: this attribute value will be deleted by Babs (must succeed)
+-
+EOMODS15
+RC=$?
+case $RC in
+0)
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Using ldapsearch to retrieve all the entries..."
+echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ 'objectClass=*' >> $SEARCHOUT 2>&1
+RC=$?
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+LDIF=$ACLOUTPROVIDER
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - operations did not complete correctly"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test007-slapmodify b/tests/scripts/test007-slapmodify
new file mode 100755
index 0000000..9acd579
--- /dev/null
+++ b/tests/scripts/test007-slapmodify
@@ -0,0 +1,90 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Testing modify, add, and delete using slapmodify..."
+$SLAPMODIFY -f $ADDCONF -d $LVL -l $LDIFMODIFY > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapmodify failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to retrieve all the entries..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 > $SEARCHOUT 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
+
+LDIF=$MODIFYOUTPROVIDER
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "modify operations did not complete correctly"
+ echo $SEARCHFLT $LDIFFLT
+ $DIFF $SEARCHFLT $LDIFFLT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test008-concurrency b/tests/scripts/test008-concurrency
new file mode 100755
index 0000000..2d71e3a
--- /dev/null
+++ b/tests/scripts/test008-concurrency
@@ -0,0 +1,99 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 x$TESTLOOPS = x ; then
+ TESTLOOPS=50
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFORDERED -d -1 2> $SLAPADDLOG1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+# fix test data to include back-monitor, if available
+# NOTE: copies do_* files from $DATADIR to $TESTDIR
+$MONITORDATA "$DATADIR" "$TESTDIR"
+
+echo "Using tester for concurrent server access..."
+$SLAPDTESTER -P "$PROGDIR" -d "$TESTDIR" -H $URI1 -D "$MANAGERDN" -w $PASSWD -l $TESTLOOPS
+RC=$?
+
+if test $RC != 0 ; then
+ echo "slapd-tester failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to retrieve all the entries..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ 'objectClass=*' > $SEARCHOUT 2>&1
+RC=$?
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - database was not created correctly"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test009-referral b/tests/scripts/test009-referral
new file mode 100755
index 0000000..b6f05fa
--- /dev/null
+++ b/tests/scripts/test009-referral
@@ -0,0 +1,181 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+#
+# Test default referral
+#
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting provider slapd on TCP/IP port $PORT1..."
+$SLAPD -n provider -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+
+echo "Starting consumer slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $REFCONSUMERCONF > $CONF2
+$SLAPD -n consumer -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+
+KILLPIDS="$PID $CONSUMERPID"
+
+sleep 1
+
+echo "Testing for provider slapd..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for provider 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 "Testing for consumer slapd..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for consumer slapd to start..."
+ sleep 5
+done
+
+cat /dev/null > $SEARCHOUT
+
+echo "Testing exact searching..."
+$LDAPSEARCH -C -S "" -b "$BASEDN" -H $URI2 \
+ 'sn=jensen' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing approximate searching..."
+$LDAPSEARCH -C -S "" -b "$BASEDN" -H $URI2 \
+ '(sn=jENSEN)' name >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing OR searching..."
+$LDAPSEARCH -C -S "" -b "$BASEDN" -H $URI2 \
+ '(|(objectclass=groupofnames)(objectClass=groupofuniquenames)(sn=jones))' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing AND matching and ends-with searching..."
+$LDAPSEARCH -C -S "" -b "ou=groups,$BASEDN" -s one -H $URI2 \
+ '(&(objectclass=groupofnames)(cn=A*))' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing NOT searching..."
+$LDAPSEARCH -C -S "" -b "$BASEDN" -H $URI2 \
+ '(!(objectclass=pilotPerson))' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing objectClass/attributeType inheritance ..."
+$LDAPSEARCH -M -a never -S "" -b "$BASEDN" -H $URI1 \
+ '(&(objectClass=inetorgperson)(userid=uham))' \
+ "2.5.4.0" "userid" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing dontUseCopy control..."
+$LDAPSEARCH -C -S "" -b "$BASEDN" -H $URI2 \
+ -E \!dontUseCopy \
+ 'sn=jensen' >> $SEARCHOUT
+RC=$?
+if test $RC = 10 ; then
+ echo "ldapsearch failed as expected ($RC)"
+else
+ echo "ldapsearch did not error as expected ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$SEARCHOUTPROVIDER
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test010-passwd b/tests/scripts/test010-passwd
new file mode 100755
index 0000000..ac6fbb9
--- /dev/null
+++ b/tests/scripts/test010-passwd
@@ -0,0 +1,189 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $PWCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+echo "Using ldapadd to populate the database..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFPASSWD > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo > $SEARCHOUT
+echo > $TESTOUT
+
+echo "Using ldapsearch to verify population ..."
+echo "++ Initial search" >> $SEARCHOUT
+$LDAPSEARCH -H $URI1 \
+ -D "$MANAGERDN" -w $PASSWD \
+ -b "$BASEDN" \
+ 'objectclass=*' >> $SEARCHOUT 2>&1
+
+echo "Using ldappasswd to test a few error conditions ..."
+echo "Pass 0" >> $TESTOUT
+$LDAPPASSWD -H $URI1 \
+ -w secret -a "" -s newsecret \
+ -D "cn=md5, $BASEDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "ldappasswd unexpectantly passed ($RC)! old empty"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+$LDAPPASSWD -H $URI1 \
+ -w secret -a oldsecret -s "" \
+ -D "cn=md5, $BASEDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "ldappasswd unexpectantly passed ($RC)! new empty"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+$LDAPPASSWD -H $URI1 \
+ -w secret -a oldsecret -s newsecret \
+ -D "cn=md5, $BASEDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "ldappasswd unexpectantly passed ($RC)! wrong old"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Using ldappasswd (PASS 1) ..."
+echo "Pass 1" >> $TESTOUT
+$LDAPPASSWD -H $URI1 \
+ -w secret -s newsecret \
+ -D "cn=md5, $BASEDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDAPPASSWD -H $URI1 \
+ -w $PASSWD -s newsecret \
+ -D "$MANAGERDN" "cn=smd5, $BASEDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDAPPASSWD -H $URI1 \
+ -w secret -s newsecret \
+ -D "cn=sha, $BASEDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDAPPASSWD -H $URI1 \
+ -w secret -s newsecret \
+ -D "cn=ssha, $BASEDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "" >> $TESTOUT
+echo "Pass 2" >> $TESTOUT
+echo "Using ldappasswd (PASS 2) ..."
+$LDAPPASSWD -H $URI1 \
+ -w newsecret \
+ -D "cn=md5, $BASEDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDAPPASSWD -H $URI1 \
+ -w newsecret \
+ -D "cn=smd5, $BASEDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDAPPASSWD -H $URI1 \
+ -w newsecret \
+ -D "cn=sha, $BASEDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDAPPASSWD -H $URI1 \
+ -w newsecret \
+ -D "cn=ssha, $BASEDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Logging end state with ldapsearch..."
+echo "" >> $TESTOUT
+echo "++ End search" >> $TESTOUT
+$LDAPSEARCH -H $URI1 \
+ -D "$MANAGERDN" -w $PASSWD \
+ -b "$BASEDN" \
+ 'objectclass=*' >> $TESTOUT 2>&1
+
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test011-glue-slapadd b/tests/scripts/test011-glue-slapadd
new file mode 100755
index 0000000..710263d
--- /dev/null
+++ b/tests/scripts/test011-glue-slapadd
@@ -0,0 +1,98 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1A $DBDIR1B $DBDIR1C
+
+echo "Running slapadd to build glued slapd databases..."
+. $CONFFILTER $BACKEND < $GLUECONF > $CONF1
+$SLAPADD -d $LVL -f $CONF1 -l $LDIFORDERED > $SLAPADDLOG1 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to retrieve all the entries..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -b "$BASEDN" -H $URI1 > $SEARCHOUT 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 "Filtering ldapsearch results..."
+$LDIFFILTER -s ldif=e < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER -s ldif=e < $LDIFGLUED > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - database was not created correctly"
+ echo $SEARCHFLT $LDIFFLT
+ $DIFF $SEARCHFLT $LDIFFLT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+if test $BACKEND != null ; then
+echo "Testing sizelimit..."
+$LDAPSEARCH -b "$BASEDN" -H $URI1 -s one -z 2 > $SEARCHOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "sizelimit not detected at end of search."
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+$LDAPSEARCH -b "$BASEDN" -H $URI1 -z 9 objectclass=OpenLDAPPerson > $SEARCHOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "sizelimit not detected at middle of search."
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test012-glue-populate b/tests/scripts/test012-glue-populate
new file mode 100755
index 0000000..121aa7c
--- /dev/null
+++ b/tests/scripts/test012-glue-populate
@@ -0,0 +1,83 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1A $DBDIR1B $DBDIR1C
+
+echo "Starting slapd on TCP/IP port $PORT..."
+. $CONFFILTER $BACKEND < $GLUECONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+echo "Using ldapadd to populate the glued database..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDERED > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries..."
+$LDAPSEARCH -b "$BASEDN" -H $URI1 \
+ 'objectclass=*' > $SEARCHOUT 2>&1
+RC=$?
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER -s ldif=e < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER -s ldif=e < $LDIFGLUED > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - database was not created correctly"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test013-language b/tests/scripts/test013-language
new file mode 100755
index 0000000..aa69c62
--- /dev/null
+++ b/tests/scripts/test013-language
@@ -0,0 +1,117 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+echo "Using ldapadd to populate the database..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFLANG > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 -s base \
+ '(&)' > $SEARCHOUT 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 read name ..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 -s base \
+ '(&)' 'name' >> $SEARCHOUT 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 read name language tag ..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 -s base \
+ '(&)' 'name;lang-en-US' >> $SEARCHOUT 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 read name language range ..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 -s base \
+ '(&)' 'name;lang-en-' >> $SEARCHOUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering language ldif ..."
+$LDIFFILTER < $LDIFLANGOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - language test failed!"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test014-whoami b/tests/scripts/test014-whoami
new file mode 100755
index 0000000..0e2f359
--- /dev/null
+++ b/tests/scripts/test014-whoami
@@ -0,0 +1,468 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $WHOAMICONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFWHOAMI
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT..."
+. $CONFFILTER $BACKEND < $WHOAMICONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+echo "Testing ldapwhoami as anonymous..."
+$LDAPWHOAMI -H $URI1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing ldapwhoami as ${MANAGERDN}..."
+$LDAPWHOAMI -H $URI1 -D "$MANAGERDN" -w $PASSWD
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing ldapwhoami as ${MANAGERDN} for anonymous..."
+$LDAPWHOAMI -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e \!authzid=""
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing ldapwhoami as ${MANAGERDN} for dn:$BABSDN..."
+$LDAPWHOAMI -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e \!authzid="dn:$BABSDN"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing ldapwhoami as ${MANAGERDN} for u:uham..."
+$LDAPWHOAMI -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e \!authzid="u:uham"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# authzFrom: someone else => bjorn
+echo "Testing authzFrom..."
+
+BINDDN="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjensen
+AUTHZID="u:bjorn"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (dn.exact)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com"
+BINDPW=melliot
+AUTHZID="u:bjorn"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (u)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com"
+BINDPW=jen
+AUTHZID="u:bjorn"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (URI)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=James A Jones 2,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=jjones
+AUTHZID="u:bjorn"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (group)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=No One,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=noone
+AUTHZID="u:bjorn"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (dn.onelevel)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com"
+BINDPW=dots
+AUTHZID="u:bjorn"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (dn.regex)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com"
+BINDPW=jaj
+AUTHZID="u:bjorn"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (dn.children)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=ITD Staff,ou=Groups,dc=example,dc=com"
+BINDPW=ITD
+AUTHZID="u:bjorn"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (dn.subtree)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=Should Fail,dc=example,dc=com"
+BINDPW=fail
+AUTHZID="u:bjorn"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (URI; should fail)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+case $RC in
+1)
+ ;;
+0)
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+BINDDN="cn=Must Fail,dc=example,dc=com"
+BINDPW=fail
+AUTHZID="u:bjorn"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (URI; should fail)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+case $RC in
+1)
+ ;;
+0)
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+# authzTo: bjorn => someone else
+echo "Testing authzTo..."
+
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+AUTHZID="u:bjensen"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (dn.exact)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+AUTHZID="u:melliot"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (u)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+AUTHZID="u:jdoe"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (URI)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+AUTHZID="u:jjones"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (group)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+AUTHZID="u:noone"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (dn.onelevel)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+AUTHZID="u:dots"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (dn.regex)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+AUTHZID="u:jaj"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (dn.children)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+AUTHZID="u:group/itd staff"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (dn.subtree)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+AUTHZID="u:fail"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (URI; should fail)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+case $RC in
+1)
+ ;;
+0)
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+AUTHZID="dn:cn=Should Fail,dc=example,dc=com"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (URI; should fail)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+case $RC in
+1)
+ ;;
+0)
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+AUTHZID="dn:cn=don't!"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID} (no authzTo; should fail)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 1 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+BINDDN="dc=example,dc=com"
+BINDPW=example
+AUTHZID="dn:"
+echo "Testing ldapwhoami as ${BINDDN} for ${AUTHZID}\"\" (dn.exact; should succeed)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW \
+ -e \!authzid="$AUTHZID"
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
+
+## Note to developers: when SLAPD_DEBUG=-1 the command
+## awk '/^do_extended$/ {if (c) {print c} c=0} /<===slap_sasl_match:/ {c++} END {print c}' $TESTDIR/slapd.1.log
+## must return the sequence 1 2 3 4 5 6 7 8 8 8 1 2 3 4 5 6 7 8 8 8 8 1
+## to indicate that the authzFrom and authzTo rules applied in the right order.
diff --git a/tests/scripts/test015-xsearch b/tests/scripts/test015-xsearch
new file mode 100755
index 0000000..b24d4a4
--- /dev/null
+++ b/tests/scripts/test015-xsearch
@@ -0,0 +1,272 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $MCONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPINDEX -f $CONF1
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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
+
+cat /dev/null > $SEARCHOUT
+
+echo "Testing exact searching..."
+echo "# Testing exact searching..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn:=jensen)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing approximate searching..."
+echo "# Testing approximate searching..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(sn~=jensen)' name >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing OR searching..."
+echo "# Testing OR searching..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(|(givenName=XX*YY*Z)(cn=)(undef=*)(objectclass=groupofnames)(objectclass=groupofuniquenames)(sn:caseExactMatch:=Jones))' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing AND matching and ends-with searching..."
+echo "# Testing AND matching and ends-with searching..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "ou=groups,$BASEDN" -s one -H $URI1 \
+ '(&(|(objectclass=groupofnames)(objectclass=groupofuniquenames))(cn=A*))' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing NOT searching..."
+echo "# Testing NOT searching..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(!(objectclass=pilotPerson))' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing objectClass/attributeType inheritance ..."
+echo "# Testing objectClass/attributeType inheritance ..." >> $SEARCHOUT
+$LDAPSEARCH -M -a never -S "" -b "$BASEDN" -H $URI1 \
+ '(&(objectClass=inetorgperson)(userid=uham))' \
+ "2.5.4.0" "userid" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing extended RFC2254 searching:"
+echo "# Testing extended RFC2254 searching:" >> $SEARCHOUT
+
+FILTER="(:dn:caseIgnoreIA5Match:=example)"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(:dn:caseExactMatch:=Information Technology Division)"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+# ITS#4380: don't crash when a matchingRule without pretty/validate is used
+FILTER="(:dn:caseIgnoreSubstringsMatch:=Information Technology Division)"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(name:dn:=whatever)"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "" -s base -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing values return filter searching:"
+echo "# Testing values return filter searching:" >> $SEARCHOUT
+
+FILTER="(o=Example, Inc.)"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -E '!mv='"$FILTER" "$FILTER" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(dc=example)"
+VRFILTER="((o:caseExactMatch:=Example, Inc.)(dc=example))"
+echo " f=$FILTER mv=$VRFILTER ..."
+echo "# f=$FILTER mv=$VRFILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -E '!mv='"$VRFILTER" "$FILTER" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(dc=example)"
+VRFILTER="((o={*)(dc=*))"
+echo " f=$FILTER mv=$VRFILTER ..."
+echo "# f=$FILTER mv=$VRFILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -E '!mv='"$VRFILTER" "$FILTER" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(attributeTypes=0.9.2342.19200300.100.1.25)"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "cn=Subschema" -s "base" -H $URI1 \
+ -E '!mv='"$FILTER" "$FILTER" "attributeTypes" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list substring searching..."
+echo "# Testing list substring searching..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(postalAddress=*Anytown*)' postalAddress >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$SEARCHOUTPROVIDER
+LDIF2=$SEARCHOUTX
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+$LDIFFILTER < $LDIF2 >> $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test016-subref b/tests/scripts/test016-subref
new file mode 100755
index 0000000..851532f
--- /dev/null
+++ b/tests/scripts/test016-subref
@@ -0,0 +1,197 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+RCODE=10
+test $BACKEND = null && RCODE=0
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $RCONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFREF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(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
+
+cat /dev/null > $SEARCHOUT
+
+echo "Testing ManageDsaIT searching at $REFDN..."
+$LDAPRSEARCH -S "" -MM -b "$REFDN" -H $URI1 \
+ '(objectClass=referral)' '*' ref >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing ManageDsaIT searching at referral object..."
+$LDAPRSEARCH -S "" -MM -b "o=abc,$REFDN" -H $URI1 \
+ '(objectClass=referral)' '*' ref >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing ManageDsaIT searching below referral object..."
+$LDAPRSEARCH -S "" -MM -b "uid=xxx,o=abc,$REFDN" -H $URI1 \
+ '(objectClass=referral)' '*' ref >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != $RCODE ; then
+ echo "ldapsearch: unexpected result ($RC)! (referral expected)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+XREFDN="$REFDN"
+echo "Testing base searching at $XREFDN..."
+$LDAPRSEARCH -S "" -s base -b "$XREFDN" -H $URI1 1.1 >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing one-level searching at $XREFDN..."
+$LDAPRSEARCH -S "" -s one -b "$XREFDN" -H $URI1 1.1 >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing subtree searching at $XREFDN..."
+$LDAPRSEARCH -S "" -s sub -b "$XREFDN" -H $URI1 1.1 >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+XREFDN="o=abc,$REFDN"
+echo "Testing base searching at $XREFDN..."
+$LDAPRSEARCH -S "" -s base -b "$XREFDN" -H $URI1 1.1 >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != $RCODE ; then
+ echo "ldapsearch: unexpected result ($RC)! (referral expected)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing one-level searching at $XREFDN..."
+$LDAPRSEARCH -S "" -s one -b "$XREFDN" -H $URI1 1.1 >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != $RCODE ; then
+ echo "ldapsearch: unexpected result ($RC)! (referral expected)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing subtree searching at $XREFDN..."
+$LDAPRSEARCH -S "" -s sub -b "$XREFDN" -H $URI1 1.1 >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != $RCODE ; then
+ echo "ldapsearch: unexpected result ($RC)! (referral expected)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+XREFDN="uid=xxx,o=abc,$REFDN"
+echo "Testing base searching at $XREFDN..."
+$LDAPRSEARCH -S "" -s base -b "$XREFDN" -H $URI1 1.1 >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != $RCODE ; then
+ echo "ldapsearch: unexpected result ($RC)! (referral expected)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing one-level searching at $XREFDN..."
+$LDAPRSEARCH -S "" -s one -b "$XREFDN" -H $URI1 1.1 >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != $RCODE ; then
+ echo "ldapsearch: unexpected result ($RC)! (referral expected)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing subtree searching at $XREFDN..."
+$LDAPRSEARCH -S "" -s sub -b "$XREFDN" -H $URI1 1.1 >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != $RCODE ; then
+ echo "ldapsearch: unexpected result ($RC)! (referral expected)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$SEARCHOUTPROVIDER
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering expected LDIF for comparison..."
+$LDIFFILTER < $REFERRALOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test017-syncreplication-refresh b/tests/scripts/test017-syncreplication-refresh
new file mode 100755
index 0000000..7588203
--- /dev/null
+++ b/tests/scripts/test017-syncreplication-refresh
@@ -0,0 +1,356 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+#
+# Test replication:
+# - start provider
+# - start consumer
+# - populate over ldap
+# - perform some modifies and deleted
+# - attempt to modify the consumer (referral)
+# - retrieve database over ldap and compare against expected results
+#
+
+echo "Starting provider slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $SRPROVIDERCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Using ldapadd to create the context prefix entry in the provider..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDEREDCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting consumer slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $R1SRCONSUMERCONF > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '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 "Using ldapadd to populate the provider directory..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDEREDNOCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapmodify to modify provider directory..."
+
+#
+# Do some modifications
+#
+
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+changetype: modify
+add: drink
+drink: Orange Juice
+-
+delete: sn
+sn: Jones
+-
+add: sn
+sn: Jones
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: drink
+drink: Iced Tea
+drink: Mad Dog 20/20
+
+dn: cn=ITD Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: uniquemember
+uniquemember: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+uniquemember: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+-
+add: uniquemember
+uniquemember: cn=Dorothy Stevens, ou=Alumni Association, ou=People, dc=example,dc=com
+uniquemember: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: description
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+cn: Gern Jensen
+sn: Jensen
+uid: gjensen
+title: Chief Investigator, ITD
+postaladdress: ITD $ 535 W. William St $ Ann Arbor, MI 48103
+seealso: cn=All Staff, ou=Groups, dc=example,dc=com
+drink: Coffee
+homepostaladdress: 844 Brown St. Apt. 4 $ Ann Arbor, MI 48104
+description: Very odd
+facsimiletelephonenumber: +1 313 555 7557
+telephonenumber: +1 313 555 8343
+mail: gjensen@mailgw.example.com
+homephone: +1 313 555 8844
+
+dn: ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: organizationalUnit
+ou: Retired
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+cn: Rosco P. Coltrane
+sn: Coltrane
+uid: rosco
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Rosco P. Coltrane
+deleteoldrdn: 1
+newsuperior: ou=Retired, ou=People, dc=example,dc=com
+
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: delete
+
+dn: dc=testdomain1,dc=example,dc=com
+changetype: modrdn
+newrdn: dc=itsdomain1
+deleteoldrdn: 1
+
+dn: dc=itsdomain1,dc=example,dc=com
+changetype: modify
+replace: description
+description: Example, Inc. ITS test domain
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Performing modrdn alone on the provider..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: dc=testdomain2,dc=example,dc=com
+changetype: modrdn
+newrdn: dc=itsdomain2
+deleteoldrdn: 1
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Performing modify alone on the provider..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: dc=itsdomain2,dc=example,dc=com
+changetype: modify
+replace: description
+description: Example, Inc. itsdomain2 test domain
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Performing larger modify on the provider..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Alumni Assoc Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+replace: objectClass
+objectClass: groupOfNames
+-
+replace: cn
+cn: Alumni Assoc Staff
+-
+replace: description
+description: blablabla
+-
+replace: member
+member: cn=Manager,dc=example,dc=com
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Try updating the consumer slapd..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example, dc=com
+changetype: modify
+add: description
+description: This write must fail because directed to a shadow context,
+description: unless the chain overlay is configured appropriately ;)
+
+EOMODS
+
+RC=$?
+
+# expect 10 (LDAP_REFERRAL)...
+if test $RC != 10 ; then
+ echo "ldapmodify should have returned referral ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+OPATTRS="entryUUID creatorsName createTimestamp modifiersName modifyTimestamp"
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectclass=*)' '*' $OPATTRS > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ '(objectclass=*)' '*' $OPATTRS > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo "Filtering provider results..."
+$LDIFFILTER < $PROVIDEROUT > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER < $CONSUMEROUT > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test018-syncreplication-persist b/tests/scripts/test018-syncreplication-persist
new file mode 100755
index 0000000..0d4a0b8
--- /dev/null
+++ b/tests/scripts/test018-syncreplication-persist
@@ -0,0 +1,548 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+OPATTRS="entryUUID creatorsName createTimestamp modifiersName modifyTimestamp"
+
+if test $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR4
+
+#
+# Test replication:
+# - start provider
+# - start consumer
+# - populate over ldap
+# - perform some modifies and deleted
+# - attempt to modify the consumer (referral or chain)
+# - retrieve database over ldap and compare against expected results
+#
+
+echo "Starting provider slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $SRPROVIDERCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Using ldapadd to create the context prefix entry in the provider..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDEREDCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting consumer slapd on TCP/IP port $PORT4..."
+. $CONFFILTER $BACKEND < $P1SRCONSUMERCONF > $CONF4
+$SLAPD -f $CONF4 -h $URI4 -d $LVL > $LOG4 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI4 \
+ '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 "Using ldapadd to populate the provider directory..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDEREDNOCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectclass=*)' '*' $OPATTRS > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI4 \
+ '(objectclass=*)' '*' $OPATTRS > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering provider results..."
+$LDIFFILTER < $PROVIDEROUT > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER < $CONSUMEROUT > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Stopping the provider, sleeping 10 seconds and restarting it..."
+kill -HUP "$PID"
+wait $PID
+sleep 10
+echo "RESTART" >> $LOG1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL >> $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+echo "Waiting $SLEEP1 seconds for consumer to reconnect..."
+sleep $SLEEP1
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapmodify to modify provider directory..."
+
+#
+# Do some modifications
+#
+
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+changetype: modify
+add: drink
+drink: Orange Juice
+-
+delete: sn
+sn: Jones
+-
+add: sn
+sn: Jones
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: drink
+drink: Iced Tea
+
+dn: cn=ITD Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: uniquemember
+uniquemember: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+uniquemember: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+-
+add: uniquemember
+uniquemember: cn=Dorothy Stevens, ou=Alumni Association, ou=People, dc=example,dc=com
+uniquemember: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: description
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+cn: Gern Jensen
+sn: Jensen
+uid: gjensen
+title: Chief Investigator, ITD
+postaladdress: ITD $ 535 W. William St $ Ann Arbor, MI 48103
+seealso: cn=All Staff, ou=Groups, dc=example,dc=com
+drink: Coffee
+homepostaladdress: 844 Brown St. Apt. 4 $ Ann Arbor, MI 48104
+description: Very odd
+facsimiletelephonenumber: +1 313 555 7557
+facsimiletelephonenumber: +1 313 555 9998
+facsimiletelephonenumber: +1 313 555 9999
+telephonenumber: +1 313 555 8343
+mail: gjensen@mailgw.example.com
+homephone: +1 313 555 8844
+
+# modify attribute with no matching rule (ITS#6458)
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: facsimiletelephonenumber
+facsimiletelephonenumber: +1 313 555 9998
+facsimiletelephonenumber: +1 313 555 9999
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: facsimiletelephonenumber
+facsimiletelephonenumber: +1 313 555 9998
+facsimiletelephonenumber: +1 313 555 9999
+facsimiletelephonenumber: +1 313 555 7557
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: facsimiletelephonenumber
+facsimiletelephonenumber: +1 313 555 9998
+facsimiletelephonenumber: +1 313 555 9999
+
+dn: ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: organizationalUnit
+ou: Retired
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+cn: Rosco P. Coltrane
+sn: Coltrane
+uid: rosco
+description: Fat tycoon
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Rosco P. Coltrane
+deleteoldrdn: 1
+newsuperior: ou=Retired, ou=People, dc=example,dc=com
+
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: delete
+
+dn: dc=testdomain1,dc=example,dc=com
+changetype: modrdn
+newrdn: dc=itsdomain1
+deleteoldrdn: 1
+
+dn: dc=itsdomain1,dc=example,dc=com
+changetype: modify
+replace: description
+description: Example, Inc. ITS test domain
+
+dn: dc=testdomain2,dc=example,dc=com
+changetype: modrdn
+newrdn: dc=itsdomain2
+deleteoldrdn: 1
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldappasswd to change some passwords..."
+$LDAPPASSWD -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ 'cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com' \
+ > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectclass=*)' '*' $OPATTRS > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI4 \
+ '(objectclass=*)' '*' $OPATTRS > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering provider results..."
+$LDIFFILTER < $PROVIDEROUT > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER < $CONSUMEROUT > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Stopping consumer to test recovery..."
+kill -HUP $CONSUMERPID
+wait $CONSUMERPID
+
+echo "Modifying more entries on the provider..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Rosco P. Coltrane, ou=Retired, ou=People, dc=example,dc=com
+changetype: delete
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+add: drink
+drink: Mad Dog 20/20
+
+dn: cn=Rosco P. Coltrane, ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+sn: Coltrane
+uid: rosco
+cn: Rosco P. Coltrane
+
+dn: dc=itsdomain2,dc=example,dc=com
+changetype: modify
+replace: description
+description: Example, Inc. itsdomain2 test domain
+
+# rename with a newly added newSuperior while the consumer is down (ITS#6472)
+dn: ou=New Branch,dc=example,dc=com
+changetype: add
+objectClass: organizationalUnit
+ou: New Branch
+
+dn: cn=Dorothy Stevens, ou=Alumni Association, ou=People, dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Dorothy Stevens
+deleteoldrdn: 0
+newsuperior: ou=New Branch,dc=example,dc=com
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Restarting consumer..."
+echo "RESTART" >> $LOG4
+$SLAPD -f $CONF4 -h $URI4 -d $LVL >> $LOG4 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$PID $CONSUMERPID"
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectclass=*)' '*' $OPATTRS > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI4 \
+ '(objectclass=*)' '*' $OPATTRS > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering provider results..."
+$LDIFFILTER < $PROVIDEROUT > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER < $CONSUMEROUT > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+if test ! $BACKLDAP = "ldapno" ; then
+ echo "Try updating the consumer slapd..."
+ $LDAPMODIFY -v -D "$MANAGERDN" -H $URI4 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example, dc=com
+changetype: modify
+add: description
+description: This write must fail because directed to a shadow context,
+description: unless the chain overlay is configured appropriately ;)
+
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ # ITS#4964
+ echo "Trying to change some passwords on the consumer..."
+ $LDAPPASSWD -D "$MANAGERDN" -H $URI4 -w $PASSWD \
+ 'cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com' \
+ > $TESTOUT 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+fi
+
+# Testing a cancel exop (should go in its own testcase)
+$LDAPSEARCH -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ -e '!cancel' \
+ '(objectclass=*)' '*' $OPATTRS > $TESTOUT 2>&1
+RC=$?
+# cancelled operation returns -1, so no point of checking return code, either
+# it's cancelled or we get stuck forever
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectclass=*)' '*' $OPATTRS > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI4 \
+ '(objectclass=*)' '*' $OPATTRS > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering provider results..."
+$LDIFFILTER < $PROVIDEROUT > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER < $CONSUMEROUT > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test019-syncreplication-cascade b/tests/scripts/test019-syncreplication-cascade
new file mode 100755
index 0000000..1501823
--- /dev/null
+++ b/tests/scripts/test019-syncreplication-cascade
@@ -0,0 +1,487 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2 $DBDIR3 $DBDIR4 $DBDIR5 $DBDIR6
+
+#
+# Test replication:
+# - start provider
+# - start consumer
+# - populate over ldap
+# - perform some modifies and deleted
+# - retrieve database over ldap and compare against expected results
+#
+
+echo "Starting provider slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $SRPROVIDERCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd (pid=$PID) is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Using ldapadd to create the context prefix entry in the provider..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDEREDCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting R1 consumer slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $R1SRCONSUMERCONF > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMER R1 PID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that R1 consumer slapd (pid=$CONSUMERPID) is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for R1 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 "Starting R2 consumer slapd on TCP/IP port $PORT3..."
+. $CONFFILTER $BACKEND < $R2SRCONSUMERCONF > $CONF3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMER R2 PID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that R2 consumer slapd (pid=$CONSUMERPID) is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI3 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for R2 consumer 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 "Starting P1 consumer slapd on TCP/IP port $PORT4..."
+. $CONFFILTER $BACKEND < $P1SRCONSUMERCONF > $CONF4
+$SLAPD -f $CONF4 -h $URI4 -d $LVL > $LOG4 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMER P1 PID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that P1 consumer slapd (pid=$CONSUMERPID) is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI4 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for P1 consumer 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 "Starting P2 consumer slapd on TCP/IP port $PORT5..."
+. $CONFFILTER $BACKEND < $P2SRCONSUMERCONF > $CONF5
+$SLAPD -f $CONF5 -h $URI5 -d $LVL > $LOG5 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMER P2 PID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that P2 consumer slapd (pid=$CONSUMERPID) is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI5 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for P2 consumer 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 "Starting P3 consumer slapd on TCP/IP port $PORT6..."
+. $CONFFILTER $BACKEND < $P3SRCONSUMERCONF > $CONF6
+$SLAPD -f $CONF6 -h $URI6 -d $LVL > $LOG6 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMER P3 PID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that P3 consumer slapd (pid=$CONSUMERPID) is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI6 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for P3 consumer 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 "Using ldapadd to populate the provider directory..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDEREDNOCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP2 seconds for syncrepl to receive changes..."
+sleep $SLEEP2
+
+echo "Using ldapmodify to modify provider directory..."
+
+#
+# Do some modifications
+#
+
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+changetype: modify
+add: drink
+drink: Orange Juice
+-
+delete: sn
+sn: Jones
+-
+add: sn
+sn: Jones
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: drink
+drink: Iced Tea
+drink: Mad Dog 20/20
+
+dn: cn=ITD Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: uniquemember
+uniquemember: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+uniquemember: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+-
+add: uniquemember
+uniquemember: cn=Dorothy Stevens, ou=Alumni Association, ou=People, dc=example,dc=com
+uniquemember: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: description
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+cn: Gern Jensen
+sn: Jensen
+uid: gjensen
+title: Chief Investigator, ITD
+postaladdress: ITD $ 535 W. William St $ Ann Arbor, MI 48103
+seealso: cn=All Staff, ou=Groups, dc=example,dc=com
+drink: Coffee
+homepostaladdress: 844 Brown St. Apt. 4 $ Ann Arbor, MI 48104
+description: Very odd
+facsimiletelephonenumber: +1 313 555 7557
+telephonenumber: +1 313 555 8343
+mail: gjensen@mailgw.example.com
+homephone: +1 313 555 8844
+
+dn: ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: organizationalUnit
+ou: Retired
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+cn: Rosco P. Coltrane
+sn: Coltrane
+uid: rosco
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Rosco P. Coltrane
+deleteoldrdn: 1
+newsuperior: ou=Retired, ou=People, dc=example,dc=com
+
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: delete
+
+dn: dc=testdomain1,dc=example,dc=com
+changetype: modrdn
+newrdn: dc=itsdomain1
+deleteoldrdn: 1
+
+dn: dc=itsdomain1,dc=example,dc=com
+changetype: modify
+replace: description
+description: Example, Inc. ITS test domain
+
+dn: dc=testdomain2,dc=example,dc=com
+changetype: modrdn
+newrdn: dc=itsdomain2
+deleteoldrdn: 1
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP2 seconds for syncrepl to receive changes..."
+sleep $SLEEP2
+
+echo "Performing modify alone on provider..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: dc=itsdomain2,dc=example,dc=com
+changetype: modify
+replace: description
+description: Example, Inc. itsdomain2 test domain
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP2 seconds for syncrepl to receive changes..."
+sleep $SLEEP2
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' '*' entryCSN > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the R1 consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ '(objectClass=*)' '*' entryCSN > $SERVER2OUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at R1 consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the R2 consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI3 \
+ '(objectClass=*)' '*' entryCSN > $SERVER3OUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at R2 consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the P1 consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI4 \
+ '(objectClass=*)' '*' entryCSN > $SERVER4OUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at P1 consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the P2 consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI5 \
+ '(objectClass=*)' '*' entryCSN > $SERVER5OUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at P2 consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the P3 consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI6 \
+ '(objectClass=*)' '*' entryCSN > $SERVER6OUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at P3 consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo "Filtering provider ldapsearch results..."
+$LDIFFILTER < $PROVIDEROUT > $PROVIDERFLT
+echo "Filtering R1 consumer ldapsearch results..."
+$LDIFFILTER < $SERVER2OUT > $SERVER2FLT
+echo "Filtering R2 consumer ldapsearch results..."
+$LDIFFILTER < $SERVER3OUT > $SERVER3FLT
+echo "Filtering P1 consumer ldapsearch results..."
+$LDIFFILTER < $SERVER4OUT > $SERVER4FLT
+echo "Filtering P2 consumer ldapsearch results..."
+$LDIFFILTER < $SERVER5OUT > $SERVER5FLT
+echo "Filtering P3 consumer ldapsearch results..."
+$LDIFFILTER < $SERVER6OUT > $SERVER6FLT
+
+echo "Comparing retrieved entries from provider and R1 consumer..."
+$CMP $PROVIDERFLT $SERVER2FLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and R1 consumer databases differ"
+ exit 1
+fi
+
+echo "Comparing retrieved entries from provider and R2 consumer..."
+$CMP $PROVIDERFLT $SERVER3FLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and R2 consumer databases differ"
+ exit 1
+fi
+
+echo "Comparing retrieved entries from provider and P1 consumer..."
+$CMP $PROVIDERFLT $SERVER4FLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and P1 consumer databases differ"
+ exit 1
+fi
+
+echo "Comparing retrieved entries from provider and P2 consumer..."
+$CMP $PROVIDERFLT $SERVER5FLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and P2 consumer databases differ"
+ exit 1
+fi
+
+echo "Comparing retrieved entries from provider and P3 consumer..."
+$CMP $PROVIDERFLT $SERVER6FLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and P3 consumer databases differ"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test020-proxycache b/tests/scripts/test020-proxycache
new file mode 100755
index 0000000..af4cc9e
--- /dev/null
+++ b/tests/scripts/test020-proxycache
@@ -0,0 +1,643 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+PCACHETTL=${PCACHETTL-"1m"}
+PCACHENTTL=${PCACHENTTL-"1m"}
+PCACHESTTL=${PCACHESTTL-"1m"}
+PCACHE_ENTRY_LIMIT=${PCACHE_ENTRY_LIMIT-"6"}
+PCACHE_CCPERIOD=${PCACHE_CCPERIOD-"2"}
+PCACHETTR=${PCACHETTR-"2"}
+PCACHEBTTR=${PCACHEBTTR-"5"}
+
+. $SRCDIR/scripts/defines.sh
+
+if test $PROXYCACHE = pcacheno; then
+ echo "Proxy cache overlay not available, test skipped"
+ exit 0
+fi
+
+if test $BACKLDAP = "ldapno" ; then
+ echo "LDAP backend not available, test skipped"
+ exit 0
+fi
+
+if test $BACKEND = ldif ; then
+ # The (mail=example.com*) queries hit a sizelimit, so which
+ # entry is returned depends on the ordering in the backend.
+ echo "Test does not support $BACKEND backend, test skipped"
+ exit 0
+fi
+
+if test $BACKEND = wt ; then
+ echo "Test does not support $BACKEND backend, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+# Test proxy caching:
+# - start provider
+# - start proxy cache
+# - populate provider
+# - perform first set of searches at the proxy
+# - verify cacheability
+# - perform second set of searches at the proxy
+# - verify answerability
+
+echo "Starting provider slapd on TCP/IP port $PORT1..."
+. $CONFFILTER < $CACHEPROVIDERCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Using ldapadd to populate the provider directory..."
+$LDAPADD -x -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDERED > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting proxy cache on TCP/IP port $PORT2..."
+. $CONFFILTER < $PROXYCACHECONF | sed \
+ -e "s/@TTL@/${PCACHETTL}/" \
+ -e "s/@NTTL@/${PCACHENTTL}/" \
+ -e "s/@STTL@/${PCACHENTTL}/" \
+ -e "s/@TTR@/${PCACHETTR}/" \
+ -e "s/@ENTRY_LIMIT@/${PCACHE_ENTRY_LIMIT}/" \
+ -e "s/@CCPERIOD@/${PCACHE_CCPERIOD}/" \
+ -e "s/@BTTR@/${PCACHEBTTR}/" \
+ > $CONF2
+
+$SLAPD -f $CONF2 -h $URI2 -d $LVL -d pcache > $LOG2 2>&1 &
+CACHEPID=$!
+if test $WAIT != 0 ; then
+ echo CACHEPID $CACHEPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CACHEPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that proxy slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '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
+
+cat /dev/null > $SEARCHOUT
+
+echo "Making queries on the proxy cache..."
+CNT=0
+
+CNT=`expr $CNT + 1`
+FILTER="(sn=Jon)"
+echo "Query $CNT: filter:$FILTER attrs:all (expect nothing)"
+echo "# Query $CNT: filter:$FILTER attrs:all (expect nothing)" >> $SEARCHOUT
+$LDAPSEARCH -x -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# ITS#4491, if debug messages are unavailable, we can't verify the tests.
+grep "query template" $LOG2 > /dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "Debug messages unavailable, remaining test skipped..."
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+ exit 0
+fi
+
+CNT=`expr $CNT + 1`
+FILTER="(|(cn=*Jon*)(sn=Jon*))"
+ATTRS="cn sn title uid"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -x -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+CNT=`expr $CNT + 1`
+FILTER="(sn=Smith*)"
+ATTRS="cn sn uid"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+CNT=`expr $CNT + 1`
+FILTER="(sn=Doe*)"
+ATTRS="cn sn title uid"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+CNT=`expr $CNT + 1`
+FILTER="(uid=johnd)"
+ATTRS="mail postaladdress telephonenumber cn uid"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+CNT=`expr $CNT + 1`
+FILTER="(mail=*@mail.alumni.example.com)"
+ATTRS="cn sn title uid"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+CNT=`expr $CNT + 1`
+FILTER="(mail=*)"
+ATTRS="cn sn title uid"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+CNT=`expr $CNT + 1`
+FILTER="(mail=*example.com)"
+ATTRS="cn sn title uid"
+USERDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+UPASSWD="bjorn"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ -D "$USERDN" -w "$UPASSWD" \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+case $RC in
+0)
+ echo "ldapsearch should have failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+4)
+ echo "ldapsearch failed ($RC)"
+ ;;
+*)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+CNT=`expr $CNT + 1`
+FILTER="(uid=b*)"
+ATTRS="mail"
+USERDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+UPASSWD="bjorn"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ -D "$USERDN" -w "$UPASSWD" \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+case $RC in
+0)
+ echo "ldapsearch should have failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+4)
+ echo "ldapsearch failed ($RC)"
+ ;;
+*)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+CNT=`expr $CNT + 1`
+FILTER="(|(cn=All Staff)(sn=All Staff))"
+ATTRS="sn cn title uid undefinedAttr"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FIRST=$CNT
+
+# queries 2-6,8-10 are cacheable
+CACHEABILITY=0111110111
+grep CACHEABLE $LOG2 | awk '
+ /NOT CACHEABLE/{printf "Query %d not cacheable\n",NR}
+ /QUERY CACHEABLE/{printf "Query %d cacheable\n",NR}'
+CACHED=`grep CACHEABLE $LOG2 | awk '
+ /NOT CACHEABLE/{printf "0"}
+ /QUERY CACHEABLE/{printf "1"}'`
+
+if test "$CACHEABILITY" = "$CACHED" ; then
+ echo "Successfully verified cacheability"
+else
+ echo "Error in verifying cacheability"
+ echo "$CACHED"
+ echo "$CACHEABILITY"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+CNT=`expr $CNT + 1`
+FILTER="(|(cn=*Jones)(sn=Jones))"
+ATTRS="cn sn title uid"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -x -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+CNT=`expr $CNT + 1`
+FILTER="(sn=Smith)"
+ATTRS="cn sn title uid"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+CNT=`expr $CNT + 1`
+FILTER="(uid=bjorn)"
+ATTRS="mail postaladdress telephonenumber cn uid"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+CNT=`expr $CNT + 1`
+FILTER="(mail=jaj@mail.alumni.example.com)"
+ATTRS="cn sn title uid"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+CNT=`expr $CNT + 1`
+FILTER="(mail=*example.com)"
+ATTRS="cn sn title uid"
+USERDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+UPASSWD="bjorn"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ -D "$USERDN" -w "$UPASSWD" \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+case $RC in
+0)
+ echo "ldapsearch should have failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+4)
+ echo "ldapsearch failed ($RC)"
+ ;;
+*)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+CNT=`expr $CNT + 1`
+FILTER="(uid=b*)"
+ATTRS="mail"
+USERDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+UPASSWD="bjorn"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ -D "$USERDN" -w "$UPASSWD" \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+case $RC in
+0)
+ echo "ldapsearch should have failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+4)
+ echo "ldapsearch failed ($RC)"
+ ;;
+*)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+CNT=`expr $CNT + 1`
+FILTER="(|(cn=All Staff)(sn=All Staff))"
+ATTRS="sn cn title uid undefinedAttr"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#queries 11-13,16-17 are answerable, 14-15 are not
+#actually, 14 would be answerable, but since 8 made mail=*example.com
+#not answerable because of sizelimit, queries contained in it are no longer
+#answerable as well
+ANSWERABILITY=1110011
+grep ANSWERABLE $LOG2 | awk "BEGIN {FIRST=$FIRST}"'
+ /NOT ANSWERABLE/{if (NR > FIRST) printf "Query %d not answerable\n",NR}
+ /QUERY ANSWERABLE/{if (NR > FIRST) printf "Query %d answerable\n",NR}'
+ANSWERED=`grep ANSWERABLE $LOG2 | awk "BEGIN {FIRST=$FIRST}"'
+ /NOT ANSWERABLE/{if (NR > FIRST) printf "0"}
+ /QUERY ANSWERABLE/{if (NR > FIRST) printf "1"}'`
+
+if test "$ANSWERABILITY" = "$ANSWERED" ; then
+ echo "Successfully verified answerability"
+else
+ echo "Error in verifying answerability"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER -s ldif=a < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif..."
+$LDIFFILTER -s ldif=a < $PROXYCACHEOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo ""
+echo "Testing cache refresh"
+
+CNT=`expr $CNT + 1`
+FILTER="(&(objectclass=person)(uid=dots))"
+ATTRS="cn mail telephonenumber"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS"
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -x -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -x -D "$MANAGERDN" -H $URI1 -w $PASSWD <<EOF \
+ > /dev/null 2>&1
+dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com
+changetype: modify
+replace: mail
+mail: dots@admin.example2.com
+-
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+SLEEP=`expr $PCACHETTR + $PCACHE_CCPERIOD + 1`
+echo "Waiting $SLEEP seconds for cache to refresh"
+
+sleep $SLEEP
+
+echo "Checking entry again"
+$LDAPSEARCH -x -S "" -b "$BASEDN" -H $URI2 \
+ "$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+grep "^mail: dots@admin" $SEARCHOUT > /dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "Refresh failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+ exit 1
+fi
+
+echo ""
+echo "Testing Bind caching"
+
+CNT=`expr $CNT + 1`
+USERDN="cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com"
+UPASSWD="jaj"
+echo "Query $CNT: $USERDN"
+echo "# Query $CNT: $USERDN" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "" -s base -H $URI2 \
+ -D "$USERDN" -w "$UPASSWD" >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+grep "CACHING BIND" $LOG2 > /dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "Refresh failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+ exit 1
+fi
+
+CNT=`expr $CNT + 1`
+USERDN="cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com"
+UPASSWD="jaj"
+echo "Query $CNT: (Bind should be cached)"
+echo "# Query $CNT: (Bind should be cached)" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "" -s base -H $URI2 \
+ -D "$USERDN" -w "$UPASSWD" >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+grep "CACHED BIND" $LOG2 > /dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "Refresh failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+ exit 1
+fi
+
+echo ""
+echo "Testing pwdModify"
+$LDAPPASSWD -H $URI2 \
+ -D "$MANAGERDN" -w "$PASSWD" -s newpw "$USERDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+RC=`grep "CACH.* BIND" $LOG2 | wc -l`
+if test $RC != 3 ; then
+ echo "ldappasswd didn't update the cache"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+ exit 1
+fi
+
+CNT=`expr $CNT + 1`
+USERDN="cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com"
+UPASSWD=newpw
+echo "Query $CNT: (Bind should be cached)"
+echo "# Query $CNT: (Bind should be cached)" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "" -s base -H $URI2 \
+ -D "$USERDN" -w "$UPASSWD" >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+RC=`grep "CACH.* BIND" $LOG2 | wc -l`
+if test $RC != 4 ; then
+ echo "Bind wasn't answered from cache"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+ exit 1
+fi
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test021-certificate b/tests/scripts/test021-certificate
new file mode 100755
index 0000000..9be5c6a
--- /dev/null
+++ b/tests/scripts/test021-certificate
@@ -0,0 +1,325 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+#echo $SLAPADD -f $CONF1 -l $LDIFORDERED
+$SLAPADD -f $CONF1 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+#valgrind -v --gdb-attach=yes --logfile=info --num-callers=16 --leak-check=yes --leak-resolution=high $SLAPD -f $CONF1 -h $URI1 -d $LVL </dev/tty > $LOG1 2>&1 &
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+echo "Testing certificate handling..."
+
+sleep 1
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Add certificates..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+version: 1
+
+# LEADING COMMENT AND WHITE SPACE
+
+# should use certificationAuthority instead of extensibleObject
+dn: dc=example,dc=com
+changetype: modify
+add: objectClass
+objectClass: extensibleObject
+-
+add: cAcertificate;binary
+cAcertificate;binary::
+ MIIDVDCCAr2gAwIBAgIBADANBgkqhkiG9w0BAQQFADB3MQswCQYDVQQGEwJVUzET
+ MBEGA1UECBMKQ2FsaWZvcm5pYTEfMB0GA1UEChMWT3BlbkxEQVAgRXhhbXBsZSwg
+ THRkLjETMBEGA1UEAxMKRXhhbXBsZSBDQTEdMBsGCSqGSIb3DQEJARYOY2FAZXhh
+ bXBsZS5jb20wHhcNMDMxMDE3MTYzMDQxWhcNMDQxMDE2MTYzMDQxWjB3MQswCQYD
+ VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEfMB0GA1UEChMWT3BlbkxEQVAg
+ RXhhbXBsZSwgTHRkLjETMBEGA1UEAxMKRXhhbXBsZSBDQTEdMBsGCSqGSIb3DQEJ
+ ARYOY2FAZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANlj
+ UGxiisAzEiALukzt3Gj/24MRw1J0AZx6GncXLhpNJsAFyA0bYZdAzgvydKeq/uX0
+ i5o/4Byc3G71XAAcbJZxDPtrLwpDAdMNOBvKV2r67yTgnpatFLfGRt/FWazj5EbF
+ YkorWWTe+4eEBd9VPzebHdIm+DPHipUfIAzRoNejAgMBAAGjge8wgewwHQYDVR0O
+ BBYEFEtvIRo2JNKQ+UOwU0ctfeHA5pgjMIGhBgNVHSMEgZkwgZaAFEtvIRo2JNKQ
+ +UOwU0ctfeHA5pgjoXukeTB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv
+ cm5pYTEfMB0GA1UEChMWT3BlbkxEQVAgRXhhbXBsZSwgTHRkLjETMBEGA1UEAxMK
+ RXhhbXBsZSBDQTEdMBsGCSqGSIb3DQEJARYOY2FAZXhhbXBsZS5jb22CAQAwDAYD
+ VR0TBAUwAwEB/zAZBgNVHREEEjAQgQ5jYUBleGFtcGxlLmNvbTANBgkqhkiG9w0B
+ AQQFAAOBgQCgXD/+28El3GXi/uxMNEKqtnIhQdTnNU4il0fZ6pcmHPFC+61Bddow
+ 90ZZZh5Gbg5ZBxFRhDXN8K/fix3ewRSjASt40dGlEODkE+FsLMt04sYl6kX7RGKg
+ 9a46DkeG+uzZnN/3252uCgh+rjNMFAglueUTERv3EtUB1iXEoU3GyA==
+
+dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com
+changetype: modify
+add: objectClass
+objectClass: strongAuthenticationUser
+-
+add: userCertificate;binary
+userCertificate;binary::
+ MIIDazCCAtSgAwIBAgIBAjANBgkqhkiG9w0BAQQFADB3MQswCQYDVQQGEwJVUzET
+ MBEGA1UECBMKQ2FsaWZvcm5pYTEfMB0GA1UEChMWT3BlbkxEQVAgRXhhbXBsZSwg
+ THRkLjETMBEGA1UEAxMKRXhhbXBsZSBDQTEdMBsGCSqGSIb3DQEJARYOY2FAZXhh
+ bXBsZS5jb20wHhcNMDMxMDE3MTYzMzE5WhcNMDQxMDE2MTYzMzE5WjB+MQswCQYD
+ VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEfMB0GA1UEChMWT3BlbkxEQVAg
+ RXhhbXBsZSwgTHRkLjEYMBYGA1UEAxMPVXJzdWxhIEhhbXBzdGVyMR8wHQYJKoZI
+ hvcNAQkBFhB1aGFtQGV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
+ iQKBgQDuxgp5ELV9LmhxWMpV7qc4028QQT3+zzFDXhruuXE7ji2n3S3ea8bOwDtJ
+ h+qnsDe561DhHHHlgIjMKCiDEizYMpxvJPYEXmvp0huRkMgpKZgmel95BSkt6TYm
+ J0erS3aoimOHLEFimmnTLolNRMiWqNBvqwobx940PGwUWEePKQIDAQABo4H/MIH8
+ MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENl
+ cnRpZmljYXRlMB0GA1UdDgQWBBSjI94TbBmuDEeUUOiC37EK0Uf0XjCBoQYDVR0j
+ BIGZMIGWgBRLbyEaNiTSkPlDsFNHLX3hwOaYI6F7pHkwdzELMAkGA1UEBhMCVVMx
+ EzARBgNVBAgTCkNhbGlmb3JuaWExHzAdBgNVBAoTFk9wZW5MREFQIEV4YW1wbGUs
+ IEx0ZC4xEzARBgNVBAMTCkV4YW1wbGUgQ0ExHTAbBgkqhkiG9w0BCQEWDmNhQGV4
+ YW1wbGUuY29tggEAMA0GCSqGSIb3DQEBBAUAA4GBAIgUcARb3OlWYNbmr1nmqESu
+ xLn16uqI1Ot6WkcICvpkdQ+Bo+R9AP05xpoXocZtKdNvBu3FNxB/jFkiOcLU2lX7
+ Px1Ijnsjh60qVRy9HOsHCungIKlGcnXLKHmKu0y//5jds/HnaJsGcHI5JRG7CBJb
+ W+wrwge3trJ1xHJI8prN
+
+dn: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+changetype: modify
+add: objectClass
+objectClass: strongAuthenticationUser
+-
+add: userCertificate;binary
+userCertificate;binary::
+ MIIDcDCCAtmgAwIBAgIBATANBgkqhkiG9w0BAQQFADB3MQswCQYDVQQGEwJVUzET
+ MBEGA1UECBMKQ2FsaWZvcm5pYTEfMB0GA1UEChMWT3BlbkxEQVAgRXhhbXBsZSwg
+ THRkLjETMBEGA1UEAxMKRXhhbXBsZSBDQTEdMBsGCSqGSIb3DQEJARYOY2FAZXhh
+ bXBsZS5jb20wHhcNMDMxMDE3MTYzMTQwWhcNMDQxMDE2MTYzMTQwWjCBgjELMAkG
+ A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExHzAdBgNVBAoTFk9wZW5MREFQ
+ IEV4YW1wbGUsIEx0ZC4xHTAbBgNVBAMUFEplbm5pZmVyICJKZW4iIFNtaXRoMR4w
+ HAYJKoZIhvcNAQkBFg9qZW5AZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
+ gY0AMIGJAoGBANUgO8cP/SjqgCVxxsRYv36AP0+QL81iEkGvR4gG6jbtDDBdVYDC
+ YbS2oKKNJ5e99NxGMIjOYfmKcAwmkV46IhdzUtkutgjHEG9vl5ajSwc1KSsbTMTy
+ NtuG3k5k02JYFbP+FrGyUE8iPqK4+i7mVjW4bh/MBCHW88FptnpDJiuHAgMBAAGj
+ gf8wgfwwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0
+ ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFEdo4jpxCQXJ1sh/E1O3ZBkLTbHkMIGh
+ BgNVHSMEgZkwgZaAFEtvIRo2JNKQ+UOwU0ctfeHA5pgjoXukeTB3MQswCQYDVQQG
+ EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEfMB0GA1UEChMWT3BlbkxEQVAgRXhh
+ bXBsZSwgTHRkLjETMBEGA1UEAxMKRXhhbXBsZSBDQTEdMBsGCSqGSIb3DQEJARYO
+ Y2FAZXhhbXBsZS5jb22CAQAwDQYJKoZIhvcNAQEEBQADgYEAFpHsQUtSZQzmm9k2
+ Vrfs0h7tdkWF3LcHzHk4a/t3k4EXcqlHBxh4f0tmb4XNP9QupRgm6ggr8t3Rq0Vt
+ T8k50x4C7oE8HwZuEEB4FM7S1Zig3dfeJ8MJgdaLqt5/U9Ip/hZdzG2dsUsIceH/
+ 5MCKLu9bGJUjsKnGdm/KpaNwaNo=
+
+dn: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+changetype: modify
+add: userCertificate;binary
+userCertificate;binary::
+ MIIDjDCCAvWgAwIBAgIBAzANBgkqhkiG9w0BAQQFADB3MQswCQYDVQQGEwJVUzET
+ MBEGA1UECBMKQ2FsaWZvcm5pYTEfMB0GA1UEChMWT3BlbkxEQVAgRXhhbXBsZSwg
+ THRkLjETMBEGA1UEAxMKRXhhbXBsZSBDQTEdMBsGCSqGSIb3DQEJARYOY2FAZXhh
+ bXBsZS5jb20wHhcNMDMxMDE3MTYzNTM1WhcNMDQxMDE2MTYzNTM1WjCBnjELMAkG
+ A1UEBhMCVVMxETAPBgNVBAgTCE1pY2hpZ2FuMR8wHQYDVQQKExZPcGVuTERBUCBF
+ eGFtcGxlLCBMdGQuMRswGQYDVQQLExJBbHVtbmkgQXNzb2ljYXRpb24xEjAQBgNV
+ BAMTCUplbiBTbWl0aDEqMCgGCSqGSIb3DQEJARYbamVuQG1haWwuYWx1bW5pLmV4
+ YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpnXWAL0VkROGO
+ 1Rg8J3u6F4F7yMqQCbUMsV9rxQisYj45+pmqiHV5urogvT4MGD6eLNFZKBn+0KRn
+ i++uu7gbartzpmBaHOlzRII9ZdVMFfrT2xYNgAlkne6pb6IZIN9UONuH/httENCD
+ J5WEpjZ48D1Lrml/HYO/W+SAMkpEqQIDAQABo4H/MIH8MAkGA1UdEwQCMAAwLAYJ
+ YIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1Ud
+ DgQWBBTB2saht/od/nis76b9m+pjxfhSPjCBoQYDVR0jBIGZMIGWgBRLbyEaNiTS
+ kPlDsFNHLX3hwOaYI6F7pHkwdzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlm
+ b3JuaWExHzAdBgNVBAoTFk9wZW5MREFQIEV4YW1wbGUsIEx0ZC4xEzARBgNVBAMT
+ CkV4YW1wbGUgQ0ExHTAbBgkqhkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tggEAMA0G
+ CSqGSIb3DQEBBAUAA4GBAIoGPc/AS0cNkMRDNoMIzcFdF9lONMduKBiSuFvv+x8n
+ Cek+LUdXxF59V2NPKh2V5gFh5xbAchyv6FVBnpVtPdB5akCr5tdFQhuBLUXXDk/t
+ THGpIWt7OAjEmpuMzsz3GUB8Zf9rioHOs1DMw+GpzWdnFITxXhAqEDc3quqPrpxZ
+-
+delete: userCertificate;binary
+userCertificate;binary::
+ MIIDcDCCAtmgAwIBAgIBATANBgkqhkiG9w0BAQQFADB3MQswCQYDVQQGEwJVUzET
+ MBEGA1UECBMKQ2FsaWZvcm5pYTEfMB0GA1UEChMWT3BlbkxEQVAgRXhhbXBsZSwg
+ THRkLjETMBEGA1UEAxMKRXhhbXBsZSBDQTEdMBsGCSqGSIb3DQEJARYOY2FAZXhh
+ bXBsZS5jb20wHhcNMDMxMDE3MTYzMTQwWhcNMDQxMDE2MTYzMTQwWjCBgjELMAkG
+ A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExHzAdBgNVBAoTFk9wZW5MREFQ
+ IEV4YW1wbGUsIEx0ZC4xHTAbBgNVBAMUFEplbm5pZmVyICJKZW4iIFNtaXRoMR4w
+ HAYJKoZIhvcNAQkBFg9qZW5AZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
+ gY0AMIGJAoGBANUgO8cP/SjqgCVxxsRYv36AP0+QL81iEkGvR4gG6jbtDDBdVYDC
+ YbS2oKKNJ5e99NxGMIjOYfmKcAwmkV46IhdzUtkutgjHEG9vl5ajSwc1KSsbTMTy
+ NtuG3k5k02JYFbP+FrGyUE8iPqK4+i7mVjW4bh/MBCHW88FptnpDJiuHAgMBAAGj
+ gf8wgfwwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0
+ ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFEdo4jpxCQXJ1sh/E1O3ZBkLTbHkMIGh
+ BgNVHSMEgZkwgZaAFEtvIRo2JNKQ+UOwU0ctfeHA5pgjoXukeTB3MQswCQYDVQQG
+ EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEfMB0GA1UEChMWT3BlbkxEQVAgRXhh
+ bXBsZSwgTHRkLjETMBEGA1UEAxMKRXhhbXBsZSBDQTEdMBsGCSqGSIb3DQEJARYO
+ Y2FAZXhhbXBsZS5jb22CAQAwDQYJKoZIhvcNAQEEBQADgYEAFpHsQUtSZQzmm9k2
+ Vrfs0h7tdkWF3LcHzHk4a/t3k4EXcqlHBxh4f0tmb4XNP9QupRgm6ggr8t3Rq0Vt
+ T8k50x4C7oE8HwZuEEB4FM7S1Zig3dfeJ8MJgdaLqt5/U9Ip/hZdzG2dsUsIceH/
+ 5MCKLu9bGJUjsKnGdm/KpaNwaNo=
+
+dn: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com
+changetype: modify
+replace: userCertificate;binary
+userCertificate;binary::
+ MIIDjDCCAvWgAwIBAgIBAzANBgkqhkiG9w0BAQQFADB3MQswCQYDVQQGEwJVUzET
+ MBEGA1UECBMKQ2FsaWZvcm5pYTEfMB0GA1UEChMWT3BlbkxEQVAgRXhhbXBsZSwg
+ THRkLjETMBEGA1UEAxMKRXhhbXBsZSBDQTEdMBsGCSqGSIb3DQEJARYOY2FAZXhh
+ bXBsZS5jb20wHhcNMDMxMDE3MTYzNTM1WhcNMDQxMDE2MTYzNTM1WjCBnjELMAkG
+ A1UEBhMCVVMxETAPBgNVBAgTCE1pY2hpZ2FuMR8wHQYDVQQKExZPcGVuTERBUCBF
+ eGFtcGxlLCBMdGQuMRswGQYDVQQLExJBbHVtbmkgQXNzb2ljYXRpb24xEjAQBgNV
+ BAMTCUplbiBTbWl0aDEqMCgGCSqGSIb3DQEJARYbamVuQG1haWwuYWx1bW5pLmV4
+ YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpnXWAL0VkROGO
+ 1Rg8J3u6F4F7yMqQCbUMsV9rxQisYj45+pmqiHV5urogvT4MGD6eLNFZKBn+0KRn
+ i++uu7gbartzpmBaHOlzRII9ZdVMFfrT2xYNgAlkne6pb6IZIN9UONuH/httENCD
+ J5WEpjZ48D1Lrml/HYO/W+SAMkpEqQIDAQABo4H/MIH8MAkGA1UdEwQCMAAwLAYJ
+ YIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1Ud
+ DgQWBBTB2saht/od/nis76b9m+pjxfhSPjCBoQYDVR0jBIGZMIGWgBRLbyEaNiTS
+ kPlDsFNHLX3hwOaYI6F7pHkwdzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlm
+ b3JuaWExHzAdBgNVBAoTFk9wZW5MREFQIEV4YW1wbGUsIEx0ZC4xEzARBgNVBAMT
+ CkV4YW1wbGUgQ0ExHTAbBgkqhkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tggEAMA0G
+ CSqGSIb3DQEBBAUAA4GBAIoGPc/AS0cNkMRDNoMIzcFdF9lONMduKBiSuFvv+x8n
+ Cek+LUdXxF59V2NPKh2V5gFh5xbAchyv6FVBnpVtPdB5akCr5tdFQhuBLUXXDk/t
+ THGpIWt7OAjEmpuMzsz3GUB8Zf9rioHOs1DMw+GpzWdnFITxXhAqEDc3quqPrpxZ
+-
+delete: userCertificate;binary
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo 'Using ldapsearch to retrieve (userCertificate;binary=*) ...'
+echo "# (userCertificate;binary=*)" > $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(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 'Using ldapsearch to retrieve (cAcertificate=*) ...'
+echo "# (cAcertificate=*)" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(cAcertificate=*)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+SNAI='2$EMAIL=ca@example.com,CN=Example CA,O=Openldap Example\5C, Ltd.,ST=California,C=US'
+
+echo 'Using ldapsearch to retrieve (userCertificate=serialNumberAndIssuer) [old format] ...'
+echo "# (userCertificate=$SNAI)" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "(userCertificate=$SNAI)" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+SNAI='{ serialNumber 2, issuer "EMAIL=ca@example.com,CN=Example CA,O=Openldap Example\5C, Ltd.,ST=California,C=US" }'
+
+echo 'Using ldapsearch to retrieve (userCertificate=serialNumberAndIssuer) [new format] ...'
+echo "# (userCertificate=$SNAI)" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "(userCertificate=$SNAI)" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+SNAI='3$EMAIL=ca@example.com,CN=Example CA,O=Openldap Example\5C, Ltd.,ST=California,C=US'
+
+echo 'Using ldapsearch to retrieve (userCertificate:certificateExactMatch:=serialNumberAndIssuer) [old format] ...'
+echo "# (userCertificate:certificateExactMatch:=$SNAI)" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "(userCertificate:certificateExactMatch:=$SNAI)" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+SNAI='{ issuer "EMAIL=ca@example.com,CN=Example CA,O=Openldap Example\5C, Ltd.,ST=California,C=US", serialNumber 3 }'
+
+echo 'Using ldapsearch to retrieve (userCertificate:certificateExactMatch:=serialNumberAndIssuer) [new format]...'
+echo "# (userCertificate:certificateExactMatch:=$SNAI)" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "(userCertificate:certificateExactMatch:=$SNAI)" >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$CERTIFICATETLS
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - certificate operations did not complete correctly"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test022-ppolicy b/tests/scripts/test022-ppolicy
new file mode 100755
index 0000000..292a97c
--- /dev/null
+++ b/tests/scripts/test022-ppolicy
@@ -0,0 +1,782 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $PPOLICY = ppolicyno; then
+ echo "Password policy overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $PPOLICYCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+USER="uid=nd, ou=People, dc=example, dc=com"
+PASS=testpassword
+PWADMIN="uid=ndadmin, ou=People, dc=example, dc=com"
+ADMINPASSWD=testpw
+
+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 "$MONITOR" -H $URI1 \
+ '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 /dev/null > $TESTOUT
+
+echo "Testing redundant ppolicy instance..."
+$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcOverlay=ppolicy,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcPPolicyConfig
+olcOverlay: ppolicy
+olcPPolicyDefault: cn=duplicate policy,ou=policies,dc=example,dc=com
+EOF
+RC=$?
+if test $RC = 0 ; then
+ echo "ldapadd should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Using ldapadd to populate the database..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ < $LDIFPPOLICY >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing account lockout..."
+$LDAPSEARCH -H $URI1 -D "$USER" -w wrongpw >$SEARCHOUT 2>&1
+sleep 2
+$LDAPSEARCH -H $URI1 -D "$USER" -w wrongpw >>$SEARCHOUT 2>&1
+sleep 2
+$LDAPSEARCH -H $URI1 -D "$USER" -w wrongpw >>$SEARCHOUT 2>&1
+sleep 2
+$LDAPSEARCH -e ppolicy -H $URI1 -D "$USER" -w wrongpw >> $SEARCHOUT 2>&1
+$LDAPSEARCH -e ppolicy -H $URI1 -D "$USER" -w $PASS >> $SEARCHOUT 2>&1
+COUNT=`grep "Account locked" $SEARCHOUT | wc -l`
+if test $COUNT != 2 ; then
+ echo "Account lockout test failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+DELAYATTR=`$LDAPSEARCH -D "$MANAGERDN" -H $URI1 -w $PASSWD -b "$USER" -E accountUsability 1.1`
+echo "$DELAYATTR" >> $SEARCHOUT
+DELAY=`echo "$DELAYATTR" | sed -n -e 's/.*seconds_before_unlock=\([[:digit:]]*\)/\1/p'`
+
+echo "Waiting $DELAY seconds for lockout to reset..."
+sleep $DELAY
+sleep 1
+
+$LDAPSEARCH -e ppolicy -H $URI1 -D "$USER" -w $PASS \
+ -b "$BASEDN" -s base >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+DELAYATTR=`$LDAPSEARCH -D "$MANAGERDN" -H $URI1 -w $PASSWD -b "$USER" -E accountUsability 1.1`
+echo "$DELAYATTR" >> $SEARCHOUT
+DELAY=`echo "$DELAYATTR" | sed -n -e 's/.*expire=\([[:digit:]]*\)/\1/p'`
+
+echo "Testing password expiration"
+echo "Waiting $DELAY seconds for password to expire..."
+sleep $DELAY
+sleep 1
+
+$LDAPSEARCH -e ppolicy -H $URI1 -D "$USER" -w $PASS \
+ -b "$BASEDN" -s base > $SEARCHOUT 2>&1
+sleep 2
+$LDAPSEARCH -e ppolicy -H $URI1 -D "$USER" -w $PASS \
+ -b "$BASEDN" -s base >> $SEARCHOUT 2>&1
+sleep 2
+$LDAPSEARCH -e ppolicy -H $URI1 -D "$USER" -w $PASS \
+ -b "$BASEDN" -s base >> $SEARCHOUT 2>&1
+sleep 2
+$LDAPSEARCH -e ppolicy -H $URI1 -D "$USER" -w $PASS \
+ -b "$BASEDN" -s base >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "Password expiration failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+COUNT=`grep "grace logins" $SEARCHOUT | wc -l`
+if test $COUNT != 3 ; then
+ echo "Password expiration test failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Resetting password to clear expired status"
+$LDAPPASSWD -H $URI1 \
+ -w secret -s $PASS \
+ -D "$MANAGERDN" "$USER" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filling password history..."
+$LDAPMODIFY -v -D "$USER" -H $URI1 -w $PASS >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: $USER
+changetype: modify
+delete: userpassword
+userpassword: $PASS
+-
+replace: userpassword
+userpassword: 20urgle12-1
+
+dn: $USER
+changetype: modify
+delete: userpassword
+userpassword: 20urgle12-1
+-
+replace: userpassword
+userpassword: 20urgle12-2
+
+dn: $USER
+changetype: modify
+delete: userpassword
+userpassword: 20urgle12-2
+-
+replace: userpassword
+userpassword: 20urgle12-3
+
+dn: $USER
+changetype: modify
+delete: userpassword
+userpassword: 20urgle12-3
+-
+replace: userpassword
+userpassword: 20urgle12-4
+
+dn: $USER
+changetype: modify
+delete: userpassword
+userpassword: 20urgle12-4
+-
+replace: userpassword
+userpassword: 20urgle12-5
+
+dn: $USER
+changetype: modify
+delete: userpassword
+userpassword: 20urgle12-5
+-
+replace: userpassword
+userpassword: 20urgle12-6
+
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+echo "Testing password history..."
+$LDAPMODIFY -v -D "$USER" -H $URI1 -w 20urgle12-6 >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: $USER
+changetype: modify
+delete: userPassword
+userPassword: 20urgle12-6
+-
+replace: userPassword
+userPassword: 20urgle12-2
+
+EOMODS
+RC=$?
+if test $RC = 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing failed logins when password/policy missing..."
+
+$LDAPSEARCH -e ppolicy -H $URI1 \
+ -D "uid=test, ou=People,$BASEDN" -w hasnopolicy \
+ -b "$BASEDN" -s base > $SEARCHOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "Password accepted ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+$LDAPSEARCH -e ppolicy -H $URI1 -D "$BASEDN" -w hasnopw \
+ -b "$BASEDN" -s base > $SEARCHOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "Password accepted ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+$LDAPSEARCH -H $URI1 -D "$MANAGERDN" -w $PASSWD -b "$BASEDN" \* \+ > $SEARCHOUT 2>&1
+COUNT=`grep "pwdFailureTime" $SEARCHOUT | wc -l`
+if test $COUNT != 0 ; then
+ echo "Failed login stored on an account without policy and or password"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing forced reset..."
+
+$LDAPMODIFY -v -D "$PWADMIN" -H $URI1 -w $ADMINPASSWD >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: $USER
+changetype: modify
+replace: userPassword
+userPassword: $PASS
+
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -e ppolicy -H $URI1 -D "$USER" -w $PASS \
+ -b "$BASEDN" -s base > $SEARCHOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "Forced reset failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+COUNT=`grep "Operations are restricted" $SEARCHOUT | wc -l`
+if test $COUNT != 1 ; then
+ echo "Forced reset test failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Clearing forced reset..."
+
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: $USER
+changetype: modify
+delete: pwdReset
+
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -e ppolicy -H $URI1 -D "$USER" -w $PASS \
+ -b "$BASEDN" -s base > $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Clearing forced reset failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing Safe modify..."
+
+$LDAPPASSWD -H $URI1 \
+ -w $PASS -s failexpect \
+ -D "$USER" >> $TESTOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "Safe modify test 1 failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+sleep 2
+
+OLDPASS=$PASS
+PASS=successexpect
+
+$LDAPPASSWD -H $URI1 \
+ -w $OLDPASS -s $PASS -a $OLDPASS \
+ -D "$USER" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Safe modify test 2 failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing length requirement..."
+# check control in response (ITS#5711)
+$LDAPPASSWD -H $URI1 \
+ -w $PASS -a $PASS -s 2shr \
+ -D "$USER" -e ppolicy > ${TESTOUT}.2 2>&1
+RC=$?
+cat ${TESTOUT}.2 >> $TESTOUT
+if test $RC = 0 ; then
+ echo "Length requirement test failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+COUNT=`grep "Password fails quality" ${TESTOUT}.2 | wc -l`
+if test $COUNT != 1 ; then
+ echo "Length requirement test failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+COUNT=`grep "Password is too short for policy" ${TESTOUT}.2 | wc -l`
+if test $COUNT != 1 ; then
+ echo "Control not returned in response"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+$LDAPPASSWD -H $URI1 \
+ -w $PASS -a $PASS -s passwordthatistoolong \
+ -D "$USER" -e ppolicy > ${TESTOUT}.2 2>&1
+RC=$?
+cat ${TESTOUT}.2 >> $TESTOUT
+COUNT=`grep "Password is too long for policy" ${TESTOUT}.2 | wc -l`
+if test $COUNT != 1 ; then
+ echo "Control not returned in response"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing hashed length requirement..."
+
+$LDAPMODIFY -H $URI1 -D "$USER" -w $PASS > \
+ ${TESTOUT}.2 2>&1 << EOMODS
+dn: $USER
+changetype: modify
+delete: userPassword
+userPassword: $PASS
+-
+add: userPassword
+userPassword: {MD5}xxxxxx
+
+EOMODS
+RC=$?
+cat ${TESTOUT}.2 >> $TESTOUT
+if test $RC = 0 ; then
+ echo "Hashed length requirement test failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+COUNT=`grep "Password fails quality" ${TESTOUT}.2 | wc -l`
+if test $COUNT != 1 ; then
+ echo "Hashed length requirement test failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing multiple password add/modify checks..."
+
+$LDAPMODIFY -H $URI1 -D "$MANAGERDN" -w $PASSWD >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Add Should Fail, ou=People, dc=example, dc=com
+changetype: add
+objectClass: inetOrgPerson
+cn: Add Should Fail
+sn: Fail
+userPassword: firstpw
+userPassword: secondpw
+EOMODS
+RC=$?
+if test $RC = 0 ; then
+ echo "Multiple password add test failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+$LDAPMODIFY -H $URI1 -D "$MANAGERDN" -w $PASSWD >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: $USER
+changetype: modify
+add: userPassword
+userPassword: firstpw
+userPassword: secondpw
+EOMODS
+RC=$?
+if test $RC = 0 ; then
+ echo "Multiple password modify add test failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+$LDAPMODIFY -H $URI1 -D "$MANAGERDN" -w $PASSWD >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: $USER
+changetype: modify
+replace: userPassword
+userPassword: firstpw
+userPassword: secondpw
+EOMODS
+RC=$?
+if test $RC = 0 ; then
+ echo "Multiple password modify replace test failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing idle password expiration"
+echo "Reconfiguring policy to replace expiration with idle expiration..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Standard Policy, ou=Policies, dc=example, dc=com
+changetype: modify
+delete: pwdMaxAge
+-
+add: pwdMaxIdle
+pwdMaxIdle: 15
+
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -e ppolicy -H $URI1 -D "$USER" -w $PASS \
+ -b "$BASEDN" -s base > $SEARCHOUT 2>&1
+
+DELAYATTR=`$LDAPSEARCH -D "$MANAGERDN" -H $URI1 -w $PASSWD -b "$USER" -E accountUsability 1.1`
+echo "$DELAYATTR" >> $SEARCHOUT
+DELAY=`echo "$DELAYATTR" | sed -n -e 's/.*expire=\([[:digit:]]*\)/\1/p'`
+
+echo "Waiting $DELAY seconds for password to expire..."
+sleep $DELAY
+sleep 1
+
+$LDAPSEARCH -e ppolicy -H $URI1 -D "$USER" -w $PASS \
+ -b "$BASEDN" -s base >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 49 ; then
+ echo "Password idle expiration failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Reverting policy changes..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Standard Policy, ou=Policies, dc=example, dc=com
+changetype: modify
+delete: pwdMaxIdle
+-
+add: pwdMaxAge
+pwdMaxAge: 30
+
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+if test "$BACKLDAP" != "ldapno" && test "$SYNCPROV" != "syncprovno" ; then
+echo ""
+echo "Setting up policy state forwarding test..."
+
+mkdir $DBDIR2
+sed -e "s,$DBDIR1,$DBDIR2," < $CONF1 > $CONF2
+echo "Starting slapd consumer on TCP/IP port $PORT2..."
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+echo "Configuring syncprov on provider..."
+if [ "$SYNCPROV" = syncprovmod ]; then
+ $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectclass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+olcModuleLoad: syncprov.la
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for moduleLoad ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+
+$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcOverlay={1}syncprov,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: {1}syncprov
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for provider database config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check that slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '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 "Configuring syncrepl on consumer..."
+if [ "$BACKLDAP" = ldapmod ]; then
+ $LDAPADD -D cn=config -H $URI2 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectclass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/back-ldap
+olcModuleLoad: back_ldap.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 $URI2 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcOverlay={0}chain,olcDatabase={-1}frontend,cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcChainConfig
+olcOverlay: {0}chain
+
+dn: olcDatabase=ldap,olcOverlay={0}chain,olcDatabase={-1}frontend,cn=config
+changetype: add
+objectClass: olcLDAPConfig
+objectClass: olcChainDatabase
+olcDBURI: $URI1
+olcDbIDAssertBind: bindmethod=simple
+ binddn="cn=manager,dc=example,dc=com"
+ credentials=secret
+ mode=self
+
+dn: olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+add: olcSyncrepl
+olcSyncrepl: rid=1
+ provider=$URI1
+ binddn="cn=manager,dc=example,dc=com"
+ bindmethod=simple
+ credentials=secret
+ searchbase="dc=example,dc=com"
+ type=refreshAndPersist
+ retry="3 5 300 5"
+-
+add: olcUpdateref
+olcUpdateref: $URI1
+-
+
+dn: olcOverlay={0}ppolicy,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+replace: olcPPolicyForwardUpdates
+olcPPolicyForwardUpdates: TRUE
+-
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting for consumer to sync..."
+sleep $SLEEP1
+
+echo "Testing policy state forwarding..."
+$LDAPSEARCH -H $URI2 -D "$USER" -w wrongpw >$SEARCHOUT 2>&1
+RC=$?
+if test $RC != 49 ; then
+ echo "ldapsearch should have failed with 49, got ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+$LDAPSEARCH -H $URI1 -D "$MANAGERDN" -w $PASSWD -b "$USER" \* \+ >> $SEARCHOUT 2>&1
+COUNT=`grep "pwdFailureTime" $SEARCHOUT | wc -l`
+if test $COUNT != 1 ; then
+ echo "Policy state forwarding failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+# End of chaining test
+
+fi
+
+echo ""
+echo "Testing obsolete Netscape ppolicy controls..."
+echo "Enabling Netscape controls..."
+$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: olcOverlay={0}ppolicy,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+replace: olcPPolicySendNetscapeControls
+olcPPolicySendNetscapeControls: TRUE
+-
+
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Reconfiguring policy to remove grace logins..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Standard Policy, ou=Policies, dc=example, dc=com
+changetype: modify
+delete: pwdGraceAuthnLimit
+-
+replace: pwdMaxAge
+pwdMaxAge: 15
+-
+
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+OLDPASS=$PASS
+PASS=newpass
+$LDAPPASSWD -H $URI1 \
+ -w secret -s $PASS \
+ -D "$MANAGERDN" "$USER" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Setting new password failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Clearing forced reset..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: $USER
+changetype: modify
+delete: pwdReset
+
+EOMODS
+
+DELAYATTR=`$LDAPSEARCH -D "$MANAGERDN" -H $URI1 -w $PASSWD -b "$USER" -E accountUsability 1.1`
+echo "$DELAYATTR" >> $TESTOUT
+DELAY=`echo "$DELAYATTR" | sed -n -e 's/.*expire=\([[:digit:]]*\)/\1/p'`
+DELAY=`expr $DELAY - 10`
+
+echo "Testing password expiration"
+echo "Waiting $DELAY seconds for password to expire..."
+sleep $DELAY
+
+$LDAPSEARCH -H $URI1 -D "$USER" -w $PASS \
+ -b "$BASEDN" -s base > $SEARCHOUT 2>&1
+sleep 3
+$LDAPSEARCH -H $URI1 -D "$USER" -w $PASS \
+ -b "$BASEDN" -s base >> $SEARCHOUT 2>&1
+sleep 3
+$LDAPSEARCH -H $URI1 -D "$USER" -w $PASS \
+ -b "$BASEDN" -s base >> $SEARCHOUT 2>&1
+sleep 3
+$LDAPSEARCH -H $URI1 -D "$USER" -w $PASS \
+ -b "$BASEDN" -s base >> $SEARCHOUT 2>&1
+sleep 3
+$LDAPSEARCH -H $URI1 -D "$USER" -w $PASS \
+ -b "$BASEDN" -s base >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "Password expiration failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+COUNT=`grep "PasswordExpiring" $SEARCHOUT | wc -l`
+if test $COUNT = 0 ; then
+ echo "Password expiring warning test failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test023-refint b/tests/scripts/test023-refint
new file mode 100755
index 0000000..6c10236
--- /dev/null
+++ b/tests/scripts/test023-refint
@@ -0,0 +1,276 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2004-2022 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 $REFINT = refintno; then
+ echo "Referential Integrity overlay not available, test skipped"
+ exit 0
+fi
+
+if test $BACKEND = wt ; then
+ echo "back-wt does not support subtree rename"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $REFINTCONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFREFINT
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd referential integrity operations..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Searching unmodified database..."
+
+$LDAPSEARCH -S "" -b "o=refint" -H $URI1 > $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$EGREP_CMD "(manager|secretary):" $SEARCHOUT | sed "s/george/foster/g" | \
+ sort > $TESTOUT 2>&1
+
+echo "Testing modrdn..."
+$LDAPMODRDN -D "$REFINTDN" -r -H $URI1 -w $PASSWD > \
+ /dev/null 2>&1 'uid=george,ou=users,o=refint' 'uid=foster'
+#$LDAPMODRDN -D "$REFINTDN" -r -H $URI1 -w $PASSWD \
+# 'uid=george,ou=users,o=refint' 'uid=foster'
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodrdn failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+sleep 1;
+
+echo "Using ldapsearch to check dependents new rdn..."
+
+$LDAPSEARCH -S "" -b "o=refint" -H $URI1 > $SEARCHOUT 2>&1
+
+RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$EGREP_CMD "(manager|secretary):" $SEARCHOUT | sort > $SEARCHFLT 2>&1
+
+echo "Comparing ldapsearch results against original..."
+$CMP $TESTOUT $SEARCHFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - modify operations did not complete correctly"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing delete..."
+$LDAPMODIFY -v -D "$REFINTDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EDEL
+version: 1
+dn: uid=foster,ou=users,o=refint
+changetype: delete
+EDEL
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+sleep 1;
+
+echo "Using ldapsearch to verify dependents have been deleted..."
+$LDAPSEARCH -S "" -b "o=refint" -H $URI1 > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$EGREP_CMD "(manager|secretary):" $SEARCHOUT > $SEARCHFLT 2>&1
+
+RC=`grep -c foster $SEARCHFLT`
+if test $RC != 0 ; then
+ echo "dependent modify failed - dependents were not deleted"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Additional test records..."
+
+$LDAPADD -D "$REFINTDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << ETEST
+dn: uid=special,ou=users,o=refint
+objectClass: inetOrgPerson
+objectClass: extensibleObject
+uid: special
+sn: special
+cn: special
+businessCategory: nothing
+carLicense: FOO
+departmentNumber: 933
+displayName: special
+employeeNumber: 41491
+employeeType: vendor
+givenName: special
+member: uid=alice,ou=users,o=refint
+ETEST
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing delete when referential attribute is a MUST..."
+$LDAPMODIFY -v -D "$REFINTDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EDEL
+version: 1
+dn: uid=alice,ou=users,o=refint
+changetype: delete
+EDEL
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -v -D "$REFINTDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EDEL
+version: 1
+dn: cn=group,o=refint
+changetype: add
+objectClass: groupOfNames
+cn: group
+member: uid=bill,ou=users,o=refint
+member: uid=bob,ou=users,o=refint
+member: uid=dave,ou=users,o=refint
+member: uid=jorge,ou=users,o=refint
+member: uid=theman,ou=users,o=refint
+member: uid=richard,ou=users,o=refint
+EDEL
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+sleep 1;
+
+$LDAPSEARCH -S "" -b "o=refint" -H $URI1 \
+ manager member secretary > $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$EGREP_CMD "(manager|member|secretary):" $SEARCHOUT \
+ | sed "s/ou=users/ou=people/g" | \
+ sort > $TESTOUT 2>&1
+
+echo "testing subtree rename"
+$LDAPMODRDN -D "$REFINTDN" -r -H $URI1 -w $PASSWD > \
+ /dev/null 2>&1 'ou=users,o=refint' 'ou=people'
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodrdn failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+sleep 1;
+
+echo "Using ldapsearch to check dependents new rdn..."
+
+$LDAPSEARCH -S "" -b "o=refint" -H $URI1 \
+ manager member secretary > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$EGREP_CMD "(manager|member|secretary):" $SEARCHOUT \
+ | sort > $SEARCHFLT 2>&1
+
+echo "Comparing ldapsearch results against original..."
+$CMP $TESTOUT $SEARCHFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - subtree rename operations did not complete correctly"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test024-unique b/tests/scripts/test024-unique
new file mode 100755
index 0000000..01b2b99
--- /dev/null
+++ b/tests/scripts/test024-unique
@@ -0,0 +1,845 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2004-2022 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 $UNIQUE = uniqueno; then
+ echo "Attribute Uniqueness overlay not available, test skipped"
+ exit 0
+fi
+
+RCODEconstraint=19
+RCODEnorelax=50
+test $BACKEND = null && RCODEconstraint=0
+
+mkdir -p $TESTDIR $DBDIR1
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $UNIQUECONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFUNIQUE
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+mkdir $TESTDIR/confdir
+$SLAPD -f $CONF1 -F $TESTDIR/confdir -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd attribute uniqueness operations..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 a unique record..."
+$LDAPADD -D "$UNIQUEDN" -H $URI1 -w $PASSWD \
+ > /dev/null << EOTUNIQ1
+dn: uid=dave,ou=users,o=unique
+objectClass: inetOrgPerson
+objectClass: simpleSecurityObject
+uid: dave
+sn: nothere
+cn: dave
+businessCategory: otest
+carLicense: TEST
+departmentNumber: 42
+# NOTE: use special chars in attr value to be used
+# in internal searches ITS#4212
+displayName: Dave (ITS#4212)
+employeeNumber: 69
+employeeType: contractor
+givenName: Dave
+userpassword: $PASSWD
+EOTUNIQ1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding a non-unique record..."
+$LDAPADD -D "uid=dave,ou=users,o=unique" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOTUNIQ2
+dn: uid=bill,ou=users,o=unique
+objectClass: inetOrgPerson
+uid: bill
+sn: johnson
+cn: bill
+businessCategory: rtest
+carLicense: ABC123
+departmentNumber: 42
+displayName: Bill
+employeeNumber: 5150
+employeeType: contractor
+givenName: Bill
+EOTUNIQ2
+RC=$?
+if test $RC != $RCODEconstraint ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+# ITS#6641/8057/8245
+echo "Trying to bypass uniqueness as a normal user..."
+$LDAPADD -e \!relax -D "uid=dave,ou=users,o=unique" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOTUNIQ2
+dn: uid=bill,ou=users,o=unique
+objectClass: inetOrgPerson
+uid: bill
+sn: johnson
+cn: bill
+businessCategory: rtest
+carLicense: ABC123
+departmentNumber: 42
+displayName: Bill
+employeeNumber: 5150
+employeeType: contractor
+givenName: Bill
+EOTUNIQ2
+RC=$?
+if test $RC != $RCODEnorelax && test $RC != $RCODEconstraint ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Trying to bypass uniqueness as a normal user with ManageDSAIt..."
+$LDAPADD -M -D "uid=dave,ou=users,o=unique" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOTUNIQ2
+dn: uid=bill,ou=users,o=unique
+objectClass: inetOrgPerson
+uid: bill
+sn: johnson
+cn: bill
+businessCategory: rtest
+carLicense: ABC123
+departmentNumber: 42
+displayName: Bill
+employeeNumber: 5150
+employeeType: contractor
+givenName: Bill
+EOTUNIQ2
+RC=$?
+if test $RC != $RCODEconstraint ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Bypassing uniqueness as an admin user..."
+$LDAPADD -e \!relax -D "$UNIQUEDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOTUNIQ2
+dn: uid=bill,ou=users,o=unique
+objectClass: inetOrgPerson
+uid: bill
+sn: johnson
+cn: bill
+businessCategory: rtest
+carLicense: ABC123
+departmentNumber: 42
+displayName: Bill
+employeeNumber: 5150
+employeeType: contractor
+givenName: Bill
+EOTUNIQ2
+RC=$?
+if test $RC != 0 ; then
+ echo "spurious unique error ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Cleaning up"
+$LDAPDELETE -D "$UNIQUEDN" -H $URI1 -w $PASSWD \
+ "uid=bill,ou=users,o=unique" > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0; then
+ echo "ldapdelete failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo Dynamically retrieving initial configuration...
+$LDAPSEARCH -S "" -b olcOverlay='{0}'unique,olcDatabase='{1}'$BACKEND,cn=config -D cn=config -y $CONFIGPWF -H $URI1 -LLL | tr -d \\r >$TESTDIR/initial-config.ldif
+cat <<EOF >$TESTDIR/initial-reference.ldif
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcUniqueConfig
+olcOverlay: {0}unique
+olcUniqueBase: o=unique
+olcUniqueAttribute: employeeNumber
+olcUniqueAttribute: displayName
+
+EOF
+diff $TESTDIR/initial-config.ldif $TESTDIR/initial-reference.ldif > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Initial configuration is not reported correctly."
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Dynamically trying to add a URI with legacy attrs present...
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \
+ > $TESTOUT 2>&1 <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+add: olcUniqueURI
+olcUniqueURI: ldap:///?employeeNumber,displayName?sub
+EOF
+RC=$?
+if test $RC != 80 ; then
+ echo "legacy and unique_uri allowed together"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Dynamically trying to add legacy ignored attrs with legacy attrs present...
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \
+ > $TESTOUT 2>&1 <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+add: olcUniqueIgnore
+olcUniqueIgnore: objectClass
+EOF
+RC=$?
+if test $RC != 80 ; then
+ echo "legacy attrs and legacy ignore attrs allowed together"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Verifying initial configuration intact...
+$LDAPSEARCH -S "" -b olcOverlay='{0}'unique,olcDatabase='{1}'$BACKEND,cn=config -D cn=config -y $CONFIGPWF -H $URI1 -LLL | tr -d \\r >$TESTDIR/initial-config-recheck.ldif
+diff $TESTDIR/initial-config-recheck.ldif $TESTDIR/initial-reference.ldif > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Initial configuration damaged by unsuccessful modifies."
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Dynamically removing legacy base...
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \
+ > $TESTOUT 2>&1 <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+delete: olcUniqueBase
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "base removal failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Verifying base removal...
+$LDAPSEARCH -S "" -b olcOverlay='{0}'unique,olcDatabase='{1}'$BACKEND,cn=config -D cn=config -y $CONFIGPWF -H $URI1 -LLL | tr -d \\r >$TESTDIR/baseremoval-config.ldif
+cat >$TESTDIR/baseremoval-reference.ldif <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcUniqueConfig
+olcOverlay: {0}unique
+olcUniqueAttribute: employeeNumber
+olcUniqueAttribute: displayName
+
+EOF
+diff $TESTDIR/baseremoval-config.ldif $TESTDIR/baseremoval-reference.ldif > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Configuration damaged by base removal"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Adding a non-unique record..."
+$LDAPADD -D "uid=dave,ou=users,o=unique" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOTUNIQ2
+dn: uid=bill,ou=users,o=unique
+objectClass: inetOrgPerson
+uid: bill
+sn: johnson
+cn: bill
+businessCategory: rtest
+carLicense: ABC123
+departmentNumber: 42
+displayName: Bill
+employeeNumber: 5150
+employeeType: contractor
+givenName: Bill
+EOTUNIQ2
+RC=$?
+if test $RC != $RCODEconstraint ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Trying a legacy base outside of the backend...
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \
+ > $TESTOUT 2>&1 <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+add: olcUniqueBase
+olcUniqueBase: cn=config
+EOF
+RC=$?
+if test $RC != 80 ; then
+ echo "out of backend scope base allowed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Adding and removing attrs..."
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \
+ > $TESTOUT 2>&1 <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+add: olcUniqueAttribute
+olcUniqueAttribute: description
+olcUniqueAttribute: telephoneNumber
+-
+delete: olcUniqueAttribute
+olcUniqueAttribute: displayName
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "Unable to remove an attribute"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Verifying we removed the right attr..."
+$LDAPADD -D "uid=dave,ou=users,o=unique" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOTUNIQ2
+dn: uid=bill,ou=users,o=unique
+objectClass: inetOrgPerson
+uid: bill
+sn: johnson
+cn: bill
+businessCategory: rtest
+carLicense: ABC123
+departmentNumber: 42
+displayName: Bill
+employeeNumber: 5150
+employeeType: contractor
+givenName: Bill
+EOTUNIQ2
+RC=$?
+if test $RC != $RCODEconstraint ; then
+ echo "olcUniqueAttribute single deletion hit the wrong value"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Removing legacy config and adding URIs...
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \
+ > $TESTOUT 2>&1 <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+delete: olcUniqueAttribute
+-
+add: olcUniqueURI
+olcUniqueURI: ldap:///?employeeNumber,displayName?sub
+olcUniqueURI: ldap:///?description?one
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "Reconfiguration to URIs failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Dynamically retrieving second configuration...
+$LDAPSEARCH -S "" -b olcOverlay='{0}'unique,olcDatabase='{1}'$BACKEND,cn=config -D cn=config -y $CONFIGPWF -H $URI1 -LLL | tr -d \\r >$TESTDIR/second-config.ldif
+cat >$TESTDIR/second-reference.ldif <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcUniqueConfig
+olcOverlay: {0}unique
+olcUniqueURI: ldap:///?employeeNumber,displayName?sub
+olcUniqueURI: ldap:///?description?one
+
+EOF
+diff $TESTDIR/second-config.ldif $TESTDIR/second-reference.ldif > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Second configuration is not reported correctly."
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Adding a non-unique record..."
+$LDAPADD -D "uid=dave,ou=users,o=unique" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOTUNIQ2
+dn: uid=bill,ou=users,o=unique
+objectClass: inetOrgPerson
+uid: bill
+sn: johnson
+cn: bill
+businessCategory: rtest
+carLicense: ABC123
+departmentNumber: 42
+displayName: Bill
+employeeNumber: 5150
+employeeType: contractor
+givenName: Bill
+EOTUNIQ2
+RC=$?
+if test $RC != $RCODEconstraint ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Dynamically trying to add legacy base
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \
+ > $TESTOUT 2>&1 <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+add: olcUniqueBase
+olcUniqueBase: o=unique
+EOF
+RC=$?
+if test $RC != 80 ; then
+ echo "legacy base allowed with URIs"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Dynamically trying to add legacy attrs
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \
+ > $TESTOUT 2>&1 <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+add: olcUniqueAttribute
+olcUniqueAttribute: description
+EOF
+RC=$?
+if test $RC != 80 ; then
+ echo "legacy attributes allowed with URIs"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Dynamically trying to add legacy strictness
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \
+ > $TESTOUT 2>&1 <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+add: olcUniqueStrict
+olcUniqueStrict: TRUE
+EOF
+RC=$?
+if test $RC != 80 ; then
+ echo "legacy strictness allowed with URIs"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+#echo ----------------------
+echo Dynamically trying a bad filter...
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \
+ > $TESTOUT 2>&1 <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+replace: olcUniqueURI
+olcUniqueURI: ldap:///?sn?sub?((cn=e*))
+EOF
+RC=$?
+if test $RC != 80 ; then
+ echo "bad filter allowed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Verifying second configuration intact...
+$LDAPSEARCH -S "" -b olcOverlay='{0}'unique,olcDatabase='{1}'$BACKEND,cn=config -D cn=config -y $CONFIGPWF -H $URI1 -LLL | tr -d \\r >$TESTDIR/second-config-recheck.ldif
+diff $TESTDIR/second-config-recheck.ldif $TESTDIR/second-reference.ldif > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Second configuration damaged by rejected modifies."
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+#echo ----------------------
+echo Dynamically reconfiguring to use different URIs...
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \
+ > $TESTOUT 2>&1 <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+add: olcUniqueURI
+olcUniqueURI: ldap:///?sn?sub?(cn=e*)
+olcUniqueURI: ldap:///?uid?sub?(cn=edgar)
+-
+delete: olcUniqueURI
+olcUniqueURI: ldap:///?description?one
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "unable to reconfigure"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Dynamically retrieving third configuration...
+$LDAPSEARCH -S "" -b olcOverlay='{0}'unique,olcDatabase='{1}'$BACKEND,cn=config -D cn=config -y $CONFIGPWF -H $URI1 -LLL | tr -d \\r >$TESTDIR/third-config.ldif
+cat >$TESTDIR/third-reference.ldif <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcUniqueConfig
+olcOverlay: {0}unique
+olcUniqueURI: ldap:///?employeeNumber,displayName?sub
+olcUniqueURI: ldap:///?sn?sub?(cn=e*)
+olcUniqueURI: ldap:///?uid?sub?(cn=edgar)
+
+EOF
+diff $TESTDIR/third-config.ldif $TESTDIR/third-reference.ldif > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Third configuration is not reported correctly."
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Adding a record unique in both domains if filtered..."
+
+$LDAPADD -D "$UNIQUEDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF
+dn: uid=edgar,ou=users,o=unique
+objectClass: inetOrgPerson
+uid: edgar
+sn: johnson
+cn: edgar
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Adding a record unique in all domains because of filter conditions "
+$LDAPADD -D "$UNIQUEDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF
+dn: uid=empty,ou=users,o=unique
+objectClass: inetOrgPerson
+uid: edgar
+cn: empty
+sn: empty
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "spurious unique error ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Sending an empty modification"
+
+$LDAPMODIFY -D "$UNIQUEDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF
+dn: uid=empty,ou=users,o=unique
+changetype: modify
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "spurious unique error ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Making a record non-unique"
+$LDAPMODIFY -D "uid=dave,ou=users,o=unique" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF
+dn: uid=empty,ou=users,o=unique
+changetype: modify
+replace: sn
+sn: johnson
+EOF
+
+RC=$?
+if test $RC != $RCODEconstraint ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+# ITS#6641/8057/8245
+echo "Trying to bypass uniqueness as a normal user..."
+$LDAPMODIFY -e \!relax -D "uid=dave,ou=users,o=unique" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF
+dn: uid=empty,ou=users,o=unique
+changetype: modify
+replace: sn
+sn: johnson
+EOF
+
+RC=$?
+if test $RC != $RCODEnorelax && test $RC != $RCODEconstraint ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Trying to bypass uniqueness as a normal user with ManageDSAIt..."
+$LDAPMODIFY -M -D "uid=dave,ou=users,o=unique" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF
+dn: uid=empty,ou=users,o=unique
+changetype: modify
+replace: sn
+sn: johnson
+EOF
+
+RC=$?
+if test $RC != $RCODEconstraint ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Bypassing uniqueness as an admin user..."
+$LDAPMODIFY -e \!relax -D "$UNIQUEDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF
+dn: uid=empty,ou=users,o=unique
+changetype: modify
+replace: sn
+sn: johnson
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "spurious unique error ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Cleaning up"
+$LDAPMODIFY -D "$UNIQUEDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF
+dn: uid=empty,ou=users,o=unique
+changetype: modify
+replace: sn
+sn: empty
+EOF
+
+RC=$?
+if test $RC != 0; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding another unique record..."
+$LDAPADD -D "$UNIQUEDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF
+dn: uid=not edgar,uid=edgar,ou=users,o=unique
+objectClass: inetOrgPerson
+uid: not edgar
+sn: Alan
+cn: not edgar
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Making the record non-unique with modrdn..."
+$LDAPMODRDN -D "uid=dave,ou=users,o=unique" -H $URI1 -w $PASSWD \
+ "uid=not edgar,uid=edgar,ou=users,o=unique" "uid=edgar" > $TESTOUT 2>&1
+
+RC=$?
+if test $RC != $RCODEconstraint ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+# ITS#6641/8057/8245
+echo "Trying to bypass uniqueness as a normal user..."
+$LDAPMODRDN -e \!relax -D "uid=dave,ou=users,o=unique" -H $URI1 -w $PASSWD \
+ "uid=not edgar,uid=edgar,ou=users,o=unique" "uid=edgar" > $TESTOUT 2>&1
+
+RC=$?
+if test $RC != $RCODEnorelax && test $RC != $RCODEconstraint ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Trying to bypass uniqueness as a normal user with a ManageDSAIt control..."
+$LDAPMODRDN -M -D "uid=dave,ou=users,o=unique" -H $URI1 -w $PASSWD \
+ "uid=not edgar,uid=edgar,ou=users,o=unique" "uid=edgar" > $TESTOUT 2>&1
+
+RC=$?
+if test $RC != $RCODEconstraint ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Bypassing uniqueness as an admin user..."
+$LDAPMODRDN -e \!relax -D "$UNIQUEDN" -H $URI1 -w $PASSWD \
+ "uid=not edgar,uid=edgar,ou=users,o=unique" "uid=edgar" > $TESTOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "spurious unique error ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Cleaning up"
+$LDAPDELETE -D "$UNIQUEDN" -H $URI1 -w $PASSWD \
+ "uid=edgar,uid=edgar,ou=users,o=unique" > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0; then
+ echo "ldapdelete failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding a record unique in one domain, non-unique in the filtered domain..."
+
+$LDAPADD -D "uid=dave,ou=users,o=unique" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF
+dn: uid=elvis,ou=users,o=unique
+objectClass: inetOrgPerson
+uid: elvis
+sn: johnson
+cn: elvis
+EOF
+
+RC=$?
+if test $RC != $RCODEconstraint ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+#echo ----------------------
+echo Dynamically reconfiguring to use attribute-ignore URIs...
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \
+ > $TESTOUT 2>&1 <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+replace: olcUniqueURI
+olcUniqueURI: ignore ldap:///?objectClass,uid,cn,sn?sub
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "unable to reconfigure"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Dynamically retrieving fourth configuration...
+$LDAPSEARCH -S "" -b olcOverlay='{0}'unique,olcDatabase='{1}'$BACKEND,cn=config -D cn=config -y $CONFIGPWF -H $URI1 -LLL | tr -d \\r >$TESTDIR/fourth-config.ldif
+cat >$TESTDIR/fourth-reference.ldif <<EOF
+dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcUniqueConfig
+olcOverlay: {0}unique
+olcUniqueURI: ignore ldap:///?objectClass,uid,cn,sn?sub
+
+EOF
+diff $TESTDIR/fourth-config.ldif $TESTDIR/fourth-reference.ldif > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Fourth configuration is not reported correctly."
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Adding a record unique in the ignore-domain..."
+
+$LDAPADD -D "$UNIQUEDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF
+dn: uid=elvis,ou=users,o=unique
+objectClass: inetOrgPerson
+uid: elvis
+sn: johnson
+cn: elvis
+description: left the building
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Adding a record non-unique in the ignore-domain..."
+
+$LDAPADD -D "uid=dave,ou=users,o=unique" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF
+dn: uid=harry,ou=users,o=unique
+objectClass: inetOrgPerson
+uid: harry
+sn: johnson
+cn: harry
+description: left the building
+EOF
+
+RC=$?
+if test $RC != $RCODEconstraint ; then
+ echo "unique check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test025-limits b/tests/scripts/test025-limits
new file mode 100755
index 0000000..09f8bec
--- /dev/null
+++ b/tests/scripts/test025-limits
@@ -0,0 +1,1420 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+## FIXME: need to exclude legal but wrong results...
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+if test $BACKEND = null; then
+ echo "Limits irrelevant to $BACKEND backend, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $LIMITSCONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFLIMITS
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+. $CONFFILTER $BACKEND < $LIMITSCONF > $CONF1
+$SLAPINDEX -f $CONF1
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(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
+
+cat /dev/null > $SEARCHOUT
+
+echo ""
+echo "Testing regular search limits"
+echo ""
+
+echo "Testing no limits requested for unlimited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Unlimited User,ou=People,dc=example,dc=com' \
+ '(objectClass=*)' >$SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...success (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing no limits requested for rootdn=$MANAGERDN..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D "$MANAGERDN" \
+ '(objectClass=*)' >$SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...success (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=4
+echo "Testing limit requested for rootdn=$MANAGERDN..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -z $SIZELIMIT \
+ -D "$MANAGERDN" \
+ '(objectClass=*)' >$SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" -gt "$SIZELIMIT" ; then
+ echo "...error: got $COUNT entries instead of the requested $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ echo "...didn't bump into the requested size limit ($SIZELIMIT; got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" = "$SIZELIMIT" ; then
+ echo "...bumped into requested size limit ($SIZELIMIT)"
+ else
+ echo "...error: got $COUNT entries with a requested sizelimit of $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=2
+echo "Testing size limit request ($SIZELIMIT) for unlimited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -z $SIZELIMIT \
+ -D 'cn=Unlimited User,ou=People,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" -gt "$SIZELIMIT" ; then
+ echo "...error: got $COUNT entries instead of the requested $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ echo "...didn't bump into the requested size limit ($SIZELIMIT; got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" = "$SIZELIMIT" ; then
+ echo "...bumped into requested size limit ($SIZELIMIT)"
+ else
+ echo "...error: got $COUNT entries with a requested sizelimit of $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+TIMELIMIT=10
+echo "Testing time limit request ($TIMELIMIT s) for unlimited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -l $TIMELIMIT \
+ -D 'cn=Unlimited User,ou=People,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...didn't bump into the requested time limit ($TIMELIMIT s; got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 3)
+ if test x"$COUNT" != x ; then
+ COUNT=0
+ fi
+ echo "...bumped into requested time limit ($TIMELIMIT s; got $COUNT entries)"
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing no limits requested for soft limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Soft Limited User,ou=People,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...didn't bump into server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test x"$COUNT" != x ; then
+ echo "...bumped into server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=2
+echo "Testing lower than soft limit request ($SIZELIMIT) for soft limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -z $SIZELIMIT \
+ -D 'cn=Soft Limited User,ou=People,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" -gt "$SIZELIMIT" ; then
+ echo "...error: got $COUNT entries instead of the requested $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ echo "...didn't bump into either requested ($SIZELIMIT) or server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test "x$COUNT" != "x" ; then
+ if test "x$SIZELIMIT" = "x$COUNT" ; then
+ echo "...bumped into requested ($SIZELIMIT) size limit"
+ else
+ echo "...bumped into server-side size limit ($COUNT)"
+ fi
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=100
+echo "Testing higher than soft limit request ($SIZELIMIT) for soft limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -z $SIZELIMIT \
+ -D 'cn=Soft Limited User,ou=People,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" -gt "$SIZELIMIT" ; then
+ echo "...error: got $COUNT entries instead of the requested $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ echo "...didn't bump into either requested ($SIZELIMIT) or server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test "x$COUNT" != "x" ; then
+ if test "x$SIZELIMIT" = "x$COUNT" ; then
+ echo "...bumped into requested ($SIZELIMIT) size limit"
+ else
+ echo "...bumped into server-side size limit ($COUNT)"
+ fi
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=2
+echo "Testing lower than hard limit request ($SIZELIMIT) for hard limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -z $SIZELIMIT \
+ -D 'cn=Hard Limited User,ou=People,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" -gt "$SIZELIMIT" ; then
+ echo "...error: got $COUNT entries instead of the requested $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ echo "...didn't bump into either requested ($SIZELIMIT) or server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ echo "...bumped into requested ($SIZELIMIT) size limit"
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=100
+echo "Testing higher than hard limit request ($SIZELIMIT) for hard limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -z $SIZELIMIT \
+ -D 'cn=Hard Limited User,ou=People,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" -gt "$SIZELIMIT" ; then
+ echo "...error: got $COUNT entries instead of the requested $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ echo "...didn't bump into either requested ($SIZELIMIT) or server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" = "$SIZELIMIT" ; then
+ echo "...error: bumped into requested ($SIZELIMIT) size limit"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ else
+ echo "...got size limit $COUNT instead of requested $SIZELIMIT entries"
+ fi
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+# 11)
+# echo "...bumped into server-side hard size administrative limit"
+# ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=max
+echo "Testing max limit request ($SIZELIMIT) for hard limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -z $SIZELIMIT \
+ -D 'cn=Hard Limited User,ou=People,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...didn't bump into either requested ($SIZELIMIT) or server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test x"$COUNT" != x ; then
+ echo "...bumped into requested ($SIZELIMIT=$COUNT) size limit"
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+# 11)
+# echo "...bumped into server-side hard size administrative limit"
+# ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing lower than unchecked limit request for unchecked limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Unchecked Limited User,ou=People,dc=example,dc=com' \
+ '(uid=uncheckedlimited)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...success; didn't bump into server-side unchecked limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 11)
+ echo "...error: bumped into unchecked administrative limit"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+if test $INDEXDB = indexdb ; then
+
+echo "Testing higher than unchecked limit requested for unchecked limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Unchecked Limited User,ou=People,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...error: didn't bump into server-side unchecked limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ fi
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ 11)
+ echo "...bumped into unchecked administrative limit"
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing no limits requested for unchecked limited group..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Unchecked Limited User 2,ou=People,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...error: didn't bump into server-side unchecked limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ fi
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ 11)
+ echo "...bumped into unchecked administrative limit"
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+else
+ echo "Skipping test for unchecked limit with $BACKEND backend."
+fi
+
+echo "Testing no limits requested for limited regex..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Foo User,ou=People,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...didn't bump into server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test "x$COUNT" != "x" ; then
+ echo "...bumped into server-side size limit ($COUNT)"
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing no limits requested for limited onelevel..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Bar User,ou=People,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...didn't bump into server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test "x$COUNT" != "x" ; then
+ echo "...bumped into server-side size limit ($COUNT)"
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing no limit requested for limited children..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Unchecked Limited Users,ou=Groups,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...didn't bump into server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test "x$COUNT" != "x" ; then
+ echo "...bumped into server-side size limit ($COUNT)"
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing no limit requested for limited subtree..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Unchecked Limited User 3,ou=Admin,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...didn't bump into server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test "x$COUNT" != "x" ; then
+ echo "...bumped into server-side size limit ($COUNT)"
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing no limit requested for limited users..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Special User,dc=example,dc=com' \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...didn't bump into server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test "x$COUNT" != "x" ; then
+ echo "...bumped into server-side size limit ($COUNT)"
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing no limit requested for limited anonymous..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...didn't bump into server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test "x$COUNT" != "x" ; then
+ echo "...bumped into server-side size limit ($COUNT)"
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+if test $MAINDB != maindb ; then
+ # only mdb currently supports pagedResults control
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+
+ echo ">>>>> Test succeeded"
+ exit 0
+fi
+
+if test x"$SLAPD_PAGE_SIZE" != x ; then
+ PAGESIZE="$SLAPD_PAGE_SIZE"
+ if test "$PAGESIZE" -le 0 ; then
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+ echo ""
+ echo "Testing with pagedResults control disabled"
+ echo ""
+ echo ">>>>> Test succeeded"
+ exit 0
+ fi
+else
+ PAGESIZE=5
+fi
+
+echo ""
+echo "Testing regular search limits with pagedResults control (page size $PAGESIZE)"
+echo ""
+
+echo "Testing no limits requested for unlimited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Unlimited User,ou=People,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' >$SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...success (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=2
+echo "Testing size limit request ($SIZELIMIT) for unlimited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -z $SIZELIMIT \
+ -D 'cn=Unlimited User,ou=People,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" -gt "$SIZELIMIT" ; then
+ echo "...error: got $COUNT entries instead of the requested $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ echo "...didn't bump into the requested size limit ($SIZELIMIT; got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test x"$COUNT" != x ; then
+ if test $COUNT = $SIZELIMIT ; then
+ echo "...bumped into requested size limit ($SIZELIMIT)"
+ else
+ echo "...error: got $COUNT entries while requesting $SIZELIMIT..."
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+TIMELIMIT=10
+echo "Testing time limit request ($TIMELIMIT s) for unlimited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -l $TIMELIMIT \
+ -D 'cn=Unlimited User,ou=People,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...didn't bump into the requested time limit ($TIMELIMIT s; got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 3)
+ if test x"$COUNT" = x ; then
+ COUNT=0
+ fi
+ echo "...bumped into requested time limit ($TIMELIMIT s; got $COUNT entries)"
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing no limits requested for soft limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Soft Limited User,ou=People,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...didn't bump into server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test x"$COUNT" != x ; then
+ echo "...bumped into server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=2
+echo "Testing lower than soft limit request ($SIZELIMIT) for soft limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -z $SIZELIMIT \
+ -D 'cn=Soft Limited User,ou=People,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" -gt "$SIZELIMIT" ; then
+ echo "...error: got $COUNT entries instead of the requested $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ echo "...didn't bump into either requested ($SIZELIMIT) or server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test "x$COUNT" != "x" ; then
+ if test "x$SIZELIMIT" = "x$COUNT" ; then
+ echo "...bumped into requested ($SIZELIMIT) size limit"
+ else
+ echo "...bumped into server-side size limit ($COUNT)"
+ fi
+ else
+ echo "...bumped into either requested ($SIZELIMIT) or server-side size limit"
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=100
+echo "Testing higher than soft limit request ($SIZELIMIT) for soft limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -z $SIZELIMIT \
+ -D 'cn=Soft Limited User,ou=People,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" -gt "$SIZELIMIT" ; then
+ echo "...error: got $COUNT entries instead of the requested $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ echo "...didn't bump into either requested ($SIZELIMIT) or server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test "x$COUNT" != "x" ; then
+ if test "x$SIZELIMIT" = "x$COUNT" ; then
+ echo "...bumped into requested ($SIZELIMIT) size limit"
+ else
+ echo "...bumped into server-side size limit ($COUNT)"
+ fi
+ else
+ echo "...bumped into either requested ($SIZELIMIT) or server-side size limit"
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=2
+echo "Testing lower than hard limit request ($SIZELIMIT) for hard limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -z $SIZELIMIT \
+ -D 'cn=Hard Limited User,ou=People,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" -gt "$SIZELIMIT" ; then
+ echo "...error: got $COUNT entries instead of the requested $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ echo "...didn't bump into either requested ($SIZELIMIT) or server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" = "$SIZELIMIT" ; then
+ echo "...bumped into requested ($SIZELIMIT) size limit"
+ else
+ echo "...error: got size limit $SIZELIMIT but $COUNT entries"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=100
+echo "Testing higher than hard limit request ($SIZELIMIT) for hard limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -z $SIZELIMIT \
+ -D 'cn=Hard Limited User,ou=People,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" -gt "$SIZELIMIT" ; then
+ echo "...error: got $COUNT entries instead of the requested $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ echo "...didn't bump into either requested ($SIZELIMIT) or server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" = "$SIZELIMIT" ; then
+ echo "...error: bumped into requested ($SIZELIMIT) size limit"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ else
+ echo "...got size limit $COUNT instead of requested $SIZELIMIT entries"
+ fi
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+# 11)
+# echo "...bumped into hard size administrative limit"
+# ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=max
+echo "Testing max limit request ($SIZELIMIT) for hard limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -z $SIZELIMIT \
+ -D 'cn=Hard Limited User,ou=People,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...didn't bump into either requested ($SIZELIMIT) or server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test x"$COUNT" != x ; then
+ echo "...bumped into requested ($SIZELIMIT=$COUNT) size limit"
+ else
+ echo "...error: bumped into size limit but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+# 11)
+# echo "...bumped into hard size administrative limit"
+# ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing lower than unchecked limit request for unchecked limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Unchecked Limited User,ou=People,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(uid=uncheckedlimited)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...success; didn't bump into server-side unchecked limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+# 11)
+# echo "...bumped into unchecked administrative limit"
+# ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing higher than unchecked limit requested for unchecked limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Unchecked Limited User,ou=People,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...error: didn't bump into server-side unchecked limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ fi
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ 11)
+ echo "...bumped into unchecked administrative limit"
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo ""
+echo "Testing specific search limits with pagedResults control"
+echo ""
+
+echo "Testing no limit requested for unlimited page size ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Unlimited User,ou=Paged Results Users,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ echo "...success; didn't bump into server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test x"$COUNT" != x ; then
+ echo "...bumped into server-side size limit (got $COUNT entries)"
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing no limit requested for limited page size ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Page Size Limited User,ou=Paged Results Users,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ echo "...success; didn't bump into server-side page size limit (got $COUNT entries)"
+ ;;
+ 4)
+ echo "...bumped into page size limit ($COUNT)"
+ ;;
+ 11)
+ echo "...bumped into page size administrative limit"
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing no limit requested for pagedResults disabled ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Paged Results Disabled User,ou=Paged Results Users,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ echo "...success; didn't bump into server-side unchecked limit (got $COUNT entries)"
+ ;;
+ 4)
+ echo "...bumped into server-side size limit ($COUNT)"
+ ;;
+ 11)
+ echo "...bumped into pagedResults disabled administrative limit"
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Testing no limit requested for pagedResults total count limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Paged Results Limited User,ou=Paged Results Users,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ echo "...success; didn't bump into server-side unchecked limit (got $COUNT entries)"
+ ;;
+ 4)
+ echo "...bumped into server-side size limit ($COUNT)"
+ ;;
+ 11)
+ echo "...bumped into pagedResults total count administrative limit"
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=8
+echo "Testing higher than hard but lower then total count limit requested for pagedResults total count limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Paged Results Limited User,ou=Paged Results Users,dc=example,dc=com' \
+ -z $SIZELIMIT -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ echo "...success; didn't bump into either requested ($SIZELIMIT) or server-side unchecked limit (got $COUNT entries)"
+ ;;
+ 4)
+ if test "x$COUNT" != "x" ; then
+ if test "x$SIZELIMIT" = "x$COUNT" ; then
+ echo "...bumped into requested ($SIZELIMIT) size limit"
+ else
+ echo "...bumped into server-side size limit ($COUNT)"
+ fi
+ else
+ echo "...bumped into either requested ($SIZELIMIT) or server-side size limit"
+ fi
+ ;;
+ 11)
+ echo "...bumped into either hard size or pagedResults total count administrative limit"
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=15
+echo "Testing higher than total count limit requested for pagedResults total count limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Paged Results Limited User,ou=Paged Results Users,dc=example,dc=com' \
+ -z $SIZELIMIT -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ echo "...success; didn't bump into either requested ($SIZELIMIT) or server-side unchecked limit (got $COUNT entries)"
+ ;;
+ 4)
+ if test "x$COUNT" != "x" ; then
+ if test "x$SIZELIMIT" = "x$COUNT" ; then
+ echo "...bumped into requested ($SIZELIMIT) size limit"
+ else
+ echo "...bumped into server-side size limit ($COUNT)"
+ fi
+ else
+ echo "...bumped into either requested ($SIZELIMIT) or server-side size limit"
+ fi
+ ;;
+ 11)
+ echo "...bumped into pagedResults total count administrative limit"
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+SIZELIMIT=max
+echo "Testing max limit requested for pagedResults total count limited ID..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret \
+ -D 'cn=Paged Results Limited User,ou=Paged Results Users,dc=example,dc=com' \
+ -z $SIZELIMIT -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ echo "...success; didn't bump into either requested ($SIZELIMIT) or server-side unchecked limit (got $COUNT entries)"
+ ;;
+ 4)
+ if test "x$COUNT" != "x" ; then
+ if test "x$SIZELIMIT" = "x$COUNT" ; then
+ echo "...bumped into requested ($SIZELIMIT) size limit"
+ else
+ echo "...bumped into server-side size limit ($COUNT)"
+ fi
+ else
+ echo "...bumped into either requested ($SIZELIMIT) or server-side size limit"
+ fi
+ ;;
+ 11)
+ echo "...bumped into pagedResults total count administrative limit"
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+# ITS#4479
+PAGESIZE=1
+SIZELIMIT=2
+echo "Testing size limit request ($SIZELIMIT) for unlimited ID and pagesize=$PAGESIZE..."
+$LDAPRSEARCH -S "" -b "$BASEDN" -H $URI1 -w secret -z $SIZELIMIT \
+ -D 'cn=Unlimited User,ou=People,dc=example,dc=com' \
+ -E '!pr='$PAGESIZE'/noprompt' '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+COUNT=`awk '/^# numEntries:/ {print $3}' $SEARCHOUT`
+case $RC in
+ 0)
+ if test x"$COUNT" != x ; then
+ if test "$COUNT" -gt "$SIZELIMIT" ; then
+ echo "...error: got $COUNT entries instead of the requested $SIZELIMIT"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ echo "...didn't bump into the requested size limit ($SIZELIMIT; got $COUNT entries)"
+ else
+ echo "...error: did not expect ldapsearch success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+ 4)
+ if test x"$COUNT" != x ; then
+ if test $COUNT = $SIZELIMIT ; then
+ echo "...bumped into requested size limit ($SIZELIMIT)"
+ else
+ echo "...error: got $COUNT entries while requesting $SIZELIMIT..."
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ else
+ echo "...error: bumped into server-side size limit, but got no entries!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ ;;
+ *)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test026-dn b/tests/scripts/test026-dn
new file mode 100755
index 0000000..3676139
--- /dev/null
+++ b/tests/scripts/test026-dn
@@ -0,0 +1,180 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2004-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+. $CONFFILTER $BACKEND < $DNCONF > $CONF1
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd DN parsing..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Loading database..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -c -f $LDIFDN > \
+ $TESTOUT 2>&1
+
+cat /dev/null > $SEARCHOUT
+
+echo "Searching database..."
+echo "# Searching database..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+DN="OU=Sales+CN=J. Smith,DC=example,DC=net"
+echo "Searching database for DN=\"$DN\"..."
+echo "# Searching database for DN=\"$DN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "(member=$DN)" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+DN="testUUID=597ae2f6-16a6-1027-98f4-ABCDEFabcdef,DC=Example"
+echo "Searching database for entryUUID-named DN=\"$DN\"..."
+echo "# Searching database for entryUUID-named DN=\"$DN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "(member=$DN)" \
+ >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+DN="dc=example,dc=com"
+echo "Searching database for nameAndOptionalUID=\"$DN\"..."
+echo "# Searching database for nameAndOptionalUID=\"$DN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "(uniqueMember=$DN)" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+DN="dc=example,dc=com#'001000'B"
+echo "Searching database for nameAndOptionalUID=\"$DN\"..."
+echo "# Searching database for nameAndOptionalUID=\"$DN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "(uniqueMember=$DN)" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+DN="dc=example,dc=com#'1000'B"
+echo "Searching database for nameAndOptionalUID=\"$DN\"..."
+echo "# Searching database for nameAndOptionalUID=\"$DN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "(uniqueMember=$DN)" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+DN="dc=example,dc=com"
+echo "Searching database for uniqueMember~=\"$DN\" (approx)..."
+echo "# Searching database for uniqueMember~=\"$DN\" (approx)..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "(uniqueMember~=)" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+DN="dc=example,dc=com#'1000'B"
+echo "Searching database for uniqueMember~=\"$DN\" (approx)..."
+echo "# Searching database for uniqueMember~=\"$DN\" (approx)..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "(uniqueMember~=$DN)" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original data..."
+$LDIFFILTER < $DNOUT > $LDIFFLT
+echo "Comparing ldapsearch results against original..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - DN write operations did not complete correctly"
+ exit 1
+fi
+
+#####
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test027-emptydn b/tests/scripts/test027-emptydn
new file mode 100755
index 0000000..a1f1512
--- /dev/null
+++ b/tests/scripts/test027-emptydn
@@ -0,0 +1,175 @@
+#! /bin/sh
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2004-2022 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
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+. $CONFFILTER $BACKEND < $EMPTYDNCONF > $CONF1
+
+echo "Running slapadd to build \"dc=example,dc=com\" slapd database..."
+$SLAPADD -f $CONF1 -n 1 -l $LDIFEMPTYDN1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Running slapadd to build empty DN slapd database..."
+$SLAPADD -f $CONF1 -b "" -l $LDIFEMPTYDN2
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd empty DN handling..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Searching database..."
+
+$LDAPSEARCH -S "" -b "" -H $URI1 > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+kill -HUP $KILLPIDS
+wait
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering expected results..."
+$LDIFFILTER < $EMPTYDNOUT1 > $LDIFFLT
+echo "Comparing ldapsearch results against original..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - empty DN write operations did not complete correctly"
+ exit 1
+fi
+
+echo "Comparison of database generated via slapadd succeeded"
+
+echo "Cleaning up database directories..."
+/bin/rm -rf $TESTDIR/db.*
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd empty DN handling..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Loading database..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ -f $LDIFEMPTYDN1 > /dev/null 2>&1
+$LDAPADD -D "$EMPTYDNDN" -H $URI1 -w $PASSWD \
+ -f $LDIFEMPTYDN2 > /dev/null 2>&1
+
+$LDAPMODIFY -D "$EMPTYDNDN" -H $URI1 -w $PASSWD \
+ > /dev/null 2>&1 << EOF
+dn: o=Beispiel,c=DE
+changetype: delete
+
+dn: c=DE
+changetype: delete
+EOF
+
+echo "Searching database..."
+
+$LDAPSEARCH -S "" -b "" -H $URI1 > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering expected results..."
+$LDIFFILTER < $EMPTYDNOUT2 > $LDIFFLT
+echo "Comparing ldapsearch results against original..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - empty DN write operations did not complete correctly"
+ exit 1
+fi
+
+#####
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test028-idassert b/tests/scripts/test028-idassert
new file mode 100755
index 0000000..76fb5c8
--- /dev/null
+++ b/tests/scripts/test028-idassert
@@ -0,0 +1,273 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+echo "### This test requires the LDAP backend and the rwm overlay."
+echo "### If available, and explicitly requested, it can use SASL bind;"
+echo "### note that SASL must be properly set up, and the requested"
+echo "### mechanism must be available. Define SLAPD_USE_SASL={yes|<mech>},"
+echo "### with \"yes\" defaulting to DIGEST-MD5 to enable SASL authc[/authz]."
+
+if test $BACKLDAP = "ldapno" ; then
+ echo "LDAP backend not available, test skipped"
+ exit 0
+fi
+
+if test $RWM = "rwmno" ; then
+ echo "Rewrite/remap overlay not available, test skipped"
+ exit 0
+fi
+
+if test $WITH_SASL = "yes" ; then
+ if test $USE_SASL != "no" ; then
+ if test $USE_SASL = "yes" ; then
+ MECH="DIGEST-MD5"
+ else
+ MECH="$USE_SASL"
+ fi
+ echo "Using SASL authc[/authz] with mech=$MECH; unset SLAPD_USE_SASL to disable"
+ else
+ echo "Using proxyAuthz with simple authc..."
+ fi
+else
+ echo "SASL not available; using proxyAuthz with simple authc..."
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $IDASSERTCONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFIDASSERT1 -n 1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd -n 1 failed ($RC)!"
+ exit $RC
+fi
+$SLAPADD -f $ADDCONF -l $LDIFIDASSERT2 -n 2
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd -n 2 failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT..."
+. $CONFFILTER $BACKEND < $IDASSERTCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+echo "Testing ldapwhoami as proxy US..."
+$LDAPWHOAMI -H $URI1 -D "cn=proxy US,ou=Admin,dc=example,dc=com" -w proxy
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+AUTHZID="u:it/jaj"
+echo "Testing ldapwhoami as proxy US, $AUTHZID..."
+$LDAPWHOAMI -H $URI1 -D "cn=proxy US,ou=Admin,dc=example,dc=com" -w proxy -e\!"authzid=$AUTHZID"
+RC=$?
+if test $RC != 0 && test $BACKEND != null ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+AUTHZID="u:bjorn"
+echo "Testing ldapwhoami as proxy US, $AUTHZID... (should fail)"
+$LDAPWHOAMI -H $URI1 -D "cn=proxy US,ou=Admin,dc=example,dc=com" -w proxy -e\!"authzid=$AUTHZID"
+RC=$?
+if test $RC != 1 ; then
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+AUTHZID="u:bjensen"
+echo "Testing ldapwhoami as proxy US, $AUTHZID... (should fail)"
+$LDAPWHOAMI -H $URI1 -D "cn=proxy US,ou=Admin,dc=example,dc=com" -w proxy -e\!"authzid=$AUTHZID"
+RC=$?
+if test $RC != 1 ; then
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing ldapwhoami as proxy IT..."
+$LDAPWHOAMI -H $URI1 -D "cn=proxy IT,ou=Admin,dc=example,dc=com" -w proxy
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+AUTHZID="u:it/jaj"
+echo "Testing ldapwhoami as proxy IT, $AUTHZID... (should fail)"
+$LDAPWHOAMI -H $URI1 -D "cn=proxy IT,ou=Admin,dc=example,dc=com" -w proxy -e\!"authzid=$AUTHZID"
+RC=$?
+if test $RC != 1 ; then
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+AUTHZID="u:bjorn"
+echo "Testing ldapwhoami as proxy IT, $AUTHZID... (should fail)"
+$LDAPWHOAMI -H $URI1 -D "cn=proxy IT,ou=Admin,dc=example,dc=com" -w proxy -e\!"authzid=$AUTHZID"
+RC=$?
+if test $RC != 1 ; then
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+AUTHZID="dn:cn=Sandbox,ou=Admin,dc=example,dc=com"
+echo "Testing ldapwhoami as proxy IT, $AUTHZID..."
+$LDAPWHOAMI -H $URI1 -D "cn=proxy IT,ou=Admin,dc=example,dc=com" -w proxy -e\!"authzid=$AUTHZID"
+RC=$?
+if test $RC != 0 && test $BACKEND != null ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+AUTHZID="dn:uid=bjorn,ou=People,o=Example,c=US"
+echo "Testing ldapwhoami as bjorn, $AUTHZID..."
+$LDAPWHOAMI -H $URI1 -D "uid=bjorn,ou=people,dc=example,dc=com" -w bjorn -e\!"authzid=$AUTHZID"
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+AUTHZID="dn:uid=bjorn,ou=People,o=Esempio,c=IT"
+echo "Testing ldapwhoami as bjorn, $AUTHZID..."
+$LDAPWHOAMI -H $URI1 -D "uid=bjorn,ou=people,dc=example,dc=com" -w bjorn -e\!"authzid=$AUTHZID"
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+AUTHZID="u:it/jaj"
+echo "Checking another DB's rootdn can't assert identity from another DB..."
+$LDAPWHOAMI -H $URI1 -D "$MANAGERDN" -w $PASSWD -e\!"authzid=$AUTHZID"
+
+RC=$?
+if test $RC != 1 ; then
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+ID="uid=jaj,ou=People,dc=example,dc=it"
+BASE="o=Example,c=US"
+echo "Testing ldapsearch as $ID for \"$BASE\"..."
+$LDAPSEARCH -H $URI1 -b "$BASE" \
+ -D "$ID" -w jaj > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 && test $BACKEND != null ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER -s ldif=e < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER -s ldif=e < $IDASSERTOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - search with identity assertion didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+if test $USE_SASL != "no" ; then
+ ID="it/jaj"
+ BASE="o=Example,c=US"
+ echo "Testing ldapsearch as $ID for \"$BASE\" with SASL bind and identity assertion..."
+ $LDAPSASLSEARCH -H $URI1 -b "$BASE" \
+ -Q -U "$ID" -w jaj -Y $MECH > $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ ID="manager"
+ AUTHZID="u:it/jaj"
+ echo "Checking another DB's rootdn can't assert in another (with SASL bind this time)..."
+ $LDAPSASLWHOAMI -H $URI1 \
+ -Q -U "$ID" -w $PASSWD -Y $MECH -X $AUTHZID
+
+ RC=$?
+ if test $RC != 50 ; then
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ echo "Filtering ldapsearch results..."
+ $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+ echo "Filtering original ldif used to create database..."
+ $LDIFFILTER < $IDASSERTOUT > $LDIFFLT
+ echo "Comparing filter output..."
+ $CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+ if test $? != 0 ; then
+ echo "comparison failed - search with SASL bind and identity assertion didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test029-ldapglue b/tests/scripts/test029-ldapglue
new file mode 100755
index 0000000..f0ad581
--- /dev/null
+++ b/tests/scripts/test029-ldapglue
@@ -0,0 +1,224 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+echo "### This test requires the ldap backend and glue overlay."
+echo "### If available, and explicitly requested, it can use SASL bind;"
+echo "### note that SASL must be properly set up, and the requested"
+echo "### mechanism must be available. Define SLAPD_USE_SASL={yes|<mech>},"
+echo "### with \"yes\" defaulting to DIGEST-MD5 to enable SASL authc[/authz]."
+
+if test $BACKLDAP = "ldapno" ; then
+ echo "LDAP backend not available, test skipped"
+ exit 0
+fi
+
+if test $WITH_SASL = "yes" ; then
+ if test $USE_SASL != "no" ; then
+ if test $USE_SASL = "yes" ; then
+ MECH="DIGEST-MD5"
+ else
+ MECH="$USE_SASL"
+ fi
+ echo "Using SASL authc[/authz] with mech=$MECH; unset SLAPD_USE_SASL to disable"
+ else
+ echo "Using proxyAuthz with simple authc..."
+ fi
+else
+ echo "SASL not available; using proxyAuthz with simple authc..."
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2 $DBDIR3
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $LDAPGLUECONF1 > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFLDAPGLUE1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd 1 failed ($RC)!"
+ exit $RC
+fi
+
+. $CONFFILTER $BACKEND < $LDAPGLUECONF2 > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFLDAPGLUE2
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd 2 failed ($RC)!"
+ exit $RC
+fi
+
+. $CONFFILTER $BACKEND < $LDAPGLUECONF3 > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFLDAPGLUE3
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd 3 failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting local slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $LDAPGLUECONF1 > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID1=$!
+if test $WAIT != 0 ; then
+ echo PID $PID1
+ read foo
+fi
+
+echo "Starting remote slapd 1 on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $LDAPGLUECONF2 > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID2=$!
+if test $WAIT != 0 ; then
+ echo PID $PID2
+ read foo
+fi
+
+echo "Starting remote slapd 2 on TCP/IP port $PORT3..."
+. $CONFFILTER $BACKEND < $LDAPGLUECONF3 > $CONF3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID3=$!
+if test $WAIT != 0 ; then
+ echo PID $PID3
+ read foo
+fi
+KILLPIDS="$PID1 $PID2 $PID3"
+
+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 "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+echo "Using ldapsearch to check that slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+echo "Using ldapsearch to check that slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI3 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+ID="uid=bjorn,ou=People,dc=example,dc=com"
+BASE="dc=example,dc=com"
+echo "Testing ldapsearch as $ID for \"$BASE\"..."
+$LDAPSEARCH -H $URI1 -b "$BASE" \
+ -D "$ID" -w bjorn > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER -s ldif=e < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER -s ldif=e < $LDAPGLUEOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - glued search with identity assertion didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+BASE="dc=example,dc=com"
+echo "Testing ldapsearch as anonymous for \"$BASE\"..."
+$LDAPSEARCH -H $URI1 -b "$BASE" \
+ > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDAPGLUEANONYMOUSOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - anonymous glued search with identity assertion didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+# FIXME: this cannot work as is, because SASL bind cannot be proxied!
+if test $USE_SASL != "no" ; then
+ ID="bjorn"
+ BASE="dc=example,dc=com"
+ echo "Testing ldapsearch as $ID for \"$BASE\" with SASL bind and identity assertion..."
+ $LDAPSASLSEARCH -H $URI1 -b "$BASE" \
+ -Q -U "$ID" -w bjorn -Y $MECH > $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Filtering ldapsearch results..."
+ $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+ echo "Filtering original ldif used to create database..."
+ $LDIFFILTER < $LDAPGLUEOUT > $LDIFFLT
+ echo "Comparing filter output..."
+ $CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+ if test $? != 0 ; then
+ echo "comparison failed - glued search with SASL bind and identity assertion didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test030-relay b/tests/scripts/test030-relay
new file mode 100755
index 0000000..1ce5250
--- /dev/null
+++ b/tests/scripts/test030-relay
@@ -0,0 +1,98 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $RWM = rwmno ; then
+ echo "rwm (Rewrite/remap) overlay not available, test skipped"
+ exit 0
+fi
+
+echo ""
+
+if test "x$RELAYS" = "x" ; then
+ RELAYS=
+ # back-relay
+ if test $BACKRELAY = relayno ; then
+ echo "relay backend not available, test skipped"
+ else
+ if test "x$RELAYS" != "x" ; then
+ RELAYS="${RELAYS} "
+ fi
+ RELAYS="${RELAYS}relay"
+ fi
+
+ # back-ldap
+ if test $BACKLDAP = ldapno ; then
+ echo "ldap backend not available, test skipped"
+ else
+ if test "x$RELAYS" != "x" ; then
+ RELAYS="${RELAYS} "
+ fi
+ RELAYS="${RELAYS}ldap"
+ fi
+
+ # back-meta
+ if test $BACKMETA = metano ; then
+ echo "meta backend not available, test skipped"
+ else
+ if test "x$RELAYS" != "x" ; then
+ RELAYS="${RELAYS} "
+ fi
+ RELAYS="${RELAYS}meta"
+ fi
+fi
+
+if test "x$RELAYS" = "x" ; then
+ echo "no relaying capable backend is available"
+ echo ">>>>> Test succeeded"
+ exit 0
+fi
+
+echo "Testing virtual naming context mapping with $RELAYS backend(s)..."
+echo ""
+
+tmpfile=savelog.log
+if test -f $tmpfile ; then
+ rm -f $tmpfile
+fi
+first=1
+for RELAY in $RELAYS ; do
+ if test $first = 1 ; then
+ first=0
+ else
+ echo ">>>>> waiting for things to exit"
+ test $KILLSERVERS != no && wait
+ echo ""
+
+ mv -f $LOG1 $tmpfile
+ rm -rf $TESTDIR
+ fi
+
+ mkdir -p $TESTDIR $DBDIR1
+
+ if test -f $tmpfile ; then
+ mv $tmpfile $LOG1
+ fi
+
+ . $SRCDIR/scripts/relay
+done
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test031-component-filter b/tests/scripts/test031-component-filter
new file mode 100755
index 0000000..b289054
--- /dev/null
+++ b/tests/scripts/test031-component-filter
@@ -0,0 +1,330 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 you use this script then
+## Make sure that you turn on LDAP_COMP_MATCH in slapd source codes
+## and --enable-modules is configured yes
+if test "$AC_WITH_MODULES_ENABLED" != "yes" ; then
+ echo "dynamic module disabled, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+## Make sure that you set a proper path to component matching
+## module directory in $COMPCONF
+## moduleload path/to/component/library/compmatch.la
+## otherwise it fails to execute slapd
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $COMPCONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFCOMPMATCH
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ echo "Be sure to have a certificate module in tests/data/comp_libs "
+ echo "The module is in openldap/contrib/slapd-modules/comp_match"
+ echo "Test skipped."
+ exit 0
+fi
+
+echo "Running slapindex to index slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPINDEX -f $CONF1
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $ADDCONF -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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
+
+cat /dev/null > $SEARCHOUT
+
+echo "Testing Component Filter Match RFC3687 Certificate searching:"
+echo "# Testing Component Filter Match RFC3687 Certificate searching:" >> $SEARCHOUT
+
+FILTER="(userCertificate:componentFilterMatch:=item:{ component \"toBeSigned.serialNumber\", rule allComponentsMatch, value 0 })"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(userCertificate:componentFilterMatch:=item:{ component \"toBeSigned.version\", rule allComponentsMatch, value 2 })"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(userCertificate:componentFilterMatch:=item:{ component \"toBeSigned.issuer.rdnSequence.1.1.value\", rule caseExactMatch, value \"US\" })"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(userCertificate:componentFilterMatch:=item:{ component \"toBeSigned.issuer.rdnSequence.1.1.value\", rule allComponentsMatch, value \"US\" })"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(userCertificate:componentFilterMatch:=item:{ component \"toBeSigned.issuer.rdnSequence\", rule allComponentsMatch, value { { { type 2.5.4.6 , value \"US\" } } } })"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(userCertificate:componentFilterMatch:=item:{ component \"toBeSigned.extensions.0\", rule integerMatch, value 3 })"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(userCertificate:componentFilterMatch:=item:{ component \"toBeSigned.extensions.\2a.extnID\", rule allComponentsMatch, value 2.5.29.14 })"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(userCertificate:componentFilterMatch:=not:item:{ component \"toBeSigned.extensions.\2a\", rule allComponentsMatch, value { extnID 2.5.29.19 , extnValue '30030101FF'H })"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(userCertificate:componentFilterMatch:=item:{ component \"toBeSigned.issuer.rdnSequence\", rule distinguishedNameMatch, value \"c=US\" })"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(userCertificate:componentFilterMatch:=item:{ component \"toBeSigned.issuer.rdnSequence.1\", rule rdnMatch, value \"c=US\" })"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(userCertificate:componentFilterMatch:=item:{ component \"toBeSigned.extensions.\2a.extnValue.content.\282.5.29.35\29.authorityCertSerialNumber\", rule integerMatch, value 0 })"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+
+FILTER="(userCertificate:componentFilterMatch:=item:{ component \"toBeSigned.subject.rdnSequence.\2a\", rule rdnMatch, value \"c=US\" })"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(userCertificate:componentFilterMatch:=item:{ component \"toBeSigned.subject.rdnSequence.\2a.\2a.value.\282.5.4.6\29\", rule caseExactMatch, value \"US\" })"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# extraction filter
+FILTER="(x509CertificateIssuer=c=US)"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# extraction filter
+FILTER="(x509CertificateSerial=0)"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# extraction filter
+FILTER="(x509CertificateSerialAndIssuer:certificateExactMatch:=0\$c=US)"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+FILTER="(certificateRevocationList:componentFilterMatch:=item:{ component \"tbsCertList.revokedCertificates.\2a.userCertificate\", rule integerMatch, value 952069669 })"
+echo " f=$FILTER ..."
+echo "# f=$FILTER ..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ "$FILTER" >> $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $COMPSEARCHOUT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test032-chain b/tests/scripts/test032-chain
new file mode 100755
index 0000000..3da9a24
--- /dev/null
+++ b/tests/scripts/test032-chain
@@ -0,0 +1,340 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $BACKLDAP = "ldapno" ; then
+ echo "LDAP backend not available, test skipped"
+ exit 0
+fi
+
+rm -rf $TESTDIR
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CHAINCONF1 > $ADDCONF
+. $CONFFILTER < $LDIFCHAIN1 > $SEARCHOUT
+$SLAPADD -f $ADDCONF -l $SEARCHOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd 1 failed ($RC)!"
+ exit $RC
+fi
+
+. $CONFFILTER $BACKEND < $CHAINCONF2 > $ADDCONF
+. $CONFFILTER < $LDIFCHAIN2 > $SEARCHOUT
+$SLAPADD -f $ADDCONF -l $SEARCHOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd 2 failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting first slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $CHAINCONF1 > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID1=$!
+if test $WAIT != 0 ; then
+ echo PID $PID1
+ read foo
+fi
+KILLPIDS="$PID1"
+
+echo "Starting second slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $CHAINCONF2 > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID2=$!
+if test $WAIT != 0 ; then
+ echo PID $PID2
+ read foo
+fi
+
+KILLPIDS="$KILLPIDS $PID2"
+
+sleep 1
+
+echo "Using ldapsearch to check that first slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Using ldapsearch to check that second slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '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
+
+for n in 1 2 ; do
+ URI=`eval echo '$URI'$n`
+ echo "Testing ldapsearch as anonymous for \"$BASEDN\" on server $n..."
+ $LDAPSEARCH -H $URI -b "$BASEDN" -S "" \
+ > $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Filtering ldapsearch results..."
+ $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+ echo "Filtering original ldif used to create database..."
+ $LDIFFILTER < $CHAINOUT > $LDIFFLT
+ echo "Comparing filter output..."
+ $CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+ if test $? != 0 ; then
+ echo "comparison failed - chained search didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ echo "Reading the referral entry \"ou=Other,$BASEDN\" as anonymous on server $n..."
+ $LDAPSEARCH -H $URI -b "ou=Other,$BASEDN" -S "" \
+ > $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Filtering ldapsearch results..."
+ $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+ echo "Filtering original ldif used to create database..."
+ $LDIFFILTER < $CHAINREFOUT > $LDIFFLT
+ echo "Comparing filter output..."
+ $CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+ if test $? != 0 ; then
+ echo "comparison failed - chained search didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ DN="cn=Mark Elliot,ou=Alumni Association,ou=People,$BASEDN"
+ echo "Comparing \"$DN\" on server $n..."
+ $LDAPCOMPARE -H $URI "$DN" "cn:Mark Elliot" \
+ > $TESTOUT 2>&1
+
+ RC=$?
+ if test $RC != 6 && test $RC,$BACKEND != 5,null ; then
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ DN="ou=Other,$BASEDN"
+ echo "Comparing \"$DN\" on server $n with manageDSAit control..."
+ $LDAPCOMPARE -H $URI -M "$DN" "ou:Other" \
+ > $TESTOUT 2>&1
+
+ RC=$?
+ if test $RC != 6 && test $RC,$BACKEND != 5,null ; then
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+done
+
+#
+# Testing writes to first server
+#
+echo "Writing to first server with scope on second server..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=New Group,ou=Groups,dc=example,dc=com
+changetype: add
+objectClass: groupOfNames
+cn: New Group
+member:
+
+dn: cn=New Group,ou=Groups,dc=example,dc=com
+changetype: modify
+add: description
+description: testing chain overlay writes...
+-
+replace: member
+member: cn=New Group,ou=Groups,dc=example,dc=com
+member: cn=Manager,dc=example,dc=com
+-
+add: owner
+owner: cn=Manager,dc=example,dc=com
+-
+
+dn: cn=New Group,ou=Groups,dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Renamed Group
+deleteoldrdn: 1
+
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: delete
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#
+# Testing writes to second server
+#
+echo "Writing to second server with scope on first server..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=New User,ou=People,dc=example,dc=com
+changetype: add
+objectClass: person
+cn: New User
+sn: User
+seeAlso: cn=New Group,ou=Groups,dc=example,dc=com
+
+dn: cn=New User,ou=People,dc=example,dc=com
+changetype: modify
+add: description
+description: testing chain overlay writes...
+-
+replace: seeAlso
+seeAlso: cn=Renamed Group,ou=Groups,dc=example,dc=com
+-
+
+dn: cn=New User,ou=People,dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Renamed User
+deleteoldrdn: 1
+
+dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com
+changetype: delete
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+for n in 1 2 ; do
+ URI=`eval echo '$URI'$n`
+ echo "Testing ldapsearch as anonymous for \"$BASEDN\" on server $n..."
+ $LDAPSEARCH -H $URI -b "$BASEDN" -S "" \
+ > $SEARCHOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Filtering ldapsearch results..."
+ $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+ echo "Filtering original ldif used to create database..."
+ $LDIFFILTER < $CHAINMODOUT > $LDIFFLT
+ echo "Comparing filter output..."
+ $CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+ if test $? != 0 ; then
+ echo "comparison failed - chained search didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+done
+
+NEWPW=newsecret
+echo "Using ldappasswd on second server with scope on first server..."
+$LDAPPASSWD -H $URI2 \
+ -w secret -s $NEWPW \
+ -D "$MANAGERDN" "$BJORNSDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Binding with newly changed password on first server..."
+$LDAPWHOAMI -H $URI1 \
+ -D "$BJORNSDN" -w $NEWPW
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# ITS#57??
+$LDAPADD -H $URI1 \
+ -D "$MANAGERDN" -w secret \
+ >> $TESTOUT 2>&1 \
+ << EOMODS
+dn: ou=Can't Contact,dc=example,dc=com
+changetype: add
+objectclass: referral
+objectclass: extensibleobject
+ou: Can't Contact
+# invalid URI to test broken connectivity handling (search only)
+ref: ${URI3}ou=Can't%20Contact,dc=example,dc=com
+EOMODS
+
+echo "Reading the referral entry \"ou=Can't Contact,$BASEDN\" as anonymous on port $PORT1..."
+$LDAPSEARCH -H $URI1 -b "$BASEDN" -S "" "(cn=Can't Contact)" \
+ > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test033-glue-syncrepl b/tests/scripts/test033-glue-syncrepl
new file mode 100755
index 0000000..0becc30
--- /dev/null
+++ b/tests/scripts/test033-glue-syncrepl
@@ -0,0 +1,189 @@
+#! /bin/sh
+# $OpenLDAP$ */
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1A $DBDIR1B $DBDIR1C $DBDIR2A $DBDIR2B
+
+echo "Running slapadd to build glued slapd databases..."
+. $CONFFILTER $BACKEND < $GLUECONF > $CONF1
+$SLAPADD -d $LVL -f $CONF1 -l $LDIFORDERED > $SLAPADDLOG1 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+rm -rf $DBDIR1A/* $DBDIR1B/*
+cp -pr $DBDIR1C $DBDIR2C
+
+echo "Starting slapd 1 on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $GLUESYNCCONF1 > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that slapd 1 is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+echo "Starting slapd 2 on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $GLUESYNCCONF2 > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that slapd 2 is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '(objectclass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+SUBTREE1="ou=Information Technology Division,ou=People,dc=example,dc=com"
+SUBTREE2="ou=Groups,dc=example,dc=com"
+
+echo "Using ldapadd to populate subtree=\"${SUBTREE1}\" on port $PORT1..."
+$LDAPADD -D "cn=Manager 1,$BASEDN" -w $PASSWD -H $URI1 \
+ -f $LDIFORDERED -c \
+ > /dev/null 2>&1
+RC=$?
+case $RC in
+0)
+ echo "ldapadd should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+10|68)
+ # Fine if we get alreadyExists or referrals
+ ;;
+*)
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Using ldapadd to populate subtree=\"${SUBTREE2}\" on port $PORT2..."
+$LDAPADD -D "cn=Manager 2,$BASEDN" -w $PASSWD -H $URI2 \
+ -f $LDIFORDERED -c \
+ > /dev/null 2>&1
+RC=$?
+case $RC in
+0)
+ echo "ldapadd should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+10|68)
+ # Fine if we get alreadyExists or referrals
+ ;;
+*)
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Waiting $SLEEP1 seconds for shadow subtrees to sync..."
+sleep $SLEEP1
+
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $GLUESYNCOUT > $LDIFFLT
+
+for n in 1 2 ; do
+ URI=`eval echo '$URI'$n`
+ echo "Using ldapsearch to read all the entries from server $n..."
+ $LDAPSEARCH -b "$BASEDN" -H $URI \
+ -S "" '(objectclass=*)' > "${SEARCHOUT}.${n}" 2>&1
+ RC=$?
+
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Filtering ldapsearch results..."
+ $LDIFFILTER < "${SEARCHOUT}.${n}" > $SEARCHFLT
+ echo "Comparing filter output..."
+ $CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+ if test $? != 0 ; then
+ echo "comparison failed - database was not created correctly"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+done
+
+echo "Testing ldapdelete propagation..."
+$LDAPDELETE -D "cn=Manager 1,$BASEDN" -w $PASSWD -H $URI1 "$BABSDN" \
+ > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapdelete failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# This usually propagates immediately
+sleep $SLEEP1
+
+$LDAPSEARCH -H $URI2 -b "$BABSDN" > $TESTOUT 2>&1
+RC=$?
+if test $RC = 0 && test $BACKEND != null ; then
+ echo "ldapsearch should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test034-translucent b/tests/scripts/test034-translucent
new file mode 100755
index 0000000..8b834d9
--- /dev/null
+++ b/tests/scripts/test034-translucent
@@ -0,0 +1,807 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2004-2022 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
+
+PERSONAL="(objectClass=inetOrgPerson)"
+NOWHERE="/dev/null"
+FAILURE="additional info:"
+
+if test $TRANSLUCENT = translucentno ; then
+ echo "Translucent Proxy overlay not available, test skipped"
+ exit 0
+fi
+
+if test $AC_ldap = ldapno ; then
+ echo "Translucent Proxy overlay requires back-ldap backend, test skipped"
+ exit 0
+fi
+
+# configure backside
+mkdir -p $TESTDIR $DBDIR1
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+DBIX=2
+
+. $CONFFILTER $BACKEND < $TRANSLUCENTREMOTECONF > $CONF1
+echo "Running slapadd to build remote slapd database..."
+$SLAPADD -f $CONF1 -l $LDIFTRANSLUCENTCONFIG
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting remote slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+REMOTEPID="$PID"
+KILLPIDS="$PID"
+
+sleep 1
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for remote slapd to start..."
+ sleep 5
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# configure frontside
+mkdir -p $DBDIR2
+
+. $CONFFILTER $BACKEND < $TRANSLUCENTLOCALCONF > $CONF2
+
+echo "Starting local slapd on TCP/IP port $PORT2..."
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+LOCALPID="$PID"
+KILLPIDS="$LOCALPID $REMOTEPID"
+
+sleep 1
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for local 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 "Testing slapd Translucent Proxy operations..."
+
+echo "Testing search: no remote data defined..."
+
+$LDAPSEARCH -H $URI2 -b "$TRANSLUCENTUSER" "$PERSONAL" >$SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+if test -s $SEARCHOUT; then
+ echo "ldapsearch should have returned no records!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Populating remote database..."
+
+$LDAPADD -D "$TRANSLUCENTROOT" -H $URI1 \
+ -w $PASSWD < $LDIFTRANSLUCENTDATA > $NOWHERE 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing search: remote database via local slapd..."
+
+$LDAPSEARCH -H $URI2 -b "$TRANSLUCENTUSER" "$PERSONAL" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+$LDIFFILTER < $LDIFTRANSLUCENTDATA > $LDIFFLT
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed -- corruption from remote to local!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing add: prohibited local record..."
+
+$LDAPADD -D "$TRANSLUCENTDN" -H $URI2 \
+ -w $TRANSLUCENTPASSWD < $LDIFTRANSLUCENTADD > $TESTOUT 2>&1
+
+RC=$?
+if test $RC != 50 ; then
+ echo "ldapadd failed ($RC), expected INSUFFICIENT ACCESS!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing add: valid local record, no_glue..."
+
+$LDAPADD -v -v -v -D "$TRANSLUCENTROOT" -H $URI2 \
+ -w $PASSWD < $LDIFTRANSLUCENTADD > $TESTOUT 2>&1
+
+RC=$?
+if test $RC != 32 && test $RC,$BACKEND != 0,null ; then
+ echo "ldapadd failed ($RC), expected NO SUCH OBJECT!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing modrdn: valid local record, no_glue..."
+
+$LDAPMODRDN -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 'uid=fred,ou=users,o=translucent' 'uid=someguy'
+
+RC=$?
+if test $RC != 32 && test $RC,$BACKEND != 0,null ; then
+ echo "ldapmodrdn failed ($RC), expected NO SUCH OBJECT!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Dynamically configuring local slapd without translucent_no_glue..."
+
+$LDAPMODIFY -D cn=config -H $URI2 -y $CONFIGPWF <<EOF
+dn: olcOverlay={0}translucent,olcDatabase={$DBIX}$BACKEND,cn=config
+changetype: modify
+replace: olcTranslucentNoGlue
+olcTranslucentNoGlue: FALSE
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify of dynamic config failed ($RC)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing add: valid local record..."
+
+$LDAPADD -D "$TRANSLUCENTROOT" -H $URI2 \
+ -w $PASSWD < $LDIFTRANSLUCENTADD > $TESTOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing search: data merging..."
+
+$LDAPSEARCH -H $URI2 -b "$TRANSLUCENTUSER" "$PERSONAL" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+$LDIFFILTER < $LDIFTRANSLUCENTMERGED > $LDIFFLT
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed -- local data failed to merge with remote!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing compare: valid local..."
+
+$LDAPCOMPARE -z -H $URI2 -w $TRANSLUCENTPASSWD -D $TRANSLUCENTDN \
+ "uid=danger,ou=users,o=translucent" "carLicense:LIVID"
+
+RC=$?
+if test $RC != 6 ; then
+ echo "ldapcompare failed ($RC), expected TRUE!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing compare: valid remote..."
+
+$LDAPCOMPARE -z -x -H $URI2 -w $TRANSLUCENTPASSWD -D $TRANSLUCENTDN \
+ "uid=binder,o=translucent" "businessCategory:binder-test-user"
+
+RC=$?
+if test $RC != 6 ; then
+ echo "ldapcompare failed ($RC), expected TRUE!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing compare: bogus local..."
+
+$LDAPCOMPARE -z -x -H $URI2 -w $TRANSLUCENTPASSWD -D $TRANSLUCENTDN \
+ "uid=danger,ou=users,o=translucent" "businessCategory:invalid-test-value"
+
+RC=$?
+if test $RC != 5 ; then
+ echo "ldapcompare failed ($RC), expected FALSE!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing compare: bogus remote..."
+
+$LDAPCOMPARE -z -x -H $URI2 -w $TRANSLUCENTPASSWD -D $TRANSLUCENTDN \
+ "uid=binder,o=translucent" "businessCategory:invalid-test-value"
+
+RC=$?
+if test $RC != 5 ; then
+ echo "ldapcompare failed ($RC), expected FALSE!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing modify: nonexistent record..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD
+version: 1
+dn: uid=bogus,ou=users,o=translucent
+changetype: modify
+replace: roomNumber
+roomNumber: 31J-2112
+EOF_MOD
+
+RC=$?
+if test $RC != 32 ; then
+ echo "ldapmodify failed ($RC), expected NO SUCH OBJECT!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing modify: valid local record, nonexistent attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD1
+version: 1
+dn: uid=danger,ou=users,o=translucent
+changetype: modify
+replace: roomNumber
+roomNumber: 9N-21
+EOF_MOD1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -H $URI2 -b "uid=danger,ou=users,o=translucent" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ATTR=`grep roomNumber $SEARCHOUT` > $NOWHERE 2>&1
+if test "$ATTR" != "roomNumber: 9N-21" ; then
+ echo "modification failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing search: specific nonexistent remote attribute..."
+
+$LDAPSEARCH -H $URI2 -b "uid=danger,ou=users,o=translucent" roomNumber > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing modify: nonexistent local record, nonexistent attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD2
+version: 1
+dn: uid=fred,ou=users,o=translucent
+changetype: modify
+replace: roomNumber
+roomNumber: 31J-2112
+EOF_MOD2
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -H $URI2 -b "uid=fred,ou=users,o=translucent" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ATTR=`grep roomNumber $SEARCHOUT` > $NOWHERE 2>&1
+if test "$ATTR" != "roomNumber: 31J-2112" ; then
+ echo "modification failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing modify: valid remote record, nonexistent attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD9
+version: 1
+dn: uid=fred,ou=users,o=translucent
+changetype: modify
+delete: preferredLanguage
+EOF_MOD9
+
+RC=$?
+if test $RC != 16 ; then
+ echo "ldapmodify failed ($RC), expected NO SUCH ATTRIBUTE!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing delete: valid local record, nonexistent attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD4
+version: 1
+dn: uid=fred,ou=users,o=translucent
+changetype: modify
+delete: roomNumber
+EOF_MOD4
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing modrdn: prohibited local record..."
+
+$LDAPMODRDN -D "$TRANSLUCENTDN" -H $URI2 -w $TRANSLUCENTPASSWD > \
+ $TESTOUT 2>&1 'uid=fred,ou=users,o=translucent' 'uid=someguy'
+
+RC=$?
+if test $RC != 50 ; then
+ echo "ldapmodrdn failed ($RC), expected INSUFFICIENT ACCESS!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing modrdn: valid local record..."
+
+$LDAPMODRDN -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 'uid=fred,ou=users,o=translucent' 'uid=someguy'
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodrdn failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing delete: prohibited local record..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTDN" -H $URI2 -w $TRANSLUCENTPASSWD > \
+ $TESTOUT 2>&1 << EOF_DEL2
+version: 1
+dn: uid=someguy,ou=users,o=translucent
+changetype: delete
+EOF_DEL2
+
+RC=$?
+if test $RC != 50 ; then
+ echo "ldapadd failed ($RC), expected INSUFFICIENT ACCESS!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing delete: valid local record..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_DEL3
+version: 1
+dn: uid=someguy,ou=users,o=translucent
+changetype: delete
+EOF_DEL3
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing delete: valid remote record..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_DEL8
+version: 1
+dn: uid=fred,ou=users,o=translucent
+changetype: delete
+EOF_DEL8
+
+RC=$?
+if test $RC != 32 ; then
+ echo "ldapmodify failed ($RC), expected NO SUCH OBJECT!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing delete: nonexistent local record, nonexistent attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_DEL1
+version: 1
+dn: uid=fred,ou=users,o=translucent
+changetype: modify
+delete: roomNumber
+EOF_DEL1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -H $URI2 -b "uid=fred,ou=users,o=translucent" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing delete: valid local record, nonexistent attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD8
+version: 1
+dn: uid=danger,ou=users,o=translucent
+changetype: modify
+delete: preferredLanguage
+EOF_MOD8
+
+RC=$?
+if test $RC != 16 ; then
+ echo "ldapmodify failed ($RC), expected NO SUCH ATTRIBUTE!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing delete: valid local record, remote attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD8
+version: 1
+dn: uid=danger,ou=users,o=translucent
+changetype: modify
+delete: initials
+EOF_MOD8
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing modify: valid remote record, combination add-modify-delete..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD6
+version: 1
+dn: uid=fred,ou=users,o=translucent
+changetype: modify
+delete: carLicense
+-
+add: preferredLanguage
+preferredLanguage: ISO8859-1
+-
+replace: employeeType
+employeeType: consultant
+EOF_MOD6
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -H $URI2 -b "uid=fred,ou=users,o=translucent" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ATTR=`grep employeeType $SEARCHOUT` > $NOWHERE 2>&1
+if test "$ATTR" != "employeeType: consultant" ; then
+ echo "modification failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+ATTR=`grep preferredLanguage $SEARCHOUT` > $NOWHERE 2>&1
+if test "$ATTR" != "preferredLanguage: ISO8859-1" ; then
+ echo "modification failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Dynamically configuring local slapd with translucent_no_glue and translucent_strict..."
+
+$LDAPMODIFY -D cn=config -H $URI2 -y $CONFIGPWF <<EOF
+dn: olcOverlay={0}translucent,olcDatabase={$DBIX}$BACKEND,cn=config
+changetype: modify
+replace: olcTranslucentNoGlue
+olcTranslucentNoGlue: TRUE
+-
+replace: olcTranslucentStrict
+olcTranslucentStrict: TRUE
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify of dynamic config failed ($RC)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing strict mode delete: nonexistent local attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD5
+version: 1
+dn: uid=example,ou=users,o=translucent
+changetype: modify
+delete: preferredLanguage
+EOF_MOD5
+
+RC=$?
+if test $RC != 19 ; then
+ echo "ldapmodify failed ($RC), expected CONSTRAINT VIOLATION!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing strict mode delete: nonexistent remote attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD3
+version: 1
+dn: uid=danger,ou=users,o=translucent
+changetype: modify
+delete: displayName
+EOF_MOD3
+
+RC=$?
+if test $RC != 19 ; then
+ echo "ldapmodify failed ($RC), expected CONSTRAINT VIOLATION!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing strict mode modify: combination add-modify-delete..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD6
+version: 1
+dn: uid=example,ou=users,o=translucent
+changetype: modify
+delete: carLicense
+-
+add: preferredLanguage
+preferredLanguage: ISO8859-1
+-
+replace: employeeType
+employeeType: consultant
+EOF_MOD6
+
+RC=$?
+if test $RC != 19 ; then
+ echo "ldapmodify failed ($RC), expected CONSTRAINT VIOLATION!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing invalid Bind request..."
+$LDAPWHOAMI -D "$TRANSLUCENTDN" -H $URI2 -w Wrong"$TRANSLUCENTPASSWD" > \
+ $TESTOUT 2>&1
+RC=$?
+if test $RC != 49 ; then
+ echo "ldapwhoami failed ($RC), expected INVALID CREDENTIALS!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+$LDAPWHOAMI -D "$TRANSLUCENTDN" -H $URI2 -w "$TRANSLUCENTPASSWD" > \
+ $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC), expected SUCCESS!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing search: unconfigured local filter..."
+$LDAPSEARCH -H $URI2 -b "o=translucent" "(employeeType=consultant)" > $SEARCHOUT 2>&1
+
+ATTR=`grep dn: $SEARCHOUT` > $NOWHERE 2>&1
+if test -n "$ATTR" ; then
+ echo "got result $ATTR, should have been no result"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Dynamically configuring local slapd with translucent_local..."
+
+$LDAPMODIFY -D cn=config -H $URI2 -y $CONFIGPWF <<EOF
+dn: olcOverlay={0}translucent,olcDatabase={$DBIX}$BACKEND,cn=config
+changetype: modify
+add: olcTranslucentLocal
+olcTranslucentLocal: employeeType
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify of dynamic config failed ($RC)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing search: configured local filter..."
+$LDAPSEARCH -H $URI2 -b "o=translucent" "(employeeType=consultant)" > $SEARCHOUT 2>&1
+
+ATTR=`grep dn: $SEARCHOUT` > $NOWHERE 2>&1
+if test -z "$ATTR" ; then
+ echo "got no result, should have found entry"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+$LDAPSEARCH -H $URI2 -b "o=translucent" "(employeeType=consult*)" > $SEARCHOUT 2>&1
+ATTR=`grep dn: $SEARCHOUT` > $NOWHERE 2>&1
+if test -z "$ATTR" ; then
+ echo "got no result, should have found entry"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing search: unconfigured remote filter..."
+$LDAPSEARCH -H $URI2 -b "o=translucent" "(|(employeeType=foo)(carlicense=right))" > $SEARCHOUT 2>&1
+
+ATTR=`grep dn: $SEARCHOUT` > $NOWHERE 2>&1
+if test -n "$ATTR" ; then
+ echo "got result $ATTR, should have been no result"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Dynamically configuring local slapd with translucent_remote..."
+
+$LDAPMODIFY -D cn=config -H $URI2 -y $CONFIGPWF <<EOF
+dn: olcOverlay={0}translucent,olcDatabase={$DBIX}$BACKEND,cn=config
+changetype: modify
+add: olcTranslucentRemote
+olcTranslucentRemote: carLicense
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify of dynamic config failed ($RC)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing search: configured remote filter..."
+$LDAPSEARCH -H $URI2 -b "o=translucent" "(|(employeeType=foo)(carlicense=right))" > $SEARCHOUT 2>&1
+
+ATTR=`grep dn: $SEARCHOUT` > $NOWHERE 2>&1
+if test -z "$ATTR" ; then
+ echo "got no result, should have found entry"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test035-meta b/tests/scripts/test035-meta
new file mode 100755
index 0000000..44f72e3
--- /dev/null
+++ b/tests/scripts/test035-meta
@@ -0,0 +1,739 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+echo ""
+
+if test $BACKMETA = metano ; then
+ echo "meta backend not available, test skipped"
+ exit 0
+fi
+
+if test $BACKLDAP = ldapno ; then
+ echo "ldap backend not available, test skipped"
+ exit 0
+fi
+
+rm -rf $TESTDIR
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $METACONF1 > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ '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 "Using ldapadd to populate the database..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDERED > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $METACONF2 > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+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 "$MONITOR" -H $URI2 \
+ '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 "Using ldapadd to populate the database..."
+$LDAPADD -D "$METAMANAGERDN" -H $URI2 -w $PASSWD < \
+ $LDIFMETA >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT3..."
+. $CONFFILTER $BACKEND < $METACONF > $CONF3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+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 "$MONITOR" -H $URI3 \
+ '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
+
+cat /dev/null > $SEARCHOUT
+
+BASEDN="o=Example,c=US"
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+# ITS#4195: spurious matchedDN when the search scopes the main target,
+# and the searchBase is not present, so that target returns noSuchObject
+BASEDN="ou=Meta,o=Example,c=US"
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+#
+# Do some modifications
+#
+
+BASEDN="o=Example,c=US"
+echo "Modifying database \"$BASEDN\"..."
+$LDAPMODIFY -v -D "cn=Manager,$BASEDN" -H $URI3 -w $PASSWD \
+ -M >> $TESTOUT 2>&1 << EOMODS
+# These operations (updates with objectClass mapping) triggered ITS#3499
+dn: cn=Added Group,ou=Groups,$BASEDN
+changetype: add
+objectClass: groupOfNames
+objectClass: uidObject
+cn: Added Group
+member: cn=Added Group,ou=Groups,$BASEDN
+uid: added
+
+dn: cn=Another Added Group,ou=Groups,$BASEDN
+changetype: add
+objectClass: groupOfNames
+cn: Another Added Group
+member: cn=Added Group,ou=Groups,$BASEDN
+member: cn=Another Added Group,ou=Groups,$BASEDN
+
+dn: cn=Another Added Group,ou=Groups,$BASEDN
+changetype: modify
+add: objectClass
+objectClass: uidObject
+-
+add: uid
+uid: added
+-
+
+dn: cn=Added Group,ou=Groups,$BASEDN
+changetype: modify
+delete: objectClass
+objectClass: uidObject
+-
+delete: uid
+-
+
+dn: ou=Meta,$BASEDN
+changetype: modify
+add: description
+description: added to "ou=Meta,$BASEDN"
+-
+
+dn: ou=Who's going to handle this?,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Who's going to handle this?
+description: added
+description: will be deleted
+
+dn: ou=Same as above,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Same as above
+description: added right after "Who's going to handle this?"
+description: will be preserved
+
+dn: ou=Who's going to handle this?,$BASEDN
+changetype: delete
+
+dn: ou=Who's going to handle this?,ou=Meta,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Who's going to handle this?
+description: added
+description: will be deleted
+
+dn: ou=Same as above,ou=Meta,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Same as above
+description: added right after "Who's going to handle this?"
+description: will be preserved
+
+dn: cn=Added User,ou=Same as above,ou=Meta,$BASEDN
+changetype: add
+objectClass: inetOrgPerson
+cn: Added User
+sn: User
+userPassword: secret
+
+dn: ou=Who's going to handle this?,ou=Meta,$BASEDN
+changetype: delete
+EOMODS
+
+RC=$?
+#if test $RC != 0 ; then
+# echo "Modify failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Modify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+BASEDN="o=Example,c=US"
+echo " base=\"$BASEDN\"..."
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" -M "$FILTER" '*' ref \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+BASEDN="o=Example,c=US"
+FILTER="(seeAlso=cn=all staff,ou=Groups,$BASEDN)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"seeAlso\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"seeAlso\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" "$FILTER" seeAlso \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+FILTER="(uid=example)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"uid\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"uid\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" "$FILTER" uid \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+FILTER="(member=cn=Another Added Group,ou=Groups,$BASEDN)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"member\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"member\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" "$FILTER" member \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Waiting 10 seconds for cached connections to timeout..."
+sleep 10
+
+echo "Searching with a timed out connection..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"member\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"" >> $SEARCHOUT
+echo "# with a timed out connection..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -D "cn=Manager,$BASEDN" -w $PASSWD \
+ -b "$BASEDN" "$FILTER" member \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+# NOTE: cannot send to $SEARCHOUT because the returned entries
+# are not predictable...
+echo "Checking server-enforced size limit..."
+echo "# Checking server-enforced size limit..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 \
+ -D "cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN" -w bjorn \
+ -b "$BASEDN" "(objectClass=*)" 1.1 \
+ >> $TESTOUT 2>&1
+RC=$?
+case $RC,$BACKEND in
+ 4,* | 0,null)
+ ;;
+ 0,*)
+ echo "Search should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+# NOTE: cannot send to $SEARCHOUT because the returned entries
+# are not predictable...
+echo "Checking client-requested size limit..."
+echo "# Checking client-requested size limit..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 \
+ -D "cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN" -w bjorn \
+ -b "$BASEDN" -z 2 "(objectClass=*)" 1.1 \
+ >> $TESTOUT 2>&1
+RC=$?
+case $RC,$BACKEND in
+ 4,* | 0,null)
+ ;;
+ 0,*)
+ echo "Search should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $METAOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - meta search/modification didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+BASEDN="o=Example,c=US"
+echo "Changing password to database \"$BASEDN\"..."
+$LDAPPASSWD -H $URI3 -D "cn=Manager,$BASEDN" -w $PASSWD \
+ -s $PASSWD "cn=Ursula Hampster,ou=Alumni Association,ou=People,$BASEDN" \
+ >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Passwd ExOp failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Passwd ExOp failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Binding with newly changed password to database \"$BASEDN\"..."
+$LDAPWHOAMI -H $URI3 \
+ -D "cn=Ursula Hampster,ou=Alumni Association,ou=People,$BASEDN" \
+ -w $PASSWD >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "WhoAmI failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ echo "WhoAmI failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Binding as newly added user to database \"$BASEDN\"..."
+$LDAPWHOAMI -H $URI3 \
+ -D "cn=Added User,ou=Same as above,ou=Meta,$BASEDN" \
+ -w $PASSWD >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "WhoAmI failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ echo "WhoAmI failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Changing password to database \"$BASEDN\"..."
+$LDAPPASSWD -H $URI3 -D "cn=Manager,$BASEDN" -w $PASSWD \
+ -s meta "cn=Added User,ou=Same as above,ou=Meta,$BASEDN" \
+ >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Passwd ExOp failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Passwd ExOp failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Binding with newly changed password to database \"$BASEDN\"..."
+$LDAPWHOAMI -H $URI3 \
+ -D "cn=Added User,ou=Same as above,ou=Meta,$BASEDN" \
+ -w meta >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "WhoAmI failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ echo "WhoAmI failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Binding with incorrect password to database \"$BASEDN\"..."
+$LDAPWHOAMI -H $URI3 \
+ -D "cn=Added User,ou=Same as above,ou=Meta,$BASEDN" \
+ -w bogus >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "WhoAmI failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC,$BACKEND in
+ 0,null)
+ ;;
+ 0,*)
+ echo "WhoAmI should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ 51,*)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ ;;
+esac
+
+echo "Binding with non-existing user to database \"$BASEDN\"..."
+$LDAPWHOAMI -H $URI3 \
+ -D "cn=Non-existing User,ou=Same as above,ou=Meta,$BASEDN" \
+ -w bogus >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "WhoAmI failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC,$BACKEND in
+ 0,null)
+ ;;
+ 0,*)
+ echo "WhoAmI should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ 51,*)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ ;;
+esac
+
+echo "Comparing to database \"$BASEDN\"..."
+$LDAPCOMPARE -H $URI3 \
+ "cn=Another Added Group,ou=Groups,$BASEDN" \
+ "member:cn=Added Group,ou=Groups,$BASEDN" >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 6 ; then
+# echo "Compare failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit 1
+#fi
+case $RC,$BACKEND in
+ 6,* | 5,null)
+ ;;
+ 51,*)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ echo "Compare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+esac
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test036-meta-concurrency b/tests/scripts/test036-meta-concurrency
new file mode 100755
index 0000000..46f5cfb
--- /dev/null
+++ b/tests/scripts/test036-meta-concurrency
@@ -0,0 +1,225 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+echo ""
+
+if test $BACKMETA = metano ; then
+ echo "meta backend not available, test skipped"
+ exit 0
+fi
+
+if test $BACKLDAP = ldapno ; then
+ echo "ldap backend not available, test skipped"
+ exit 0
+fi
+
+if test x$TESTLOOPS = x ; then
+ TESTLOOPS=50
+fi
+
+if test x$TESTCHILDREN = x ; then
+ TESTCHILDREN=20
+fi
+
+rm -rf $TESTDIR
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $METACONF1 > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ '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 "Using ldapadd to populate the database..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDERED > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $METACONF2 > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+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 "$MONITOR" -H $URI2 \
+ '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 "Using ldapadd to populate the database..."
+$LDAPADD -D "$METAMANAGERDN" -H $URI2 -w $PASSWD < \
+ $LDIFMETA >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT3..."
+. $CONFFILTER $BACKEND < $METACONF > $CONF3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+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 "$MONITOR" -H $URI3 \
+ '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
+
+cat /dev/null > $SEARCHOUT
+
+mkdir -p $TESTDIR/$DATADIR
+METABASEDN="o=Example,c=US"
+for f in $DATADIR/do_* ; do
+ sed -e "s;$BASEDN;$METABASEDN;" $f > $TESTDIR/$f
+done
+
+# add a read that matches only the local database, but selects
+# also the remote as candidate; this should be removed to compare
+# execution times with test008...
+for f in $TESTDIR/$DATADIR/do_read.* ; do
+ echo "ou=Meta,$METABASEDN" >> $f
+done
+
+# add a read that matches a referral in the local database only,
+# but selects also the remote as candidate; this should be removed
+# to compare execution times with test008...
+for f in $TESTDIR/$DATADIR/do_read.* ; do
+ echo "cn=Somewhere,ou=Meta,$METABASEDN" >> $f
+done
+
+# add a bind that resolves to a referral
+for f in $TESTDIR/$DATADIR/do_bind.* ; do
+ echo "cn=Foo,ou=Meta,$METABASEDN" >> $f
+ echo "bar" >> $f
+ echo "" >> $f
+ echo "" >> $f
+done
+
+# NOTE: copies do_* files from $TESTDIR/$DATADIR to $TESTDIR
+$MONITORDATA "$TESTDIR/$DATADIR" "$TESTDIR"
+
+BINDDN="cn=Manager,o=Local"
+PASSWD="secret"
+echo "Using tester for concurrent server access..."
+$SLAPDTESTER -P "$PROGDIR" -d "$TESTDIR" -H $URI3 \
+ -D "$BINDDN" -w $PASSWD -l $TESTLOOPS -j $TESTCHILDREN \
+ -r 20 -i '!REFERRAL' -i '*INVALID_CREDENTIALS' -SS
+RC=$?
+
+if test $RC != 0 ; then
+ echo "slapd-tester failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to retrieve all the entries..."
+$LDAPSEARCH -S "" -b "$METABASEDN" -H $URI3 \
+ 'objectClass=*' > $SEARCHOUT 2>&1
+RC=$?
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $METACONCURRENCYOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - slapd-meta search/modification didn't succeed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test037-manage b/tests/scripts/test037-manage
new file mode 100755
index 0000000..9587593
--- /dev/null
+++ b/tests/scripts/test037-manage
@@ -0,0 +1,219 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $BACKEND = "ldif" ; then
+ echo "LDIF backend does not support relax control, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd Manage operations..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Testing modify, add, and delete..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ -e \!relax > \
+ $TESTOUT 2>&1 << EOMODS
+version: 1
+#
+# Working Tests
+#
+
+#
+# ObjectClass tests
+#
+
+dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,
+ dc=com
+# add obsolete auxiliary objectclass
+changetype: modify
+add: objectClass
+objectClass: obsoletePerson
+
+dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,
+ dc=com
+# add obsolete attribute
+changetype: modify
+add: testObsolete
+testObsolete: TRUE
+
+#
+# create/modify timestamp test
+#
+
+dn: ou=Groups,dc=example,dc=com
+# change creatorsName
+changetype: modify
+replace: creatorsName
+creatorsName: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com
+
+dn: cn=ITD Staff,ou=Groups,dc=example,dc=com
+# change modifiersName
+changetype: modify
+replace: modifiersName
+modifiersName: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com
+
+dn: dc=example,dc=com
+# change timestamps
+changetype: modify
+replace: modifyTimestamp
+modifyTimestamp: 19700101000000Z
+-
+replace: createTimestamp
+createTimestamp: 19700101000000Z
+-
+
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+# change entryUUID
+changetype: modify
+replace: entryUUID
+entryUUID: badbadba-dbad-1029-92f7-badbadbadbad
+
+dn: cn=All Staff,dc=example,dc=com
+changetype: add
+objectClass: groupOfNames
+cn: All Staff
+member:
+creatorsName: cn=Someone
+createTimestamp: 19700101000000Z
+modifiersName: cn=Someone Else
+modifyTimestamp: 19700101000000Z
+entryUUID: badbadef-dbad-1029-92f7-badbadbadbad
+
+#
+# Tests that did not work until ITS#5792
+#
+
+dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,
+ dc=com
+# update structural object class of entry via objectClass replace
+changetype: modify
+replace: objectClass
+objectClass: obsoletePerson
+objectClass: testPerson
+-
+
+dn: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com
+# update structural object class of entry via objectClass add
+changetype: modify
+add: objectClass
+objectClass: testPerson
+-
+
+dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com
+# update structural object class of entry via objectClass delete/add
+changetype: modify
+delete: objectClass
+objectClass: OpenLDAPperson
+-
+add: objectClass
+objectClass: testPerson
+-
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to retrieve all the entries..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ 'objectClass=*' '*' creatorsName modifiersName > $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+$LDAPSEARCH -S "" -b "$BASEDN" -s base -H $URI1 \
+ 'objectClass=*' '*' creatorsName createTimestamp \
+ modifiersName modifyTimestamp >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(cn=All Staff)' '*' entryUUID >> $SEARCHOUT 2>&1
+RC=$?
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+LDIF=$MANAGEOUT
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - manage operations did not complete correctly"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test038-retcode b/tests/scripts/test038-retcode
new file mode 100755
index 0000000..1e0ecb2
--- /dev/null
+++ b/tests/scripts/test038-retcode
@@ -0,0 +1,112 @@
+#! /bin/sh
+# $Header$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $RETCODE = retcodeno; then
+ echo "Retcode overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $MCONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+. $CONFFILTER $BACKEND < $RETCODECONF > $CONF1
+$SLAPINDEX -f $CONF1
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(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 "Testing search for timelimitExceeded..."
+$LDAPSEARCH -b "cn=timelimitExceeded,ou=RetCodes,$BASEDN" \
+ -H $URI1 '(objectClass=*)' >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 3 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing modify for unwillingToPerform..."
+$LDAPMODIFY -D "$MANAGERDN" -w $PASSWD \
+ -H $URI1 >> $TESTOUT 2>&1 << EOMODS
+dn: cn=unwillingToPerform,ou=RetCodes,$BASEDN
+changetype: delete
+EOMODS
+RC=$?
+if test $RC != 53 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing compare for success after sleep (2 s)..."
+$LDAPCOMPARE -H $URI1 \
+ "cn=Success w/ Delay,ou=RetCodes,$BASEDN" "cn:foo" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test039-glue-ldap-concurrency b/tests/scripts/test039-glue-ldap-concurrency
new file mode 100755
index 0000000..5b5580a
--- /dev/null
+++ b/tests/scripts/test039-glue-ldap-concurrency
@@ -0,0 +1,231 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+echo ""
+
+if test $BACKLDAP = ldapno ; then
+ echo "ldap backend not available, test skipped"
+ exit 0
+fi
+
+if test $RWM = rwmno ; then
+ echo "rwm (rewrite/remap) overlay not available, test skipped"
+ exit 0
+fi
+
+if test x$TESTLOOPS = x ; then
+ TESTLOOPS=50
+fi
+
+if test x$TESTOLOOPS = x ; then
+ TESTOLOOPS=1
+fi
+
+if test x$TESTCHILDREN = x ; then
+ TESTCHILDREN=20
+fi
+
+rm -rf $TESTDIR
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $METACONF1 > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ '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 "Using ldapadd to populate the database..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDERED > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $METACONF2 > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+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 "$MONITOR" -H $URI2 \
+ '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 "Using ldapadd to populate the database..."
+$LDAPADD -D "$METAMANAGERDN" -H $URI2 -w $PASSWD < \
+ $LDIFMETA >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT3..."
+. $CONFFILTER $BACKEND < $GLUELDAPCONF > $CONF3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+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 "$MONITOR" -H $URI3 \
+ '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
+
+cat /dev/null > $SEARCHOUT
+
+mkdir -p $TESTDIR/$DATADIR
+METABASEDN="o=Example,c=US"
+for f in $DATADIR/do_* ; do
+ sed -e "s;$BASEDN;$METABASEDN;" $f > $TESTDIR/$f
+done
+
+# add a read that matches only the local database, but selects
+# also the remote as candidate; this should be removed to compare
+# execution times with test008...
+for f in $TESTDIR/$DATADIR/do_read.* ; do
+ echo "ou=Meta,$METABASEDN" >> $f
+done
+
+# add a read that matches a referral in the local database only,
+# but selects also the remote as candidate; this should be removed
+# to compare execution times with test008...
+for f in $TESTDIR/$DATADIR/do_read.* ; do
+ echo "cn=Somewhere,ou=Meta,$METABASEDN" >> $f
+done
+
+# add a bind that resolves to a referral
+for f in $TESTDIR/$DATADIR/do_bind.* ; do
+ echo "cn=Foo,ou=Meta,$METABASEDN" >> $f
+ echo "bar" >> $f
+ echo "" >> $f
+ echo "" >> $f
+done
+
+# fix test data to include back-monitor, if available
+# NOTE: copies do_* files from $TESTDIR/$DATADIR to $TESTDIR
+$MONITORDATA "$TESTDIR/$DATADIR" "$TESTDIR"
+
+echo "Using tester for concurrent server access..."
+BINDDN="cn=Manager,o=Local"
+PASSWD="secret"
+$SLAPDTESTER -P "$PROGDIR" -d "$TESTDIR" -H $URI3 \
+ -D "$BINDDN" -w $PASSWD \
+ -l $TESTLOOPS -L $TESTOLOOPS -j $TESTCHILDREN -r 20 \
+ -i '!REFERRAL' -i '*INVALID_CREDENTIALS' -SS
+RC=$?
+
+if test $RC != 0 ; then
+ echo "slapd-tester failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to retrieve all the entries..."
+$LDAPSEARCH -S "" -b "$METABASEDN" -H $URI3 \
+ '(objectClass=*)' > $SEARCHOUT 2>&1
+RC=$?
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $METACONCURRENCYOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - slapd-ldap search/modification didn't succeed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test040-subtree-rename b/tests/scripts/test040-subtree-rename
new file mode 100755
index 0000000..9554da3
--- /dev/null
+++ b/tests/scripts/test040-subtree-rename
@@ -0,0 +1,209 @@
+#! /bin/sh
+# $OpenLDAP$ */
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $BACKEND = wt ; then
+ echo "back-wt does not support subtree rename"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(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
+
+cat /dev/null > $TESTOUT
+cat /dev/null > $SEARCHOUT
+
+# Add
+echo "Populating the database..."
+echo "# Populating the database..." >> $TESTOUT
+$LDAPADD -v -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOMODS0
+dn: dc=example,dc=com
+objectClass: organization
+objectClass: dcObject
+o: Example, Inc.
+dc: example
+
+dn: ou=Parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Parent
+
+dn: ou=Another parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Another parent
+
+dn: ou=Child,ou=Parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Child
+
+dn: ou=Grandchild,ou=Child,ou=Parent,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Grandchild
+EOMODS0
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Searching all database..."
+echo "# Searching all database (after add)..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Rename (PASS1)
+echo "Renaming (PASS1)..."
+echo "# Renaming (PASS1)..." >> $TESTOUT
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOMODS1
+dn: ou=Child,ou=Parent,dc=example,dc=com
+changetype: modrdn
+newrdn: ou=Renamed child
+deleteoldrdn: 0
+EOMODS1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Searching all database..."
+echo "# Searching all database (after PASS1)..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Rename (PASS2)
+echo "Renaming (PASS2)..."
+echo "# Renaming (PASS2)..." >> $TESTOUT
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOMODS2
+dn: ou=Parent,dc=example,dc=com
+changetype: modrdn
+newrdn: ou=Renamed parent
+deleteoldrdn: 0
+EOMODS2
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Searching all database..."
+echo "# Searching all database (after PASS2)..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Rename (PASS3)
+echo "Renaming (PASS3)..."
+echo "# Renaming (PASS3)..." >> $TESTOUT
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOMODS3
+dn: ou=Renamed child,ou=Renamed parent,dc=example,dc=com
+changetype: modrdn
+newrdn: ou=Renamed child
+deleteoldrdn: 0
+newsuperior: ou=Another parent,dc=example,dc=com
+EOMODS3
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Searching all database..."
+echo "# Searching all database (after PASS3)..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$SUBTREERENAMEOUT
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test041-aci b/tests/scripts/test041-aci
new file mode 100755
index 0000000..f3993b9
--- /dev/null
+++ b/tests/scripts/test041-aci
@@ -0,0 +1,258 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+case "$BACKEND" in ldif | null)
+ echo "$BACKEND backend does not support access controls, test skipped"
+ exit 0
+ ;;
+esac
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+if test "$ACI" = "acino" ; then
+ echo "ACI not enabled, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $ACICONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd ACI access control..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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
+
+cat /dev/null > $SEARCHOUT
+cat /dev/null > $TESTOUT
+
+# Search must fail
+BASEDN="dc=example,dc=com"
+echo "Searching \"$BASEDN\" (should fail)..."
+echo "# Searching \"$BASEDN\" (should fail)..." >> $SEARCHOUT
+$LDAPSEARCH -s base -b "$BASEDN" -H $URI1 \
+ '(objectclass=*)' >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 32 ; then
+ echo "ldapsearch should have failed with noSuchObject ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ if test $RC = 0 ; then
+ exit 1
+ fi
+ exit $RC
+fi
+
+# Bind must fail
+BINDDN="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjensen
+echo "Testing ldapwhoami as ${BINDDN} (should fail)..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW
+RC=$?
+if test $RC = 0 ; then
+ echo "ldapwhoami should have failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+# Populate ACIs
+echo "Writing ACIs as \"$MANAGERDN\"..."
+$LDAPMODIFY -D "$MANAGERDN" -w $PASSWD -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS0
+dn: dc=example,dc=com
+changetype: modify
+add: OpenLDAPaci
+OpenLDAPaci: 0#subtree#grant;d,c,s,r;[all]#group/groupOfUniqueNames/uniqueMe
+ mber#cn=ITD Staff,ou=Groups,dc=example,dc=com
+OpenLDAPaci: 1#entry#grant;d;[all]#public#
+
+dn: ou=People,dc=example,dc=com
+changetype: modify
+add: OpenLDAPaci
+OpenLDAPaci: 0#subtree#grant;x;userPassword#public#
+OpenLDAPaci: 1#subtree#grant;w;userPassword#self#
+OpenLDAPaci: 2#subtree#grant;w;userPassword#access-id#cn=Bjorn Jensen,ou=Inf
+ ormation Technology Division,ou=People,dc=example,dc=com
+
+dn: ou=Groups,dc=example,dc=com
+changetype: modify
+add: OpenLDAPaci
+OpenLDAPaci: 0#entry#grant;s;[all]#public#
+OpenLDAPaci: 1#children#grant;r;member;r;uniqueMember#access-id#cn=Bjorn Jen
+ sen,ou=Information Technology Division,ou=People,dc=example,dc=com
+EOMODS0
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Search must succeed with no results
+BASEDN="dc=example,dc=com"
+echo "Searching \"$BASEDN\" (should succeed with no results)..."
+echo "# Searching \"$BASEDN\" (should succeed with no results)..." >> $SEARCHOUT
+$LDAPSEARCH -s base -b "$BASEDN" -H $URI1 \
+ '(objectclass=*)' >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ ### TEMPORARY (see ITS#3963)
+ echo "ldapsearch failed ($RC)! IGNORED..."
+ ###echo "ldapsearch failed ($RC)!"
+ ###test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ ###exit $RC
+fi
+
+BINDDN="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjensen
+echo "Testing ldapwhoami as ${BINDDN}..."
+$LDAPWHOAMI -H $URI1 -D "$BINDDN" -w $BINDPW
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Search must succeed
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+BASEDN="dc=example,dc=com"
+echo "Searching \"$BASEDN\" as \"$BINDDN\" (should succeed)..."
+echo "# Searching \"$BASEDN\" as \"$BINDDN\" (should succeed)..." >> $SEARCHOUT
+$LDAPSEARCH -s base -b "$BASEDN" -H $URI1 \
+ -D "$BINDDN" -w "$BINDPW" \
+ '(objectClass=*)' >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Passwd must succeed
+BINDDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjorn
+TGT="cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc=com"
+NEWPW=jdoe
+echo "Setting \"$TGT\" password..."
+$LDAPPASSWD -H $URI1 \
+ -w "$BINDPW" -s "$NEWPW" \
+ -D "$BINDDN" "$TGT" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Re-change as self...
+echo "Changing self password..."
+BINDDN="$TGT"
+BINDPW=$NEWPW
+TGT="cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc=com"
+NEWPW=newcred
+$LDAPPASSWD -H $URI1 \
+ -w "$BINDPW" -s "$NEWPW" \
+ -D "$BINDDN" "$TGT" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldappasswd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Searching groups
+BINDPW=$NEWPW
+BASEDN="ou=Groups,dc=example,dc=com"
+echo "Searching \"$BASEDN\" as \"$BINDDN\" (should succeed)..."
+echo "# Searching \"$BASEDN\" as \"$BINDDN\" (should succeed)..." >> $SEARCHOUT
+$LDAPSEARCH -s one -b "$BASEDN" -H $URI1 \
+ -D "$BINDDN" -w "$BINDPW" \
+ '(objectClass=*)' >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Search must fail
+BINDDN="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
+BINDPW=bjensen
+echo "Searching \"$BASEDN\" as \"$BINDDN\" (should succeed with no results)..."
+echo "# Searching \"$BASEDN\" as \"$BINDDN\" (should succeed with no results)..." >> $SEARCHOUT
+$LDAPSEARCH -s one -b "$BASEDN" -H $URI1 \
+ -D "$BINDDN" -w "$BINDPW" \
+ '(objectClass=*)' >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$ACIOUT
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER -s mdb=e < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER -s mdb=e < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - operations did not complete correctly"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test042-valsort b/tests/scripts/test042-valsort
new file mode 100755
index 0000000..853381f
--- /dev/null
+++ b/tests/scripts/test042-valsort
@@ -0,0 +1,229 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2004-2022 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 $VALSORT = valsortno; then
+ echo "Valsort overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $VALSORTCONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFVALSORT
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd sorted values operations..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Testing ascending and weighted sort"
+
+FILTER="objectClass=*"
+$LDAPSEARCH -b "$VALSORTBASEDN" -H $URI1 \
+ "$FILTER" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering expected ldif..."
+$LDIFFILTER < $VALSORTOUT1 > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Reconfiguring slapd to test valsort descending"
+
+$LDAPMODIFY -x -D cn=config -H $URI1 -y $CONFIGPWF > \
+ $TESTOUT 2>&1 << EOMODS
+version: 1
+dn: olcOverlay={0}valsort,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+replace: olcValSortAttr
+olcValSortAttr: employeeType "ou=users,o=valsort" weighted alpha-descend
+olcValSortAttr: ou "ou=users,o=valsort" weighted
+olcValSortAttr: mailPreferenceOption "ou=users,o=valsort" numeric-descend
+olcValSortAttr: departmentNumber "ou=users,o=valsort" alpha-descend
+olcValSortAttr: sn "ou=users,o=valsort" alpha-descend
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing descending and weighted sort"
+
+$LDAPSEARCH -b "$VALSORTBASEDN" -H $URI1 \
+ "$FILTER" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering expected ldif..."
+$LDIFFILTER < $VALSORTOUT2 > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Adding a valsort record with weighted ou..."
+
+$LDAPADD -D "$VALSORTDN" -H $URI1 -w $PASSWD \
+ > /dev/null << EOTVALSORT1
+dn: uid=dave,ou=users,o=valsort
+objectClass: OpenLDAPperson
+uid: dave
+sn: nothere
+cn: dave
+businessCategory: otest
+carLicense: TEST
+departmentNumber: 42
+displayName: Dave
+employeeNumber: 69
+employeeType: {1}contractor
+givenName: Dave
+ou: {1}Test
+ou: {3}Okay
+ou: {2}Is
+EOTVALSORT1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo ----------------------
+#$LDAPSEARCH -b "o=valsort" -H $URI1
+
+echo "Adding a non-weighted valsort record with ou..."
+
+$LDAPADD -D "$VALSORTDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOTVALSORT2
+dn: uid=bill,ou=users,o=valsort
+objectClass: OpenLDAPperson
+uid: bill
+sn: johnson
+cn: bill
+businessCategory: rtest
+carLicense: ABC123
+departmentNumber: 42
+displayName: Bill
+employeeNumber: 5150
+employeeType: {1}contractor
+givenName: Bill
+ou: Test
+ou: Okay
+ou: Is
+EOTVALSORT2
+
+RC=$?
+if test $RC != 19 ; then
+ echo "valsort check failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+$LDAPSEARCH -b "$VALSORTBASEDN" -H $URI1 \
+ "$FILTER" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER -s ldif=e < $SEARCHOUT > $SEARCHFLT
+echo "Filtering expected ldif..."
+$LDIFFILTER -s ldif=e < $VALSORTOUT3 > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+test $KILLSERVERS != no && wait
+
+echo ">>>>> Test succeeded"
+
+exit 0
diff --git a/tests/scripts/test043-delta-syncrepl b/tests/scripts/test043-delta-syncrepl
new file mode 100755
index 0000000..0d30e72
--- /dev/null
+++ b/tests/scripts/test043-delta-syncrepl
@@ -0,0 +1,552 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+if test $ACCESSLOG = accesslogno; then
+ echo "Accesslog overlay not available, test skipped"
+ exit 0
+fi
+if test $BACKEND = ldif ; then
+ # Onelevel search does not return entries in order of creation or CSN.
+ echo "$BACKEND backend unsuitable for syncprov logdb, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1A $DBDIR1B $DBDIR2
+
+SPEC="mdb=a"
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+#
+# Test replication:
+# - start provider
+# - start consumer
+# - populate over ldap
+# - perform some modifies and deleted
+# - attempt to modify the consumer (referral or chain)
+# - retrieve database over ldap and compare against expected results
+#
+
+echo "Starting provider slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $DSRPROVIDERCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Using ldapadd to create the context prefix entries in the provider..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDEREDCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting consumer slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $DSRCONSUMERCONF > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '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 "Using ldapadd to populate the provider directory..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDEREDNOCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Stopping the provider, sleeping 10 seconds and restarting it..."
+kill -HUP "$PID"
+wait $PID
+sleep 10
+echo "RESTART" >> $LOG1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL >> $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Using ldapmodify to modify provider directory..."
+
+#
+# Do some modifications
+#
+
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+changetype: modify
+add: drink
+drink: Orange Juice
+-
+delete: sn
+sn: Jones
+-
+add: sn
+sn: Jones
+-
+add: displayName
+displayName: The one
+
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+changetype: modify
+add: displayName
+displayName: James the First
+-
+delete: displayName
+displayName: The one
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: drink
+drink: Iced Tea
+
+dn: cn=ITD Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: uniquemember
+uniquemember: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+uniquemember: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+-
+add: uniquemember
+uniquemember: cn=Dorothy Stevens, ou=Alumni Association, ou=People, dc=example,dc=com
+uniquemember: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: description
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+cn: Gern Jensen
+sn: Jensen
+uid: gjensen
+title: Chief Investigator, ITD
+postaladdress: ITD $ 535 W. William St $ Ann Arbor, MI 48103
+seealso: cn=All Staff, ou=Groups, dc=example,dc=com
+drink: Coffee
+homepostaladdress: 844 Brown St. Apt. 4 $ Ann Arbor, MI 48104
+description: Very odd
+facsimiletelephonenumber: +1 313 555 7557
+telephonenumber: +1 313 555 8343
+mail: gjensen@mailgw.example.com
+homephone: +1 313 555 8844
+
+dn: ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: organizationalUnit
+ou: Retired
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+cn: Rosco P. Coltrane
+sn: Coltrane
+uid: rosco
+description: Fat tycoon
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Rosco P. Coltrane
+deleteoldrdn: 1
+newsuperior: ou=Retired, ou=People, dc=example,dc=com
+
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: delete
+
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ 'objectclass=*' \* + > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ 'objectclass=*' \* + > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering provider results..."
+$LDIFFILTER -b $BACKEND -s $SPEC < $PROVIDEROUT | grep -iv "^auditcontext:" > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER -b $BACKEND -s $SPEC < $CONSUMEROUT | grep -iv "^auditcontext:" > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Stopping consumer to test recovery..."
+kill -HUP $CONSUMERPID
+wait $CONSUMERPID
+KILLPIDS="$PID"
+
+echo "Modifying more entries on the provider..."
+$LDAPMODIFY -v -D "$BJORNSDN" -H $URI1 -w bjorn >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Rosco P. Coltrane, ou=Retired, ou=People, dc=example,dc=com
+changetype: delete
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+add: drink
+drink: Mad Dog 20/20
+
+dn: cn=Rosco P. Coltrane, ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+sn: Coltrane
+uid: rosco
+cn: Rosco P. Coltrane
+
+dn: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com
+changetype: modify
+replace: drink
+drink: Red Wine
+-
+replace: drink
+
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Some Staff
+deleteoldrdn: 1
+
+EOMODS
+
+echo "Restarting consumer..."
+echo "RESTART" >> $LOG2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL >> $LOG2 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$PID $CONSUMERPID"
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+if test ! $BACKLDAP = "ldapno" ; then
+ echo "Try updating the consumer slapd..."
+ $LDAPMODIFY -v -D "$MANAGERDN" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example, dc=com
+changetype: modify
+add: description
+description: This write must fail because directed to a shadow context,
+description: unless the chain overlay is configured appropriately ;)
+
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+fi
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ 'objectclass=*' \* + > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ 'objectclass=*' \* + > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering provider results..."
+$LDIFFILTER -b $BACKEND -s $SPEC < $PROVIDEROUT | grep -iv "^auditcontext:" > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER -b $BACKEND -s $SPEC < $CONSUMEROUT | grep -iv "^auditcontext:" > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Stopping consumer to test recovery after logpurge expired..."
+kill -HUP $CONSUMERPID
+wait $CONSUMERPID
+KILLPIDS="$PID"
+
+echo "Modifying even more entries on the provider..."
+$LDAPMODIFY -v -D "$BJORNSDN" -H $URI1 -w bjorn >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com
+changetype: delete
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+add: drink
+drink: Sangria
+
+dn: cn=George D. Stevens, ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+sn: Stevens
+uid: gstevens
+cn: George D. Stevens
+
+dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,
+ dc=com
+changetype: modify
+replace: drink
+drink: cold water
+
+dn: cn=Some Staff,ou=Groups,dc=example,dc=com
+changetype: modrdn
+newrdn: cn=More Staff
+deleteoldrdn: 1
+
+EOMODS
+
+echo "Configuring logpurge of 1 second..."
+$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF >> \
+ $TESTOUT 2>&1 << EOMODS
+
+dn: olcOverlay={1}accesslog,olcDatabase={2}$BACKEND,cn=config
+changetype: modify
+replace: olcAccessLogPurge
+olcAccessLogPurge: 0+00:00:02 0+00:00:01
+-
+
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting 4 seconds for accesslog to be purged..."
+sleep 4
+
+echo "Using ldapsearch to check if accesslog is empty..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -b "cn=log" -H $URI1 -z 1 \
+ > $SEARCHOUT 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 3 seconds for accesslog to be purged..."
+ sleep 3
+done
+
+if test $RC != 0; then
+ echo "Accesslog did not purge in time"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+
+echo "Restarting consumer..."
+echo "RESTART" >> $LOG2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL >> $LOG2 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$PID $CONSUMERPID"
+
+echo "Waiting $SLEEP1 seconds for syncrepl to reschedule (ITS#9878) and poking it..."
+sleep $SLEEP1
+
+$LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+RC=$?
+
+if test $RC != 0; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ 'objectclass=*' \* + > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ 'objectclass=*' \* + > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo "Filtering provider results..."
+$LDIFFILTER -b $BACKEND -s $SPEC < $PROVIDEROUT | grep -iv "^auditcontext:" > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER -b $BACKEND -s $SPEC < $CONSUMEROUT | grep -iv "^auditcontext:" > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test044-dynlist b/tests/scripts/test044-dynlist
new file mode 100755
index 0000000..da70343
--- /dev/null
+++ b/tests/scripts/test044-dynlist
@@ -0,0 +1,1124 @@
+#! /bin/sh
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $DYNLIST = "dynlistno" ; then
+ echo "dynlist overlay not available, test skipped"
+ exit 0
+fi
+
+if test $BACKEND = ldif ; then
+ # dynlist+ldif fails because back-ldif lacks bi_op_compare()
+ echo "$BACKEND backend unsuitable for dynlist overlay, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+DBIX=2
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $DYNLISTCONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(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
+
+cat /dev/null > $SEARCHOUT
+
+LISTDN="ou=Dynamic Lists,$BASEDN"
+echo "Adding a dynamic list..."
+$LDAPADD -v -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ > $TESTOUT 2>&1 << EOMODS
+dn: $LISTDN
+objectClass: organizationalUnit
+ou: Dynamic Lists
+
+dn: cn=Dynamic List,$LISTDN
+objectClass: groupOfURLs
+cn: Dynamic List
+memberURL: ldap:///ou=People,${BASEDN}?cn,mail?sub?(objectClass=person)
+EOMODS
+
+echo "Testing list search of all attrs..."
+echo "# Testing list search of all attrs..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(cn=Dynamic List)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list search of a listed attr..."
+echo "# Testing list search of a listed attr..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(cn=Dynamic List)' mail \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list search of a non-listed attr..."
+echo "# Testing list search of a non-listed attr..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(cn=Dynamic List)' objectClass \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list search with (critical) manageDSAit..."
+echo "# Testing list search with (critical) manageDSAit..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 -MM \
+ '(cn=Dynamic List)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing filtered search with all attrs..."
+echo "# Testing filtered search with all attrs..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(mail=jdoe@woof.net)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing filtered search of a listed attr..."
+echo "# Testing filtered search of a listed attr..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(mail=jdoe@woof.net)' mail \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing filtered search of a non-listed attr..."
+echo "# Testing filtered search of a non-listed attr..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(mail=jdoe@woof.net)' objectClass \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing filtered search of a non-present attr..."
+echo "# Testing filtered search of a non-present attr..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(mail=nobody@nowhere)' objectClass \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list compare..."
+echo "# Testing list compare..." >> $SEARCHOUT
+$LDAPCOMPARE -H $URI1 \
+ "cn=Dynamic List,$LISTDN" "cn:Bjorn Jensen" \
+ >> $SEARCHOUT 2>&1
+RC=$?
+case $RC in
+5)
+ echo "ldapcompare returned FALSE ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+6)
+ echo "ldapcompare returned TRUE ($RC)"
+ ;;
+0)
+ echo "ldapcompare returned success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+echo "" >> $SEARCHOUT
+
+echo "Testing list compare (should return FALSE)..."
+echo "# Testing list compare (should return FALSE)..." >> $SEARCHOUT
+$LDAPCOMPARE -H $URI1 \
+ "cn=Dynamic List,$LISTDN" "cn:FALSE" \
+ >> $SEARCHOUT 2>&1
+RC=$?
+case $RC in
+5)
+ echo "ldapcompare returned FALSE ($RC)"
+ ;;
+6)
+ echo "ldapcompare returned TRUE ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+0)
+ echo "ldapcompare returned success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+echo "" >> $SEARCHOUT
+
+echo "Testing list compare (should return UNDEFINED)..."
+echo "# Testing list compare (should return UNDEFINED)..." >> $SEARCHOUT
+$LDAPCOMPARE -H $URI1 \
+ "cn=Dynamic List,$LISTDN" "dc:UNDEFINED" \
+ >> $SEARCHOUT 2>&1
+RC=$?
+case $RC in
+5)
+ echo "ldapcompare returned FALSE ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+6)
+ echo "ldapcompare returned TRUE ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+16|32)
+ echo "ldapcompare returned UNDEFINED ($RC)"
+ ;;
+0)
+ echo "ldapcompare returned success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapcompare failed ($RC)"
+ ;;
+esac
+echo "" >> $SEARCHOUT
+
+echo "Testing list compare with manageDSAit..."
+echo "# Testing list compare with manageDSAit..." >> $SEARCHOUT
+$LDAPCOMPARE -H $URI1 -MM \
+ "cn=Dynamic List,$LISTDN" "cn:Bjorn Jensen" \
+ >> $SEARCHOUT 2>&1
+RC=$?
+case $RC in
+5)
+ echo "ldapcompare returned FALSE ($RC)"
+ ;;
+6)
+ echo "ldapcompare returned TRUE ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+0)
+ echo "ldapcompare returned success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+echo "" >> $SEARCHOUT
+
+echo "Reconfiguring slapd..."
+$LDAPMODIFY -x -D cn=config -H $URI1 -y $CONFIGPWF > \
+ $TESTOUT 2>&1 << EOMODS
+version: 1
+dn: olcOverlay={0}dynlist,olcDatabase={$DBIX}$BACKEND,cn=config
+changetype: modify
+delete: olcDynListAttrSet
+olcDynListAttrSet: {0}
+-
+add: olcDynListAttrSet
+olcDynListAttrSet: groupOfURLs memberURL sn:cn mail
+-
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "==========================================================" >> $LOG1
+
+echo "Testing attribute mapping"
+
+echo "Testing list search of all (mapped) attrs..."
+echo "# Testing list search of all (mapped) attrs..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(cn=Dynamic List)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list search of a (mapped) listed attr..."
+echo "# Testing list search of a (mapped) listed attr..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(cn=Dynamic List)' sn \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list search of a (n unmapped) listed attr..."
+echo "# Testing list search of a (n unmapped) listed attr..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(cn=Dynamic List)' mail \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list compare (mapped attrs) ..."
+echo "# Testing list compare (mapped attrs) ..." >> $SEARCHOUT
+$LDAPCOMPARE -H $URI1 \
+ "cn=Dynamic List,$LISTDN" "sn:Bjorn Jensen" \
+ >> $SEARCHOUT 2>&1
+RC=$?
+case $RC in
+5)
+ echo "ldapcompare returned FALSE ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+6)
+ echo "ldapcompare returned TRUE ($RC)"
+ ;;
+0)
+ echo "ldapcompare returned success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+echo "" >> $SEARCHOUT
+
+echo "Testing list compare (mapped attrs; should return FALSE)..."
+echo "# Testing list compare (mapped attrs; should return FALSE)..." >> $SEARCHOUT
+$LDAPCOMPARE -H $URI1 \
+ "cn=Dynamic List,$LISTDN" "sn:FALSE" \
+ >> $SEARCHOUT 2>&1
+RC=$?
+case $RC in
+5)
+ echo "ldapcompare returned FALSE ($RC)"
+ ;;
+6)
+ echo "ldapcompare returned TRUE ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+0)
+ echo "ldapcompare returned success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+echo "" >> $SEARCHOUT
+
+echo "Reconfiguring slapd..."
+$LDAPMODIFY -x -D cn=config -H $URI1 -y $CONFIGPWF > \
+ $TESTOUT 2>&1 << EOMODS
+version: 1
+dn: olcOverlay={0}dynlist,olcDatabase={$DBIX}$BACKEND,cn=config
+changetype: modify
+delete: olcDynListAttrSet
+olcDynListAttrSet: {0}
+-
+add: olcDynListAttrSet
+olcDynListAttrSet: groupOfURLs memberURL member
+-
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "==========================================================" >> $LOG1
+
+echo "Adding a dynamic list..."
+$LDAPADD -v -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ > $TESTOUT 2>&1 << EOMODS
+dn: cn=Dynamic List of Members,$LISTDN
+objectClass: groupOfURLs
+cn: Dynamic List of Members
+memberURL: ldap:///ou=People,${BASEDN}??sub?(objectClass=person)
+EOMODS
+
+echo "Testing list search of all attrs..."
+echo "# Testing list search of all attrs..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(cn=Dynamic List of Members)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list search of a listed attr..."
+echo "# Testing list search of a listed attr..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(cn=Dynamic List of Members)' member \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list search of a non-listed attr..."
+echo "# Testing list search of a non-listed attr..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(cn=Dynamic List of Members)' objectClass \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list search with (critical) manageDSAit..."
+echo "# Testing list search with (critical) manageDSAit..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 -MM \
+ '(&(cn=Dynamic List of Members)(objectClass=groupOfURLs))' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+CMPDN="$BJORNSDN"
+echo "Testing list compare..."
+echo "# Testing list compare..." >> $SEARCHOUT
+$LDAPCOMPARE -H $URI1 \
+ "cn=Dynamic List of Members,$LISTDN" "member:$CMPDN" \
+ >> $SEARCHOUT 2>&1
+RC=$?
+case $RC in
+5)
+ echo "ldapcompare returned FALSE ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+6)
+ echo "ldapcompare returned TRUE ($RC)"
+ ;;
+0)
+ echo "ldapcompare returned success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+echo "" >> $SEARCHOUT
+
+CMPDN="$BADBJORNSDN"
+echo "Testing list compare (should return FALSE)..."
+echo "# Testing list compare... (should return FALSE)" >> $SEARCHOUT
+$LDAPCOMPARE -H $URI1 \
+ "cn=Dynamic List of Members,$LISTDN" "member:$CMPDN" \
+ >> $SEARCHOUT 2>&1
+RC=$?
+case $RC in
+5)
+ echo "ldapcompare returned FALSE ($RC)"
+ ;;
+6)
+ echo "ldapcompare returned TRUE ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+0)
+ echo "ldapcompare returned success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+echo "" >> $SEARCHOUT
+
+CMPDN="$BJORNSDN"
+echo "Testing list compare (should return FALSE)..."
+echo "# Testing list compare (should return FALSE)..." >> $SEARCHOUT
+$LDAPCOMPARE -H $URI1 \
+ "cn=Dynamic List of Members,$LISTDN" "member:cn=Foo Bar" \
+ >> $SEARCHOUT 2>&1
+RC=$?
+case $RC in
+5)
+ echo "ldapcompare returned FALSE ($RC)"
+ ;;
+6)
+ echo "ldapcompare returned TRUE ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+0)
+ echo "ldapcompare returned success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+echo "" >> $SEARCHOUT
+
+echo "Testing list compare with manageDSAit (should return UNDEFINED)..."
+echo "# Testing list compare with manageDSAit (should return UNDEFINED)..." >> $SEARCHOUT
+$LDAPCOMPARE -H $URI1 -MM \
+ "cn=Dynamic List,$LISTDN" "member:$CMPDN" \
+ >> $SEARCHOUT 2>&1
+RC=$?
+case $RC in
+5)
+ echo "ldapcompare returned FALSE ($RC)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+6)
+ echo "ldapcompare returned TRUE ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+16|32)
+ echo "ldapcompare returned UNDEFINED ($RC)"
+ ;;
+0)
+ echo "ldapcompare returned success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+echo "" >> $SEARCHOUT
+
+echo "==========================================================" >> $LOG1
+
+echo "Testing dgIdentity..."
+
+# Set ACL, require authentication to get list contents
+$LDAPMODIFY -x -D cn=config -H $URI1 -y $CONFIGPWF > \
+ $TESTOUT 2>&1 << EOMODS
+version: 1
+dn: olcDatabase={$DBIX}$BACKEND,cn=config
+changetype: modify
+add: olcAccess
+olcAccess: to dn.base="cn=Dynamic List of Members,$LISTDN" by * read
+olcAccess: to * by users read by * search
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list search without dgIdentity..."
+echo "# Testing list search without dgIdentity..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(cn=Dynamic List of Members)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ > $TESTOUT 2>&1 << EOMODS
+dn: cn=Dynamic List of Members,$LISTDN
+changetype: modify
+add: objectClass
+objectClass: dgIdentityAux
+-
+add: dgIdentity
+dgIdentity: $CMPDN
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list search with dgIdentity..."
+echo "# Testing list search with dgIdentity..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(cn=Dynamic List of Members)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing dgAuthz..."
+
+CMPDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN"
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ > $TESTOUT 2>&1 << EOMODS
+dn: cn=Dynamic List of Members,$LISTDN
+changetype: modify
+add: dgAuthz
+dgAuthz: dn:$BABSDN
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list search with dgIdentity and dgAuthz anonymously..."
+echo "# Testing list search with dgIdentity and dgAuthz anonymously..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ '(cn=Dynamic List of Members)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing list search with dgIdentity and dgAuthz as the authorized identity..."
+echo "# Testing list search with dgIdentity and dgAuthz as the authorized identity..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ '(cn=Dynamic List of Members)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Reconfiguring slapd..."
+$LDAPMODIFY -x -D cn=config -H $URI1 -y $CONFIGPWF > \
+ $TESTOUT 2>&1 << EOMODS
+version: 1
+dn: olcOverlay={0}dynlist,olcDatabase={$DBIX}$BACKEND,cn=config
+changetype: modify
+delete: olcDynListAttrSet
+olcDynListAttrSet: {0}
+-
+add: olcDynListAttrSet
+olcDynListAttrSet: groupOfURLs memberURL member+memberOf
+-
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "==========================================================" >> $LOG1
+
+echo "Testing memberOf functionality..."
+echo "# Testing memberOf functionality..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "ou=People,$BASEDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ '(cn=Mark Elliot)' '*' 'memberOf' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing filtered memberOf functionality..."
+echo "# Testing filtered memberOf functionality..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "ou=People,$BASEDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ "(&(memberOf=cn=Dynamic List of Members,ou=Dynamic Lists,$BASEDN)(cn=Mark Elliot))" '*' 'memberOf' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing filtered member functionality..."
+echo "# Testing filtered member functionality..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ "(member=cn=Jane Doe,ou=Alumni Association,ou=People,$BASEDN)" \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Reconfiguring slapd..."
+$LDAPMODIFY -x -D cn=config -H $URI1 -y $CONFIGPWF > \
+ $TESTOUT 2>&1 << EOMODS
+version: 1
+dn: olcOverlay={0}dynlist,olcDatabase={$DBIX}$BACKEND,cn=config
+changetype: modify
+delete: olcDynListAttrSet
+olcDynListAttrSet: {0}
+-
+add: olcDynListAttrSet
+olcDynListAttrSet: groupOfURLs memberURL member+memberOf@groupOfNames
+-
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "==========================================================" >> $LOG1
+
+echo "Testing static group memberOf functionality..."
+echo "# Testing static group memberOf functionality..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "ou=People,$BASEDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ '(cn=Mark Elliot)' '*' 'memberOf' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing static group member compare..."
+echo "# Testing static group member compare..." >> $SEARCHOUT
+$LDAPCOMPARE -H $URI1 \
+ "cn=all staff,ou=groups,$BASEDN" "member:cn=Mark Elliot,ou=Alumni Association,ou=People,$BASEDN" >> $SEARCHOUT
+RC=$?
+case $RC in
+5)
+ echo "ldapcompare returned FALSE ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+6)
+ echo "ldapcompare returned TRUE ($RC)"
+ ;;
+0)
+ echo "ldapcompare returned success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+echo "" >> $SEARCHOUT
+
+echo "Testing static group non-member compare (should return FALSE)..."
+echo "# Testing static group non-member compare (should return FALSE)..." >> $SEARCHOUT
+$LDAPCOMPARE -H $URI1 \
+ "cn=all staff,ou=groups,$BASEDN" "member:cn=Not A User,ou=Alumni Association,ou=People,$BASEDN" >> $SEARCHOUT
+RC=$?
+case $RC in
+5)
+ echo "ldapcompare returned FALSE ($RC)"
+ ;;
+6)
+ echo "ldapcompare returned TRUE ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+0)
+ echo "ldapcompare returned success ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+*)
+ echo "ldapcompare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+echo "" >> $SEARCHOUT
+
+echo "Reconfiguring slapd..."
+$LDAPMODIFY -x -D cn=config -H $URI1 -y $CONFIGPWF > \
+ $TESTOUT 2>&1 << EOMODS
+version: 1
+dn: olcOverlay={0}dynlist,olcDatabase={$DBIX}$BACKEND,cn=config
+changetype: modify
+delete: olcDynListAttrSet
+olcDynListAttrSet: {0}
+-
+add: olcDynListAttrSet
+olcDynListAttrSet: groupOfURLs memberURL member+memberOf*
+-
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "==========================================================" >> $LOG1
+
+echo "Adding a couple dynamic groups..."
+$LDAPADD -v -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ > $TESTOUT 2>&1 << EOMODS
+dn: cn=The Smiths,$LISTDN
+objectClass: groupOfURLs
+cn: The Smiths
+memberURL: ldap:///ou=People,${BASEDN}??sub?(sn=Smith)
+description: Smith family
+
+dn: cn=Meta Group,$LISTDN
+objectClass: groupOfURLs
+cn: Meta Group
+memberURL: ldap:///${LISTDN}??sub?(description=Smith%20family)
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing nested dynamic group functionality..."
+echo "# Testing nested dynamic group functionality..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ '(objectclass=*)' '*' 'memberOf' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -S "" -b "ou=People,$BASEDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ '(cn=Mark Elliot)' '*' 'memberOf' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Reconfiguring slapd..."
+$LDAPMODIFY -x -D cn=config -H $URI1 -y $CONFIGPWF > \
+ $TESTOUT 2>&1 << EOMODS
+version: 1
+dn: olcOverlay={0}dynlist,olcDatabase={$DBIX}$BACKEND,cn=config
+changetype: modify
+delete: olcDynListAttrSet
+olcDynListAttrSet: {0}
+-
+add: olcDynListAttrSet
+olcDynListAttrSet: groupOfURLs memberURL member+memberOf@groupOfNames*
+olcDynListAttrSet: labeledURIObject labeledURI uniqueMember+seeAlso@groupOfUniqueNames
+-
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "==========================================================" >> $LOG1
+
+echo "Adding a couple static groups..."
+$LDAPADD -v -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ > $TESTOUT 2>&1 << EOMODS
+dn: cn=The Jensens,ou=Groups,$BASEDN
+objectClass: groupOfnames
+cn: The Jensens
+member: cn=Bjorn Jensen,ou=Information Technology DivisioN,ou=People,$BASEDN
+member: cn=Barbara Jensen,ou=Information Technology DivisioN,ou=People,$BASEDN
+
+dn: cn=JJs,ou=Groups,$BASEDN
+objectClass: groupOfnames
+cn: JJs
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,$BASEDN
+member: cn=James A Jones 2,ou=Information Technology Division,ou=People,$BASEDN
+member: cn=The Jensens,ou=Groups,$BASEDN
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing nested static group functionality..."
+echo "# Testing nested static group functionality..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "ou=People,$BASEDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ '(sn=Jensen)' '*' 'memberOf' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding another nested group..."
+$LDAPADD -v -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ > $TESTOUT 2>&1 << EOMODS
+dn: cn=Bonus Group,ou=Groups,$BASEDN
+objectClass: groupOfnames
+cn: Bonus Group
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,$BASEDN
+member: cn=Meta Group,$LISTDN
+EOMODS
+
+$LDAPSEARCH -S "" -b "ou=People,$BASEDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ '(sn=Hampster)' '*' 'memberOf' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -S "" -b "ou=People,$BASEDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ '(sn=Doe)' '*' 'memberOf' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -S "" -b "ou=People,$BASEDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ '(sn=Smith)' '*' 'memberOf' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing filtered nested memberOf functionality..."
+echo "# Testing filtered nested memberOf functionality..." >> $SEARCHOUT
+
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ "(memberOf=cn=bonus group,ou=groups,$BASEDN)" '*' 'memberOf' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ "(&(uid=jjones)(memberOf=cn=jjs,ou=groups,$BASEDN))" 'uid' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing negated filtered memberOf functionality..."
+echo "# Testing negated filtered memberOf functionality..." >> $SEARCHOUT
+
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ "(&(objectClass=OpenLDAPperson)(!(memberOf=cn=Alumni Assoc Staff,ou=groups,$BASEDN)))" '*' 'memberOf' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing filtered nested member functionality..."
+echo "# Testing filtered nested member functionality..." >> $SEARCHOUT
+
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -D "$BABSDN" -w bjensen \
+ "(member=cn=Jennifer Smith,ou=Alumni Association,ou=People,$BASEDN)" '*' 'memberOf' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$DYNLISTOUT
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test045-syncreplication-proxied b/tests/scripts/test045-syncreplication-proxied
new file mode 100755
index 0000000..80c7019
--- /dev/null
+++ b/tests/scripts/test045-syncreplication-proxied
@@ -0,0 +1,867 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+
+# test now handles known issues
+#if test x"$PROXYSYNC" = x ; then
+# echo "Test disabled; set PROXYSYNC=yes to enable"
+# exit 0
+#fi
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+if test $BACKLDAP = ldapno; then
+ echo "LDAP backend not available, test skipped"
+ exit 0
+fi
+
+if test $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+#
+# Test replication:
+# - start provider
+# - start consumer
+# - populate over ldap
+# - perform some modifies and deleted
+# - attempt to modify the consumer (referral or chain)
+# - retrieve database over ldap and compare against expected results
+#
+
+echo "Starting provider slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $SRPROVIDERCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PROVIDERPID=$!
+if test $WAIT != 0 ; then
+ echo PROVIDERPID $PROVIDERPID
+ read foo
+fi
+KILLPIDS="$PROVIDERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(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 "Using ldapadd to create the context prefix entry in the provider..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDEREDCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting consumer slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $RCONSUMERCONF > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$PROVIDERPID $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '(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 "Starting proxy slapd on TCP/IP port $PORT3..."
+. $CONFFILTER $BACKEND < $PLSRCONSUMERCONF > $CONF3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PROXYPID=$!
+if test $WAIT != 0 ; then
+ echo PROXYPID $PROXYPID
+ read foo
+fi
+KILLPIDS="$PROVIDERPID $CONSUMERPID $PROXYPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that proxy slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI3 \
+ '(objectClass=*)' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 || test $RC = 53 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+case $RC in
+0 )
+ echo "ldapsearch should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+53)
+ ;;
+*)
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+CHECK=1
+echo "$CHECK > Using ldapadd to populate the provider directory..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDEREDNOCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# get provider contextCSN
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -s base '(objectClass=*)' contextCSN > "${PROVIDEROUT}.$CHECK" 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# check consumer contextCSN
+sleep 1
+for i in 1 2 3; do
+ $LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ -s base '(objectClass=*)' contextCSN > "${CONSUMEROUT}.$CHECK" 2>&1
+ RC=$?
+
+ if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ $CMP ${PROVIDEROUT}.$CHECK ${CONSUMEROUT}.$CHECK > $CMPOUT
+
+ if test $? = 0 ; then
+ break
+ fi
+
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+done
+
+#echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' > "${PROVIDEROUT}.$CHECK" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ '(objectClass=*)' > "${CONSUMEROUT}.$CHECK" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Filtering provider results..."
+$LDIFFILTER < "${PROVIDEROUT}.$CHECK" > $PROVIDERFLT
+#echo "Filtering consumer results..."
+$LDIFFILTER < "${CONSUMEROUT}.$CHECK" > $CONSUMERFLT
+
+echo "$CHECK < Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+CHECK=`expr $CHECK + 1`
+echo "$CHECK > Stopping the provider, sleeping $SLEEP2 seconds and restarting it..."
+kill -HUP "$PROVIDERPID"
+wait $PROVIDERPID
+sleep $SLEEP2
+
+echo "======================= RESTART =======================" >> $LOG1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL >> $LOG1 2>&1 &
+PROVIDERPID=$!
+if test $WAIT != 0 ; then
+ echo PROVIDERPID $PROVIDERPID
+ read foo
+fi
+KILLPIDS="$PROVIDERPID $CONSUMERPID $PROXYPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(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 "Using ldapmodify to modify provider directory..."
+
+#
+# Do some modifications
+#
+
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+changetype: modify
+add: drink
+drink: Orange Juice
+-
+delete: sn
+sn: Jones
+-
+add: sn
+sn: Jones
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: drink
+drink: Iced Tea
+
+dn: cn=ITD Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: uniquemember
+uniquemember: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+uniquemember: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+-
+add: uniquemember
+uniquemember: cn=Dorothy Stevens, ou=Alumni Association, ou=People, dc=example,dc=com
+uniquemember: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+
+dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc
+ =com
+changetype: modify
+delete: cn
+cn: Biiff Jensen
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+cn: Gern Jensen
+sn: Jensen
+uid: gjensen
+title: Chief Investigator, ITD
+postaladdress: ITD $ 535 W. William St $ Ann Arbor, MI 48103
+seealso: cn=All Staff, ou=Groups, dc=example,dc=com
+drink: Coffee
+homepostaladdress: 844 Brown St. Apt. 4 $ Ann Arbor, MI 48104
+description: Very odd
+facsimiletelephonenumber: +1 313 555 7557
+telephonenumber: +1 313 555 8343
+mail: gjensen@mailgw.example.com
+homephone: +1 313 555 8844
+
+dn: ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: organizationalUnit
+ou: Retired
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+cn: Rosco P. Coltrane
+sn: Coltrane
+uid: rosco
+description: Fat tycoon
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Rosco P. Coltrane
+deleteoldrdn: 1
+newsuperior: ou=Retired, ou=People, dc=example,dc=com
+
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: delete
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# get provider contextCSN
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -s base '(objectClass=*)' contextCSN > "${PROVIDEROUT}.$CHECK" 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# check consumer contextCSN
+for i in 1 2 3; do
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+
+ $LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ -s base '(objectClass=*)' contextCSN > "${CONSUMEROUT}.$CHECK" 2>&1
+ RC=$?
+
+ if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ $CMP ${PROVIDEROUT}.$CHECK ${CONSUMEROUT}.$CHECK > $CMPOUT
+
+ if test $? = 0 ; then
+ break
+ fi
+done
+
+#echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' > "${PROVIDEROUT}.$CHECK" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ '(objectClass=*)' > "${CONSUMEROUT}.$CHECK" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Filtering provider results..."
+$LDIFFILTER < "${PROVIDEROUT}.$CHECK" > $PROVIDERFLT
+#echo "Filtering consumer results..."
+$LDIFFILTER < "${CONSUMEROUT}.$CHECK" > $CONSUMERFLT
+
+echo "$CHECK < Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+CHECK=`expr $CHECK + 1`
+echo "$CHECK > Stopping proxy to test recovery..."
+kill -HUP $PROXYPID
+wait $PROXYPID
+
+echo "Modifying more entries on the provider..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+add: description
+description: proxy is down...
+
+dn: cn=James T. Kirk, ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+sn: Kirk
+uid: jtk
+cn: James T. Kirk
+
+dn: cn=Tiberius J. Hooker, ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+sn: Hooker
+uid: tjh
+cn: Tiberius J. Hooker
+
+EOMODS
+
+echo "Restarting proxy..."
+echo "======================= RESTART =======================" >> $LOG3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL >> $LOG3 2>&1 &
+PROXYPID=$!
+if test $WAIT != 0 ; then
+ echo PROXYPID $PROXYPID
+ read foo
+fi
+KILLPIDS="$PROVIDERPID $CONSUMERPID $PROXYPID"
+
+# get provider contextCSN
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -s base '(objectClass=*)' contextCSN > "${PROVIDEROUT}.$CHECK" 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# check consumer contextCSN
+for i in 1 2 3 4 5; do
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+
+ $LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ -s base '(objectClass=*)' contextCSN > "${CONSUMEROUT}.$CHECK" 2>&1
+ RC=$?
+
+ if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ $CMP ${PROVIDEROUT}.$CHECK ${CONSUMEROUT}.$CHECK > $CMPOUT
+
+ if test $? = 0 ; then
+ break
+ fi
+done
+
+#echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' > "${PROVIDEROUT}.$CHECK" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ '(objectClass=*)' > "${CONSUMEROUT}.$CHECK" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Filtering provider results..."
+$LDIFFILTER < "${PROVIDEROUT}.$CHECK" > $PROVIDERFLT
+#echo "Filtering consumer results..."
+$LDIFFILTER < "${CONSUMEROUT}.$CHECK" > $CONSUMERFLT
+
+echo "$CHECK < Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+CHECK=`expr $CHECK + 1`
+echo "$CHECK > Try updating the consumer slapd..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example, dc=com
+changetype: modify
+add: description
+description: This write must fail because directed to a shadow context,
+description: unless the chain overlay is configured appropriately ;)
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# get provider contextCSN
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -s base '(objectClass=*)' contextCSN > "${PROVIDEROUT}.$CHECK" 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# check consumer contextCSN
+sleep 1
+
+for i in 1 2 3; do
+ $LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ -s base '(objectClass=*)' contextCSN > "${CONSUMEROUT}.$CHECK" 2>&1
+ RC=$?
+
+ if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ $CMP ${PROVIDEROUT}.$CHECK ${CONSUMEROUT}.$CHECK > $CMPOUT
+
+ if test $? = 0 ; then
+ break
+ fi
+
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+done
+
+#echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' > "${PROVIDEROUT}.$CHECK" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+'(objectClass=*)' > "${CONSUMEROUT}.$CHECK" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Filtering provider results..."
+$LDIFFILTER < "${PROVIDEROUT}.$CHECK" > $PROVIDERFLT
+#echo "Filtering consumer results..."
+$LDIFFILTER < "${CONSUMEROUT}.$CHECK" > $CONSUMERFLT
+
+echo "$CHECK < Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+CHECK=`expr $CHECK + 1`
+echo "$CHECK > Stopping consumer to test recovery..."
+kill -HUP $CONSUMERPID
+wait $CONSUMERPID
+
+echo "Modifying more entries on the provider..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+add: drink
+drink: Mad Dog 20/20
+
+EOMODS
+
+echo "Waiting $SLEEP2 seconds for syncrepl to retry..."
+sleep $SLEEP2
+
+echo "Restarting consumer..."
+echo "======================= RESTART =======================" >> $LOG2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL >> $LOG2 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$PROVIDERPID $CONSUMERPID $PROXYPID"
+
+# get provider contextCSN
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -s base '(objectClass=*)' contextCSN > "${PROVIDEROUT}.$CHECK" 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# check consumer contextCSN
+
+for i in 1 2 3 4 5; do
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+
+ $LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ -s base '(objectClass=*)' contextCSN > "${CONSUMEROUT}.$CHECK" 2>&1
+ RC=$?
+
+ if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ $CMP ${PROVIDEROUT}.$CHECK ${CONSUMEROUT}.$CHECK > $CMPOUT
+
+ if test $? = 0 ; then
+ break
+ fi
+done
+
+#echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' > "${PROVIDEROUT}.$CHECK" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ '(objectClass=*)' > "${CONSUMEROUT}.$CHECK" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Filtering provider results..."
+$LDIFFILTER < "${PROVIDEROUT}.$CHECK" > $PROVIDERFLT
+#echo "Filtering consumer results..."
+$LDIFFILTER < "${CONSUMEROUT}.$CHECK" > $CONSUMERFLT
+
+echo "$CHECK < Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ # FIXME: keep the original workaround in place, in case we needed again
+ if test 1 = 1 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ echo " test failed - provider and consumer databases differ (ignored by now)"
+ echo " Stopping proxy to see if it auto-recovers..."
+ kill -HUP $PROXYPID
+ wait $PROXYPID
+
+ echo " ${CHECK}.1 > Restarting proxy..."
+ echo "======================= RESTART =======================" >> $LOG3
+ $SLAPD -f $CONF3 -h $URI3 -d $LVL >> $LOG3 2>&1 &
+ PROXYPID=$!
+ if test $WAIT != 0 ; then
+ echo PROXYPID $PROXYPID
+ read foo
+ fi
+ KILLPIDS="$PROVIDERPID $CONSUMERPID $PROXYPID"
+
+ echo " Waiting $SLEEP2 seconds for syncrepl to receive changes..."
+ sleep $SLEEP2
+
+ #echo "Using ldapsearch to read all the entries from the consumer..."
+ $LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ '(objectClass=*)' > "${CONSUMEROUT}.5.1" 2>&1
+ RC=$?
+
+ if test $RC != 0 ; then
+ echo " ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ #echo "Filtering consumer results..."
+ $LDIFFILTER < "${CONSUMEROUT}.5.1" > $CONSUMERFLT
+
+ echo " ${CHECK}.1 < Comparing retrieved entries from provider and consumer..."
+ $CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+ if test $? != 0 ; then
+ echo " test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+fi
+
+#
+# Modifications formerly known to fail
+#
+CHECK=`expr $CHECK + 1`
+echo "$CHECK > Performing modifications that were formerly known to fail..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+# First, back out previous change
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+delete: drink
+drink: Mad Dog 20/20
+
+# From now on, perform modifications that were formerly known to fail
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: description
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# get provider contextCSN
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -s base '(objectClass=*)' contextCSN > "${PROVIDEROUT}.$CHECK" 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# check consumer contextCSN
+sleep 1
+for i in 1 2 3; do
+ $LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ -s base '(objectClass=*)' contextCSN > "${CONSUMEROUT}.$CHECK" 2>&1
+ RC=$?
+
+ if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ $CMP ${PROVIDEROUT}.$CHECK ${CONSUMEROUT}.$CHECK > $CMPOUT
+
+ if test $? = 0 ; then
+ break
+ fi
+
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+done
+
+#echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' > "${PROVIDEROUT}.$CHECK" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ '(objectClass=*)' > "${CONSUMEROUT}.$CHECK" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Filtering provider results..."
+$LDIFFILTER < "${PROVIDEROUT}.$CHECK" > $PROVIDERFLT
+#echo "Filtering consumer results..."
+$LDIFFILTER < "${CONSUMEROUT}.$CHECK" > $CONSUMERFLT
+
+echo "$CHECK < Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ (ignored by now)"
+ #echo "test failed - provider and consumer databases differ"
+ #test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ #exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test046-dds b/tests/scripts/test046-dds
new file mode 100755
index 0000000..0eaf29b
--- /dev/null
+++ b/tests/scripts/test046-dds
@@ -0,0 +1,575 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2005-2022 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
+
+case $BACKEND in ldif | null)
+ # LDIF lacks ACL support, NULL cannot hold dynamic entries
+ echo "Test does not support $BACKEND backend, test skipped"
+ exit 0
+esac
+
+if test $DDS = ddsno; then
+ echo "Dynamic Directory Services overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $MCONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+. $CONFFILTER $BACKEND < $DDSCONF > $CONF1
+$SLAPINDEX -f $CONF1
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd searching..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(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
+
+cat /dev/null > $SEARCHOUT
+
+echo "Creating a dynamic entry..."
+$LDAPADD -D $MANAGERDN -w $PASSWD -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: cn=Dynamic Object,dc=example,dc=com
+objectClass: inetOrgPerson
+objectClass: dynamicObject
+cn: Dynamic Object
+sn: Object
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Refreshing the newly created dynamic entry..."
+$LDAPEXOP -D $MANAGERDN -w $PASSWD -H $URI1 \
+ "refresh" "cn=Dynamic Object,dc=example,dc=com" "120" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapexop failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Modifying the newly created dynamic entry..."
+$LDAPMODIFY -D $MANAGERDN -w $PASSWD -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: cn=Dynamic Object,dc=example,dc=com
+changetype: modify
+add: userPassword
+userPassword: dynamic
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Binding as the newly created dynamic entry..."
+$LDAPWHOAMI -H $URI1 \
+ -D "cn=Dynamic Object,dc=example,dc=com" -w dynamic
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Creating a dynamic entry subordinate to another..."
+$LDAPADD -D $MANAGERDN -w $PASSWD -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: cn=Subordinate Dynamic Object,cn=Dynamic Object,dc=example,dc=com
+objectClass: inetOrgPerson
+objectClass: dynamicObject
+cn: Subordinate Dynamic Object
+sn: Object
+userPassword: dynamic
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+SEARCH=0
+
+SEARCH=`expr $SEARCH + 1`
+sleep $SLEEP0
+echo "# [$SEARCH] Searching the dynamic portion of the database..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=dynamicObject)' '*' entryTtl \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Creating a static entry subordinate to a dynamic one (should fail)..."
+$LDAPADD -D $MANAGERDN -w $PASSWD -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: cn=Subordinate Static Object,cn=Dynamic Object,dc=example,dc=com
+objectClass: inetOrgPerson
+cn: Subordinate Static Object
+sn: Object
+userPassword: static
+EOMODS
+RC=$?
+case $RC in
+0)
+ echo "ldapadd should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+19)
+ echo "ldapadd failed ($RC)"
+ ;;
+*)
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Turning a static into a dynamic entry (should fail)..."
+$LDAPMODIFY -D $MANAGERDN -w $PASSWD -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: ou=People,dc=example,dc=com
+changetype: modify
+add: objectClass
+objectClass: dynamicObject
+EOMODS
+RC=$?
+case $RC in
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+65)
+ echo "ldapmodify failed ($RC)"
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Turning a dynamic into a static entry (should fail)..."
+$LDAPMODIFY -D $MANAGERDN -w $PASSWD -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: cn=Dynamic Object,dc=example,dc=com
+changetype: modify
+delete: objectClass
+objectClass: dynamicObject
+EOMODS
+RC=$?
+case $RC in
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+65)
+ echo "ldapmodify failed ($RC)"
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Renaming a dynamic entry..."
+$LDAPMODIFY -D $MANAGERDN -w $PASSWD -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: cn=Subordinate Dynamic Object,cn=Dynamic Object,dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Renamed Dynamic Object
+deleteoldrdn: 1
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodrdn failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+SEARCH=`expr $SEARCH + 1`
+sleep $SLEEP0
+echo "# [$SEARCH] Searching the dynamic portion of the database..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=dynamicObject)' '*' entryTtl \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Refreshing the initial dynamic entry to make it expire earlier than the subordinate..."
+$LDAPEXOP -D $MANAGERDN -w $PASSWD -H $URI1 \
+ "refresh" "cn=Dynamic Object,dc=example,dc=com" "1" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapexop failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+SLEEP=10
+echo "Waiting $SLEEP seconds to force a subordinate/superior expiration conflict..."
+sleep $SLEEP
+
+echo "Re-vitalizing the initial dynamic entry..."
+$LDAPEXOP -D $MANAGERDN -w $PASSWD -H $URI1 \
+ "refresh" "cn=Dynamic Object,dc=example,dc=com" "120" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapexop failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Re-renaming the subordinate dynamic entry (new superior)..."
+$LDAPMODIFY -D $MANAGERDN -w $PASSWD -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: cn=Renamed Dynamic Object,cn=Dynamic Object,dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Renamed Dynamic Object
+deleteoldrdn: 1
+newsuperior: dc=example,dc=com
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodrdn failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+SEARCH=`expr $SEARCH + 1`
+sleep $SLEEP0
+echo "# [$SEARCH] Searching the dynamic portion of the database..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=dynamicObject)' '*' entryTtl \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Deleting a dynamic entry..."
+$LDAPMODIFY -D $MANAGERDN -w $PASSWD -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: cn=Dynamic Object,dc=example,dc=com
+changetype: delete
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapdelete failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+SEARCH=`expr $SEARCH + 1`
+sleep $SLEEP0
+echo "# [$SEARCH] Searching the dynamic portion of the database..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=dynamicObject)' '*' entryTtl \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Refreshing the remaining dynamic entry..."
+$LDAPEXOP -D $MANAGERDN -w $PASSWD -H $URI1 \
+ "refresh" "cn=Renamed Dynamic Object,dc=example,dc=com" "1" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapexop failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+SEARCH=`expr $SEARCH + 1`
+sleep $SLEEP0
+echo "# [$SEARCH] Searching the dynamic portion of the database..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=dynamicObject)' '*' entryTtl \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+SLEEP=15
+echo "Waiting $SLEEP seconds for remaining entry to expire..."
+sleep $SLEEP
+
+SEARCH=`expr $SEARCH + 1`
+sleep $SLEEP0
+echo "# [$SEARCH] Searching the dynamic portion of the database..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=dynamicObject)' '*' entryTtl \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Meeting
+MEETINGDN="cn=Meeting,ou=Groups,dc=example,dc=com"
+echo "Creating a meeting as $BJORNSDN..."
+$LDAPMODIFY -D "$BJORNSDN" -w bjorn -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: $MEETINGDN
+changetype: add
+objectClass: groupOfNames
+objectClass: dynamicObject
+cn: Meeting
+member: $BJORNSDN
+
+dn: $MEETINGDN
+changetype: modify
+add: member
+member: $JOHNDDN
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Refreshing the meeting as $BJORNSDN..."
+$LDAPEXOP -D "$BJORNSDN" -w bjorn -H $URI1 \
+ "refresh" "$MEETINGDN" "120" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapexop failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Joining the meeting as $BABSDN..."
+$LDAPMODIFY -D "$BABSDN" -w bjensen -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: $MEETINGDN
+changetype: modify
+add: member
+member: $BABSDN
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Trying to add a member as $BABSDN (should fail)..."
+$LDAPMODIFY -D "$BABSDN" -w bjensen -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: $MEETINGDN
+changetype: modify
+add: member
+member: $MELLIOTDN
+EOMODS
+RC=$?
+case $RC in
+0)
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+50)
+ echo "ldapmodify failed ($RC)"
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Refreshing the meeting as $BABSDN..."
+$LDAPEXOP -D "$BABSDN" -w bjensen -H $URI1 \
+ "refresh" "$MEETINGDN" "180" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapexop failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Trying to refresh the meeting anonymously (should fail)..."
+$LDAPEXOP -H $URI1 \
+ "refresh" "$MEETINGDN" "240" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "ldapexop should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Trying to refresh the meeting as $JAJDN (should fail)..."
+$LDAPEXOP -D "$JAJDN" -w "jaj" -H $URI1 \
+ "refresh" "$MEETINGDN" "240" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "ldapexop should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Trying to delete the meeting as $BABSDN (should fail)..."
+$LDAPMODIFY -D "$BABSDN" -w bjensen -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: $MEETINGDN
+changetype: delete
+EOMODS
+RC=$?
+case $RC in
+0)
+ echo "ldapdelete should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+50)
+ echo "ldapdelete failed ($RC)"
+ ;;
+*)
+ echo "ldapdelete failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Deleting the meeting as $BJORNSDN..."
+$LDAPMODIFY -D "$BJORNSDN" -w bjorn -H $URI1 \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: $MEETINGDN
+changetype: delete
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapdelete failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$DDSOUT
+
+# dds removes entryTtl and re-adds it, changing the order of attributes
+echo "Filtering ldapsearch results..."
+$LDIFFILTER -s a < $SEARCHOUT > $SEARCHFLT
+grep -i -v -e '^entryttl: ' < $SEARCHFLT > $SEARCHFLT2
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER -s a < $LDIF > $LDIFFLT
+grep -i -v -e '^entryttl: ' < $LDIFFLT > $LDIFFLT2
+echo "Comparing filter output..."
+$CMP $SEARCHFLT2 $LDIFFLT2 > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo "Listing entryTtl values from ldapsearch results..."
+grep -i -e '^entryttl: ' < $SEARCHFLT | awk '{ print $2 }' > $SEARCHFLT2
+echo "Listing entryTtl values from original ldif used to create database..."
+grep -i -e '^entryttl: ' < $LDIFFLT | awk '{ print $2 }' > $LDIFFLT2
+
+if ! type paste >/dev/null 2>&1; then
+ echo "Cannot find 'paste' command, skipping entryTtl checks..."
+else
+ echo "Checking entryTtl appears to decrease with time..."
+ paste $SEARCHFLT2 $LDIFFLT2 | while read resultTTL savedTTL; do
+ if [ `expr $savedTTL - $resultTTL` -lt $SLEEP0 ]; then
+ echo "TTL has not reduced accordingly"
+ exit 1
+ fi
+ done
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test047-ldap b/tests/scripts/test047-ldap
new file mode 100755
index 0000000..7397de6
--- /dev/null
+++ b/tests/scripts/test047-ldap
@@ -0,0 +1,754 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+echo ""
+
+if test $BACKLDAP = ldapno ; then
+ echo "ldap backend not available, test skipped"
+ exit 0
+fi
+
+if test $RWM = rwmno ; then
+ echo "rwm (rewrite/remap) overlay not available, test skipped"
+ exit 0
+fi
+
+rm -rf $TESTDIR
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $METACONF1 > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ '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 "Using ldapadd to populate the database..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDERED > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $METACONF2 > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+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 "$MONITOR" -H $URI2 \
+ '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 "Using ldapadd to populate the database..."
+$LDAPADD -D "$METAMANAGERDN" -H $URI2 -w $PASSWD < \
+ $LDIFMETA >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT3..."
+. $CONFFILTER $BACKEND < $GLUELDAPCONF > $CONF3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+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 "$MONITOR" -H $URI3 \
+ '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
+
+cat /dev/null > $SEARCHOUT
+
+BASEDN="o=Example,c=US"
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+# ITS#4195: spurious matchedDN when the search scopes the main target,
+# and the searchBase is not present, so that target returns noSuchObject
+BASEDN="ou=Meta,o=Example,c=US"
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+#
+# Do some modifications
+#
+
+BASEDN="o=Example,c=US"
+echo "Modifying database \"$BASEDN\"..."
+$LDAPMODIFY -v -D "cn=Manager,$BASEDN" -H $URI3 -w $PASSWD \
+ -M >> $TESTOUT 2>&1 << EOMODS
+# These operations (updates with objectClass mapping) triggered ITS#3499
+dn: cn=Added Group,ou=Groups,$BASEDN
+changetype: add
+objectClass: groupOfNames
+objectClass: uidObject
+cn: Added Group
+member: cn=Added Group,ou=Groups,$BASEDN
+uid: added
+
+dn: cn=Another Added Group,ou=Groups,$BASEDN
+changetype: add
+objectClass: groupOfNames
+cn: Another Added Group
+member: cn=Added Group,ou=Groups,$BASEDN
+member: cn=Another Added Group,ou=Groups,$BASEDN
+
+dn: cn=Another Added Group,ou=Groups,$BASEDN
+changetype: modify
+add: objectClass
+objectClass: uidObject
+-
+add: uid
+uid: added
+-
+
+dn: cn=Added Group,ou=Groups,$BASEDN
+changetype: modify
+delete: objectClass
+objectClass: uidObject
+-
+delete: uid
+-
+
+dn: ou=Meta,$BASEDN
+changetype: modify
+add: description
+description: added to "ou=Meta,$BASEDN"
+-
+
+dn: ou=Who's going to handle this?,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Who's going to handle this?
+description: added
+description: will be deleted
+
+dn: ou=Same as above,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Same as above
+description: added right after "Who's going to handle this?"
+description: will be preserved
+
+dn: ou=Who's going to handle this?,$BASEDN
+changetype: delete
+
+dn: ou=Who's going to handle this?,ou=Meta,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Who's going to handle this?
+description: added
+description: will be deleted
+
+dn: ou=Same as above,ou=Meta,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Same as above
+description: added right after "Who's going to handle this?"
+description: will be preserved
+
+dn: cn=Added User,ou=Same as above,ou=Meta,$BASEDN
+changetype: add
+objectClass: inetOrgPerson
+cn: Added User
+sn: User
+userPassword: secret
+
+dn: ou=Who's going to handle this?,ou=Meta,$BASEDN
+changetype: delete
+EOMODS
+
+RC=$?
+#if test $RC != 0 ; then
+# echo "Modify failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Modify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+BASEDN="o=Example,c=US"
+echo " base=\"$BASEDN\"..."
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" -M "$FILTER" '*' ref \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+BASEDN="o=Example,c=US"
+FILTER="(seeAlso=cn=all staff,ou=Groups,$BASEDN)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"seeAlso\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"seeAlso\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" "$FILTER" seeAlso \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+FILTER="(uid=example)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"uid\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"uid\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" "$FILTER" uid \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+FILTER="(member=cn=Another Added Group,ou=Groups,$BASEDN)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"member\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"member\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" "$FILTER" member \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Waiting 10 seconds for cached connections to timeout..."
+sleep 10
+
+echo "Searching with a timed out connection..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"member\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"" >> $SEARCHOUT
+echo "# with a timed out connection..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -D "cn=Manager,$BASEDN" -w $PASSWD \
+ -b "$BASEDN" "$FILTER" member \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+# NOTE: cannot send to $SEARCHOUT because the returned entries
+# are not predictable...
+echo "Checking server-enforced size limit..."
+echo "# Checking server-enforced size limit..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 \
+ -D "cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN" -w bjorn \
+ -b "$BASEDN" "(objectClass=*)" 1.1 \
+ >> $TESTOUT 2>&1
+RC=$?
+case $RC,$BACKEND in
+ 4,* | 0,null)
+ ;;
+ 0,*)
+ echo "Search should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+# NOTE: cannot send to $SEARCHOUT because the returned entries
+# are not predictable...
+echo "Checking client-requested size limit..."
+echo "# Checking client-requested size limit..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 \
+ -D "cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN" -w bjorn \
+ -b "$BASEDN" -z 2 "(objectClass=*)" 1.1 \
+ >> $TESTOUT 2>&1
+RC=$?
+case $RC,$BACKEND in
+ 4,* | 0,null)
+ ;;
+ 0,*)
+ echo "Search should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $METAOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - meta search/modification didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+# ITS#4458 needs patch to slapo-rwm for global rewriting of passwd_exop
+BASEDN="o=Example,c=US"
+echo "Changing password to database \"$BASEDN\"..."
+$LDAPPASSWD -H $URI3 -D "cn=Manager,$BASEDN" -w $PASSWD \
+ -s $PASSWD "cn=Ursula Hampster,ou=Alumni Association,ou=People,$BASEDN" \
+ >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Passwd ExOp failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+# 51)
+# echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit 0
+# ;;
+# 80)
+ 1)
+ echo "Passwd ExOp failed ($RC)! ITS#4458?"
+ ;;
+ *)
+ echo "Passwd ExOp failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+if test $RC = 0 ; then
+ echo "Binding with newly changed password to database \"$BASEDN\"..."
+ $LDAPWHOAMI -H $URI3 \
+ -D "cn=Ursula Hampster,ou=Alumni Association,ou=People,$BASEDN" \
+ -w $PASSWD >> $TESTOUT 2>&1
+ RC=$?
+ #if test $RC != 0 ; then
+ # echo "WhoAmI failed ($RC)!"
+ # test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ # exit $RC
+ #fi
+ case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ echo "WhoAmI failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+ esac
+fi
+
+echo "Binding as newly added user to database \"$BASEDN\"..."
+$LDAPWHOAMI -H $URI3 \
+ -D "cn=Added User,ou=Same as above,ou=Meta,$BASEDN" \
+ -w $PASSWD >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "WhoAmI failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ echo "WhoAmI failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Changing password to database \"$BASEDN\"..."
+$LDAPPASSWD -H $URI3 -D "cn=Manager,$BASEDN" -w $PASSWD \
+ -s meta "cn=Added User,ou=Same as above,ou=Meta,$BASEDN" \
+ >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Passwd ExOp failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+# 51)
+# echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit 0
+# ;;
+# 80)
+ 1)
+ echo "Passwd ExOp failed ($RC)! ITS#4458?"
+ ;;
+ *)
+ echo "Passwd ExOp failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+if test $RC = 0 ; then
+ echo "Binding with newly changed password to database \"$BASEDN\"..."
+ $LDAPWHOAMI -H $URI3 \
+ -D "cn=Added User,ou=Same as above,ou=Meta,$BASEDN" \
+ -w meta >> $TESTOUT 2>&1
+ RC=$?
+ #if test $RC != 0 ; then
+ # echo "WhoAmI failed ($RC)!"
+ # test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ # exit $RC
+ #fi
+ case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ echo "WhoAmI failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+ esac
+fi
+
+echo "Binding with incorrect password to database \"$BASEDN\"..."
+$LDAPWHOAMI -H $URI3 \
+ -D "cn=Added User,ou=Same as above,ou=Meta,$BASEDN" \
+ -w bogus >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "WhoAmI failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC,$BACKEND in
+ 0,null)
+ ;;
+ 0,*)
+ echo "WhoAmI should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ 51,*)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ ;;
+esac
+
+echo "Binding with non-existing user to database \"$BASEDN\"..."
+$LDAPWHOAMI -H $URI3 \
+ -D "cn=Non-existing User,ou=Same as above,ou=Meta,$BASEDN" \
+ -w bogus >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "WhoAmI failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC,$BACKEND in
+ 0,null)
+ ;;
+ 0,*)
+ echo "WhoAmI should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ 51,*)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ ;;
+esac
+
+echo "Comparing to database \"$BASEDN\"..."
+$LDAPCOMPARE -H $URI3 \
+ "cn=Another Added Group,ou=Groups,$BASEDN" \
+ "member:cn=Added Group,ou=Groups,$BASEDN" >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 6 ; then
+# echo "Compare failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit 1
+#fi
+case $RC,$BACKEND in
+ 5,null)
+ ;;
+ 6,*)
+ ;;
+ 51,*)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ echo "Compare failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+esac
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test048-syncrepl-multiproxy b/tests/scripts/test048-syncrepl-multiproxy
new file mode 100755
index 0000000..fb231a2
--- /dev/null
+++ b/tests/scripts/test048-syncrepl-multiproxy
@@ -0,0 +1,596 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $BACKLDAP = ldapno; then
+ echo "LDAP backend not available, test skipped"
+ exit 0
+fi
+
+if test $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2 $DBDIR3
+
+#
+# Test replication:
+# - start provider
+# - start consumer
+# - populate over ldap
+# - perform some modifies and deleted
+# - attempt to modify the consumer (referral or chain)
+# - retrieve database over ldap and compare against expected results
+#
+
+echo "Starting provider slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $PLSRPROVIDERCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PROVIDERPID=$!
+if test $WAIT != 0 ; then
+ echo PROVIDERPID $PROVIDERPID
+ read foo
+fi
+KILLPIDS="$PROVIDERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(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 "Using ldapadd to create the context prefix entry in the provider..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDEREDCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting P1 consumer slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $RCONSUMERCONF > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+P1CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo P1CONSUMERPID $P1CONSUMERPID
+ read foo
+fi
+KILLPIDS="$PROVIDERPID $P1CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that P1 consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '(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 "Starting R1 consumer slapd on TCP/IP port $PORT3..."
+. $CONFFILTER $BACKEND < $RCONSUMERCONF | sed -e 's;\.2\.\([^/]*\)$;.3.\1;' > $CONF3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+R1CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo R1CONSUMERPID $R1CONSUMERPID
+ read foo
+fi
+KILLPIDS="$PROVIDERPID $P1CONSUMERPID $R1CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that R1 consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI3 \
+ '(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
+
+CHECK=1
+echo "$CHECK > Using ldapadd to populate the provider directory..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDEREDNOCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+#echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' > "${PROVIDEROUT}.1" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Using ldapsearch to read all the entries from the P1 consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ '(objectClass=*)' > "${CONSUMEROUT}.1" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at P1 consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Filtering provider results..."
+$LDIFFILTER < "${PROVIDEROUT}.1" > $PROVIDERFLT
+#echo "Filtering consumer results..."
+$LDIFFILTER < "${CONSUMEROUT}.1" > $CONSUMERFLT
+
+echo "$CHECK < Comparing retrieved entries from provider and P1 consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and P1 consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+#echo "Using ldapsearch to read all the entries from the R1 consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI3 \
+ '(objectClass=*)' > "${CONSUMEROUT}.1" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at R1 consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Filtering consumer results..."
+$LDIFFILTER < "${CONSUMEROUT}.1" > $CONSUMERFLT
+
+echo "$CHECK < Comparing retrieved entries from provider and R1 consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and R1 consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+CHECK=`expr $CHECK + 1`
+echo "$CHECK > Stopping the provider, sleeping $SLEEP2 seconds and restarting it..."
+kill -HUP "$PROVIDERPID"
+wait $PROVIDERPID
+sleep $SLEEP2
+
+echo "======================= RESTART =======================" >> $LOG1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL >> $LOG1 2>&1 &
+PROVIDERPID=$!
+if test $WAIT != 0 ; then
+ echo PROVIDERPID $PROVIDERPID
+ read foo
+fi
+KILLPIDS="$PROVIDERPID $P1CONSUMERPID $R1CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '(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 "Using ldapmodify to modify provider directory..."
+
+#
+# Do some modifications
+#
+
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+changetype: modify
+add: drink
+drink: Orange Juice
+-
+delete: sn
+sn: Jones
+-
+add: sn
+sn: Jones
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: drink
+drink: Iced Tea
+
+dn: cn=ITD Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: uniquemember
+uniquemember: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+uniquemember: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+-
+add: uniquemember
+uniquemember: cn=Dorothy Stevens, ou=Alumni Association, ou=People, dc=example,dc=com
+uniquemember: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+
+dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc
+ =com
+changetype: modify
+delete: cn
+cn: Biiff Jensen
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+cn: Gern Jensen
+sn: Jensen
+uid: gjensen
+title: Chief Investigator, ITD
+postaladdress: ITD $ 535 W. William St $ Ann Arbor, MI 48103
+seealso: cn=All Staff, ou=Groups, dc=example,dc=com
+drink: Coffee
+homepostaladdress: 844 Brown St. Apt. 4 $ Ann Arbor, MI 48104
+description: Very odd
+facsimiletelephonenumber: +1 313 555 7557
+telephonenumber: +1 313 555 8343
+mail: gjensen@mailgw.example.com
+homephone: +1 313 555 8844
+
+dn: ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: organizationalUnit
+ou: Retired
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+cn: Rosco P. Coltrane
+sn: Coltrane
+uid: rosco
+description: Fat tycoon
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Rosco P. Coltrane
+deleteoldrdn: 1
+newsuperior: ou=Retired, ou=People, dc=example,dc=com
+
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: delete
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+#echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' > "${PROVIDEROUT}.2" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Using ldapsearch to read all the entries from the P1 consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ '(objectClass=*)' > "${CONSUMEROUT}.2" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at P1 consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Filtering provider results..."
+$LDIFFILTER < "${PROVIDEROUT}.2" > $PROVIDERFLT
+#echo "Filtering P1 consumer results..."
+$LDIFFILTER < "${CONSUMEROUT}.2" > $CONSUMERFLT
+
+echo "$CHECK < Comparing retrieved entries from provider and P1 consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and P1 consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+#echo "Using ldapsearch to read all the entries from the R1 consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI3 \
+ '(objectClass=*)' > "${CONSUMEROUT}.2" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at R1 consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Filtering consumer results..."
+$LDIFFILTER < "${CONSUMEROUT}.2" > $CONSUMERFLT
+
+echo "$CHECK < Comparing retrieved entries from provider and R1 consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and R1 consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+CHECK=`expr $CHECK + 1`
+echo "$CHECK > Stopping consumer to test recovery..."
+kill -HUP $P1CONSUMERPID $R1CONSUMERPID
+wait $P1CONSUMERPID
+wait $R1CONSUMERPID
+
+echo "Modifying more entries on the provider..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+add: description
+description: r1 consumer is down...
+
+dn: cn=James T. Kirk, ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+sn: Kirk
+uid: jtk
+cn: James T. Kirk
+
+dn: cn=Tiberius J. Hooker, ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+sn: Hooker
+uid: tjh
+cn: Tiberius J. Hooker
+
+EOMODS
+
+echo "Restarting P1 consumer..."
+echo "======================= RESTART =======================" >> $LOG3
+$SLAPD -f $CONF2 -h $URI2 -d $LVL >> $LOG2 2>&1 &
+P1CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo P1CONSUMERPID $P1CONSUMERPID
+ read foo
+fi
+
+echo "Restarting R1 consumer..."
+echo "======================= RESTART =======================" >> $LOG3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL >> $LOG3 2>&1 &
+R1CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo R1CONSUMERPID $R1CONSUMERPID
+ read foo
+fi
+KILLPIDS="$PROVIDERPID $P1CONSUMERPID $R1CONSUMERPID"
+
+echo "Waiting $SLEEP2 seconds for syncrepl to receive changes..."
+sleep $SLEEP2
+
+#echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' > "${PROVIDEROUT}.3" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Using ldapsearch to read all the entries from the P1 consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ '(objectClass=*)' > "${CONSUMEROUT}.3" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Filtering provider results..."
+$LDIFFILTER < "${PROVIDEROUT}.3" > $PROVIDERFLT
+#echo "Filtering consumer results..."
+$LDIFFILTER < "${CONSUMEROUT}.3" > $CONSUMERFLT
+
+echo "$CHECK < Comparing retrieved entries from provider and P1 consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+#echo "Using ldapsearch to read all the entries from the R1 consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI3 \
+ '(objectClass=*)' > "${CONSUMEROUT}.3" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Filtering consumer results..."
+$LDIFFILTER < "${CONSUMEROUT}.3" > $CONSUMERFLT
+
+echo "$CHECK < Comparing retrieved entries from provider and R1 consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+CHECK=`expr $CHECK + 1`
+echo "$CHECK > Try updating the P1 consumer slapd..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example, dc=com
+changetype: modify
+add: description
+description: This write must fail because directed to a shadow context,
+description: unless the chain overlay is configured appropriately ;)
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+#echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' > "${PROVIDEROUT}.4" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Using ldapsearch to read all the entries from the P1 consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+'(objectClass=*)' > "${CONSUMEROUT}.4" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Filtering provider results..."
+$LDIFFILTER < "${PROVIDEROUT}.4" > $PROVIDERFLT
+#echo "Filtering consumer results..."
+$LDIFFILTER < "${CONSUMEROUT}.4" > $CONSUMERFLT
+
+echo "$CHECK < Comparing retrieved entries from provider and P1 consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and P1 consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+#echo "Using ldapsearch to read all the entries from the R1 consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI3 \
+'(objectClass=*)' > "${CONSUMEROUT}.4" 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#echo "Filtering consumer results..."
+$LDIFFILTER < "${CONSUMEROUT}.4" > $CONSUMERFLT
+
+echo "$CHECK < Comparing retrieved entries from provider and R1 consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and R1 consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test049-sync-config b/tests/scripts/test049-sync-config
new file mode 100755
index 0000000..b05e041
--- /dev/null
+++ b/tests/scripts/test049-sync-config
@@ -0,0 +1,419 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+PRODIR=$TESTDIR/pro
+CONDIR=$TESTDIR/con1
+DBPRO=$PRODIR/db
+DBCON=$CONDIR/db
+CFPRO=$PRODIR/slapd.d
+CFCON=$CONDIR/slapd.d
+
+mkdir -p $TESTDIR $PRODIR $CONDIR $DBPRO $DBCON $CFPRO $CFCON
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+if test x"$SYNCMODE" = x ; then
+ SYNCMODE=rp
+fi
+case "$SYNCMODE" in
+ ro)
+ SYNCTYPE="type=refreshOnly interval=00:00:00:03"
+ ;;
+ rp)
+ SYNCTYPE="type=refreshAndPersist"
+ ;;
+ *)
+ echo "unknown sync mode $SYNCMODE"
+ exit 1;
+ ;;
+esac
+
+#
+# Test replication of dynamic config:
+# - start provider
+# - start consumer
+# - configure over ldap
+# - populate over ldap
+# - configure syncrepl over ldap
+# - retrieve database over ldap and compare against expected results
+#
+
+echo "Starting provider slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $DYNAMICCONF > $CONFLDIF
+$SLAPADD -F $CFPRO -n 0 -l $CONFLDIF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+cd $PRODIR
+$SLAPD -F ./slapd.d -h $URI1 -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 provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI1 \
+ '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 "Inserting syncprov overlay on provider..."
+if [ "$SYNCPROV" = syncprovmod ]; then
+ $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+olcModuleLoad: syncprov.la
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for moduleLoad ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+read CONFIGPW < $CONFIGPWF
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={0}config,cn=config
+changetype: modify
+add: olcSyncRepl
+olcSyncRepl: rid=001 provider=$URI1 binddn="cn=config" bindmethod=simple
+ credentials=$CONFIGPW searchbase="cn=config" type=refreshAndPersist
+ retry="3 5 300 5" timeout=3
+-
+add: olcUpdateRef
+olcUpdateRef: $URI1
+
+dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for syncrepl config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting consumer slapd on TCP/IP port $PORT2..."
+$SLAPADD -F $CFCON -n 0 -l $CONFLDIF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+cd $CONDIR
+$SLAPD -F ./slapd.d -h $URI2 -d $LVL > $LOG2 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+cd $TESTWD
+
+sleep 1
+
+echo "Using ldapsearch to check that consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI2 \
+ '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 "Configuring syncrepl on consumer..."
+$LDAPMODIFY -D cn=config -H $URI2 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: olcDatabase={0}config,cn=config
+changetype: modify
+add: olcSyncRepl
+olcSyncRepl: rid=001 provider=$URI1 binddn="cn=config" bindmethod=simple
+ credentials=$CONFIGPW searchbase="cn=config" type=refreshAndPersist
+ retry="3 5 300 5" timeout=3
+-
+add: olcUpdateRef
+olcUpdateRef: $URI1
+EOF
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapsearch to check that syncrepl received config changes..."
+RC=32
+for i in 0 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI2 -D cn=config -y $CONFIGPWF \
+ -s base -b "olcDatabase={0}config,cn=config" \
+ '(olcUpdateRef=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+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 provider..."
+$LDAPADD -D cn=config -H $URI1 -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 $URI1 -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 $URI1 -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: ./db
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+olcSyncRepl: rid=002 provider=$URI1 binddn="$MANAGERDN" bindmethod=simple
+ credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE
+ retry="3 5 300 5" timeout=3
+olcUpdateRef: $URI1
+
+dn: olcOverlay=syncprov,olcDatabase={1}${BACKEND},cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+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 $URI1 -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 provider..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $LDIFORDERED \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for database config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapsearch to check that syncrepl received database changes..."
+RC=32
+for i in 0 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI2 \
+ -s base -b "cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Replacing olcSyncrepl on provider..."
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={0}config,cn=config
+changetype: modify
+replace: olcSyncRepl
+olcSyncRepl: rid=003 provider=$URI1 binddn="cn=config" bindmethod=simple
+ credentials=$CONFIGPW searchbase="cn=config" type=refreshAndPersist
+ retry="3 5 300 5" timeout=3
+EOF
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapsearch to read config from the provider..."
+$LDAPSEARCH -b cn=config -D cn=config -H $URI1 -y $CONFIGPWF \
+ 'objectclass=*' > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read config from the consumer..."
+$LDAPSEARCH -b cn=config -D cn=config -H $URI2 -y $CONFIGPWF \
+ 'objectclass=*' > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering provider results..."
+$LDIFFILTER < $PROVIDEROUT > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER < $CONSUMEROUT > $CONSUMERFLT
+
+echo "Comparing retrieved configs from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer configs differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ 'objectclass=*' > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI2 -w $PASSWD \
+ 'objectclass=*' > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo "Filtering provider results..."
+$LDIFFILTER < $PROVIDEROUT > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER < $CONSUMEROUT > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test050-syncrepl-multiprovider b/tests/scripts/test050-syncrepl-multiprovider
new file mode 100755
index 0000000..dcdf395
--- /dev/null
+++ b/tests/scripts/test050-syncrepl-multiprovider
@@ -0,0 +1,794 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+MPR=${MPR-4}
+
+if [ $MPR -gt 9 ]; then
+MPR=9
+fi
+
+XDIR=$TESTDIR/srv
+TMP=$TESTDIR/tmp
+
+mkdir -p $TESTDIR
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+if test x"$SYNCMODE" = x ; then
+ SYNCMODE=rp
+fi
+case "$SYNCMODE" in
+ ro)
+ SYNCTYPE="type=refreshOnly interval=00:00:00:03"
+ ;;
+ rp)
+ SYNCTYPE="type=refreshAndPersist"
+ ;;
+ *)
+ echo "unknown sync mode $SYNCMODE"
+ exit 1;
+ ;;
+esac
+
+#
+# Test replication of dynamic config:
+# - start servers
+# - configure over ldap
+# - populate over ldap
+# - configure syncrepl over ldap
+# - retrieve database over ldap and compare against expected results
+#
+
+echo "Initializing server configurations..."
+n=1
+while [ $n -le $MPR ]; do
+
+DBDIR=${XDIR}$n/db
+CFDIR=${XDIR}$n/slapd.d
+
+mkdir -p ${XDIR}$n $DBDIR $CFDIR
+
+$SLAPADD -F $CFDIR -n 0 <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+olcServerID: $n
+
+dn: olcDatabase={0}config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW:< file://$CONFIGPWF
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+n=`expr $n + 1`
+done
+
+echo "Starting server 1 on TCP/IP port $PORT1..."
+cd ${XDIR}1
+$SLAPD -F slapd.d -h $URI1 -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 server 1 is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI1 \
+ '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 "Inserting syncprov overlay on server 1..."
+echo "" > $TMP
+if [ "$SYNCPROV" = syncprovmod ]; then
+cat <<EOF >> $TMP
+dn: cn=module,cn=config
+changetype: add
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+olcModuleLoad: syncprov.la
+
+EOF
+fi
+#
+# Note that we configure a timeout here; it's possible for both
+# servers to attempt to bind to each other while a modify to
+# cn=config is in progress. When the modify pauses the thread pool
+# neither server will progress. The timeout will drop the syncrepl
+# attempt and allow the modifies to complete.
+#
+read CONFIGPW < $CONFIGPWF
+echo "dn: cn=config" >> $TMP
+echo "changetype: modify" >> $TMP
+echo "replace: olcServerID" >> $TMP
+n=1
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+echo "olcServerID: $n $URI" >> $TMP
+n=`expr $n + 1`
+done
+
+cat <<EOF >> $TMP
+
+dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+
+dn: olcDatabase={0}config,cn=config
+changetype: modify
+add: olcSyncRepl
+EOF
+
+n=1
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+echo "olcSyncRepl: rid=00$n provider=$URI binddn=\"cn=config\" bindmethod=simple" >> $TMP
+echo " credentials=$CONFIGPW searchbase=\"cn=config\" type=refreshAndPersist" >> $TMP
+echo " retry=\"1 12 300 5\" timeout=3" >> $TMP
+n=`expr $n + 1`
+done
+echo "-" >> $TMP
+echo "add: olcMultiProvider" >> $TMP
+echo "olcMultiProvider: TRUE" >> $TMP
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF < $TMP >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for syncrepl config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+n=2
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+LOG=$TESTDIR/slapd.$n.log
+echo "Starting server $n on TCP/IP port $PORT..."
+cd ${XDIR}$n
+$SLAPD -F ./slapd.d -h $URI -d $LVL > $LOG 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+cd $TESTWD
+
+sleep 1
+
+echo "Using ldapsearch to check that server $n is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI \
+ '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 "Configuring syncrepl on server $n..."
+cat <<EOF > $TMP
+dn: olcDatabase={0}config,cn=config
+changetype: modify
+add: olcSyncRepl
+EOF
+j=1
+while [ $j -le $MPR ]; do
+P2=`expr $BASEPORT + $j`
+U2="ldap://${LOCALHOST}:$P2/"
+echo "olcSyncRepl: rid=00$j provider=$U2 binddn=\"cn=config\" bindmethod=simple" >> $TMP
+echo " credentials=$CONFIGPW searchbase=\"cn=config\" type=refreshAndPersist" >> $TMP
+echo " retry=\"1 12 300 5\" timeout=3" >> $TMP
+j=`expr $j + 1`
+done
+cat <<EOF >> $TMP
+-
+add: olcMultiProvider
+olcMultiProvider: TRUE
+EOF
+$LDAPMODIFY -D cn=config -H $URI -y $CONFIGPWF < $TMP >>$TESTOUT 2>&1
+n=`expr $n + 1`
+done
+
+echo "Adding schema and databases on server 1..."
+$LDAPADD -D cn=config -H $URI1 -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=""
+test $BACKEND = null && nullExclude="# "
+
+echo "" > $TMP
+if [ "$BACKENDTYPE" = mod ]; then
+cat <<EOF >> $TMP
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/back-$BACKEND
+olcModuleLoad: back_$BACKEND.la
+
+EOF
+fi
+
+cat <<EOF >> $TMP
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+olcSuffix: $BASEDN
+${nullExclude}olcDbDirectory: ./db
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+EOF
+
+n=1
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+
+echo "olcSyncRepl: rid=01$n provider=$URI binddn=\"$MANAGERDN\" bindmethod=simple" >> $TMP
+echo " credentials=$PASSWD searchbase=\"$BASEDN\" $SYNCTYPE" >> $TMP
+echo " retry=\"1 12 300 5\" timeout=3" >> $TMP
+n=`expr $n + 1`
+done
+
+cat <<EOF >> $TMP
+olcMultiProvider: TRUE
+
+dn: olcOverlay=syncprov,olcDatabase={1}${BACKEND},cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+EOF
+$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF < $TMP >>$TESTOUT 2>&1
+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 $URI1 -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 server 1..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $LDIFORDERED \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP2 seconds for syncrepl to receive changes..."
+sleep $SLEEP2
+
+n=1
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+
+echo "Using ldapsearch to read config from server $n..."
+$LDAPSEARCH -b cn=config -D cn=config -H $URI -y $CONFIGPWF \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MPR ]; do
+echo "Comparing retrieved configs from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n configs differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+n=1
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MPR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+echo "Using ldapadd to populate server 2..."
+$LDAPADD -D "$MANAGERDN" -H $URI2 -w $PASSWD -f $LDIFADD1 \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+n=1
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MPR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+echo "Using ldapadd to populate server 3..."
+$LDAPADD -D "$MANAGERDN" -H $URI3 -w $PASSWD \
+ << EOMODS >> $TESTOUT 2>&1
+dn: cn=Server 3 Test,dc=example,dc=com
+changetype: add
+objectClass: device
+cn: Server 3 Test
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server 3 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+n=1
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MPR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+echo "Using ldapmodify to add to server 1 entries that will be deleted..."
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOADDS
+dn: cn=To be deleted by server 1,dc=example,dc=com
+changetype: add
+objectClass: device
+# no distinguished values, will be added by DSA
+
+dn: cn=To be deleted by server 2,dc=example,dc=com
+changetype: add
+objectClass: device
+# no distinguished values, will be added by DSA
+
+dn: cn=To be deleted by server 3,dc=example,dc=com
+changetype: add
+objectClass: device
+# no distinguished values, will be added by DSA
+
+dn: cn=To be deleted by server 1,dc=example,dc=com
+changetype: delete
+EOADDS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+n=1
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MPR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+echo "Using ldapmodify to delete entries from server 2..."
+$LDAPMODIFY -D "$MANAGERDN" -H $URI2 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOADDS
+dn: cn=To be deleted by server 2,dc=example,dc=com
+changetype: delete
+EOADDS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapmodify to delete entries from server 3..."
+$LDAPMODIFY -D "$MANAGERDN" -H $URI3 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOADDS
+dn: cn=To be deleted by server 3,dc=example,dc=com
+changetype: delete
+EOADDS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 3 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+n=1
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MPR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+# kill!
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+kill -HUP $KILLPIDS
+
+# kill!
+# test $KILLSERVERS != no && wait
+wait
+
+echo "Restarting servers..."
+KILLPIDS=""
+
+echo "Starting server 1 on TCP/IP port $PORT1..."
+echo "======================= RESTART =======================" >> $LOG1
+cd ${XDIR}1
+$SLAPD -F slapd.d -h $URI1 -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 server 1 is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI1 \
+ '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
+
+n=2
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+LOG=$TESTDIR/slapd.$n.log
+echo "Starting server $n on TCP/IP port $PORT..."
+cd ${XDIR}$n
+echo "======================= RESTART =======================" >> $LOG
+$SLAPD -F ./slapd.d -h $URI -d $LVL >> $LOG 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+cd $TESTWD
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+echo "Using ldapsearch to check that server $n is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI \
+ '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
+n=`expr $n + 1`
+done
+
+# Insert modifications and more tests here.
+echo "Waiting $SLEEP1 seconds for servers to resync..."
+sleep $SLEEP1
+
+echo "Using ldapmodify to add/modify/delete entries from server 1..."
+for i in 1 2 3 4 5 6 7 8 9 10; do
+echo " iteration $i"
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOMODS
+dn: cn=Add-Mod-Del,dc=example,dc=com
+changetype: add
+cn: Add-Mod-Del
+objectclass: organizationalRole
+
+dn: cn=Add-Mod-Del,dc=example,dc=com
+changetype: modify
+replace: description
+description: guinea pig
+-
+
+dn: cn=Add-Mod-Del,dc=example,dc=com
+changetype: delete
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+done
+
+echo "Waiting $SLEEP1 seconds for servers to resync..."
+sleep $SLEEP1
+
+n=1
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MPR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test051-config-undo b/tests/scripts/test051-config-undo
new file mode 100755
index 0000000..56c5643
--- /dev/null
+++ b/tests/scripts/test051-config-undo
@@ -0,0 +1,117 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $UNDOCONF > $CONF1
+$SLAPADD -f $CONF1 <<EOF
+dn: o=undo
+objectClass: organization
+o: undo
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+mkdir $TESTDIR/confdir
+$SLAPD -f $CONF1 -F $TESTDIR/confdir -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 Dynamically assaulting the schema
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \
+ > $TESTOUT 2>&1 <<EOF
+dn: cn={0}core,cn=schema,cn=config
+changetype: modify
+replace: olcObjectClasses
+olcObjectClasses: ( rawr )
+-
+EOF
+RC=$?
+if test $RC != 80 ; then
+ echo "invalid objectclass modify allowed ($RC)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \
+ > $TESTOUT 2>&1 <<EOF
+dn: cn={0}core,cn=schema,cn=config
+changetype: modify
+replace: olcAttributeTypes
+olcAttributeTypes: ( rawr )
+-
+EOF
+RC=$?
+if test $RC != 80 ; then
+ echo "invalid attributeType modify allowed ($RC)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo Surveying the damage
+$LDAPMODIFY -D "cn=manager,o=undo" -w secret -H $URI1 <<EOF
+dn: o=foo,o=undo
+changetype: add
+objectClass: organization
+o: foo
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "schema destroyed by an unsuccessful operation"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test052-memberof b/tests/scripts/test052-memberof
new file mode 100755
index 0000000..afa5eb9
--- /dev/null
+++ b/tests/scripts/test052-memberof
@@ -0,0 +1,464 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $MEMBEROF = memberofno; then
+ echo "Memberof overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $TESTDIR/confdir
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $NAKEDCONF > $CONF1
+$SLAPD -f $CONF1 -F $TESTDIR/confdir -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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
+
+cat /dev/null > $TESTOUT
+
+if [ "$MEMBEROF" = memberofmod ]; then
+ echo "Inserting memberof overlay on provider..."
+ $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: ../servers/slapd/overlays
+olcModuleLoad: memberof.la
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for moduleLoad ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+
+indexInclude="" mainInclude="" nullExclude=""
+test $INDEXDB = indexdb || indexInclude="# "
+test $MAINDB = maindb || mainInclude="# "
+case $BACKEND in
+null) nullExclude="# " ;;
+esac
+
+echo "Running ldapadd to build slapd config database..."
+$LDAPADD -H $URI1 -D 'cn=config' -w `cat $CONFIGPWF` \
+ >> $TESTOUT 2>&1 <<EOF
+dn: cn=symas group example,cn=schema,cn=config
+objectClass: olcSchemaConfig
+cn: symas group example
+olcAttributeTypes: ( 1.3.6.1.4.1.4754.31.1.1
+ NAME 'memberA' SUP distinguishedName )
+olcAttributeTypes: ( 1.3.6.1.4.1.4754.31.1.2
+ NAME 'memberOfA' SUP distinguishedName )
+olcAttributeTypes: ( 1.3.6.1.4.1.4754.31.1.3
+ NAME 'memberB' SUP distinguishedName )
+olcAttributeTypes: ( 1.3.6.1.4.1.4754.31.1.4
+ NAME 'memberOfB' SUP distinguishedName )
+olcAttributeTypes: ( 1.3.6.1.4.1.4754.31.1.5
+ NAME 'memberOfC' SUP distinguishedName )
+olcObjectClasses: ( 1.3.6.1.4.1.4754.31.2.1
+ NAME 'groupA' SUP top STRUCTURAL MUST cn MAY memberA )
+olcObjectClasses: ( 1.3.6.1.4.1.4754.31.2.2
+ NAME 'groupMemberA' SUP top AUXILIARY MAY ( memberOfA $ memberOfC ) )
+olcObjectClasses: ( 1.3.6.1.4.1.4754.31.2.3
+ NAME 'groupB' SUP top STRUCTURAL MUST cn MAY memberB )
+olcObjectClasses: ( 1.3.6.1.4.1.4754.31.2.4
+ NAME 'groupMemberB' SUP top AUXILIARY MAY memberOfB )
+
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+olcSuffix: $BASEDN
+olcRootDN: cn=Manager,$BASEDN
+olcRootPW:: c2VjcmV0
+olcMonitoring: TRUE
+${nullExclude}olcDbDirectory: $TESTDIR/db.1.a/
+${indexInclude}olcDbIndex: objectClass eq
+${indexInclude}olcDbIndex: cn pres,eq,sub
+${indexInclude}olcDbIndex: uid pres,eq,sub
+${indexInclude}olcDbIndex: sn pres,eq,sub
+${mainInclude}olcDbMode: 384"
+
+dn: olcOverlay={0}memberof,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcMemberOfConfig
+olcOverlay: {0}memberof
+olcMemberOfRefInt: TRUE
+olcMemberOfGroupOC: groupOfNames
+olcMemberOfMemberAD: member
+olcMemberOfMemberOfAD: memberOf
+
+dn: olcOverlay={1}memberof,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcMemberOfConfig
+olcOverlay: {1}memberof
+olcMemberOfRefInt: TRUE
+olcMemberOfGroupOC: groupA
+olcMemberOfMemberAD: memberA
+olcMemberOfMemberOfAD: memberOfA
+
+dn: olcOverlay={2}memberof,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcMemberOfConfig
+olcOverlay: {2}memberof
+olcMemberOfRefInt: TRUE
+olcMemberOfGroupOC: groupB
+olcMemberOfMemberAD: memberB
+olcMemberOfMemberOfAD: memberOfB
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running ldapadd to build slapd database..."
+$LDAPADD -H $URI1 \
+ -D "cn=Manager,$BASEDN" -w secret \
+ >> $TESTOUT 2>&1 << EOF
+dn: $BASEDN
+objectClass: organization
+objectClass: dcObject
+o: Example, Inc.
+dc: example
+
+dn: ou=People,$BASEDN
+objectClass: organizationalUnit
+ou: People
+
+dn: ou=Groups,$BASEDN
+objectClass: organizationalUnit
+ou: Groups
+
+dn: cn=Roger Rabbit,ou=People,$BASEDN
+objectClass: inetOrgPerson
+cn: Roger Rabbit
+sn: Rabbit
+
+dn: cn=Baby Herman,ou=People,$BASEDN
+objectClass: inetOrgPerson
+cn: Baby Herman
+sn: Herman
+
+dn: cn=Cartoonia,ou=Groups,$BASEDN
+objectClass: groupOfNames
+cn: Cartoonia
+member: cn=Roger Rabbit,ou=People,$BASEDN
+member: cn=Baby Herman,ou=People,$BASEDN
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Search the entire database..."
+echo "# Search the entire database..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running ldapmodify to add a member..."
+$LDAPMODIFY -H $URI1 \
+ -D "cn=Manager,$BASEDN" -w secret \
+ >> $TESTOUT 2>&1 << EOF
+dn: cn=Jessica Rabbit,ou=People,$BASEDN
+changetype: add
+objectClass: inetOrgPerson
+cn: Jessica Rabbit
+sn: Rabbit
+
+dn: cn=Cartoonia,ou=Groups,$BASEDN
+changetype: modify
+add: member
+member: cn=Jessica Rabbit,ou=People,$BASEDN
+EOF
+
+echo "Re-search the entire database..."
+echo "# Re-search the entire database after adding Jessica Rabbit and Cartoonia..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running ldapmodify to rename a member..."
+$LDAPMODIFY -H $URI1 \
+ -D "cn=Manager,$BASEDN" -w secret \
+ >> $TESTOUT 2>&1 << EOF
+dn: cn=Baby Herman,ou=People,$BASEDN
+changetype: modrdn
+newrdn: cn=Baby Herman Jr
+deleteoldrdn: 1
+EOF
+
+echo "Re-search the entire database..."
+echo "# Re-search the entire database after renaming Baby Herman..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running ldapmodify to rename a group..."
+$LDAPMODIFY -H $URI1 \
+ -D "cn=Manager,$BASEDN" -w secret \
+ >> $TESTOUT 2>&1 << EOF
+dn: cn=Cartoonia,ou=Groups,$BASEDN
+changetype: modrdn
+newrdn: cn=Toon town
+deleteoldrdn: 1
+
+dn: cn=Toon town,ou=Groups,$BASEDN
+changetype: modrdn
+newrdn: cn=Toon Town
+deleteoldrdn: 1
+EOF
+
+echo "Re-search the entire database..."
+echo "# Re-search the entire database after renaming Cartoonia..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running ldapmodify to add self..."
+$LDAPMODIFY -H $URI1 \
+ -D "cn=Manager,$BASEDN" -w secret \
+ >> $TESTOUT 2>&1 << EOF
+dn: cn=Toon Town,ou=Groups,$BASEDN
+changetype: modify
+add: member
+member: cn=Toon Town,ou=Groups,$BASEDN
+EOF
+
+echo "Re-search the entire database..."
+echo "# Re-search the entire database after adding Toon Town to self..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running ldapdelete to remove a member..."
+$LDAPMODIFY -H $URI1 \
+ -D "cn=Manager,$BASEDN" -w secret \
+ >> $TESTOUT 2>&1 << EOF
+dn: cn=Baby Herman Jr,ou=People,$BASEDN
+changetype: delete
+EOF
+
+echo "Re-search the entire database..."
+echo "# Re-search the entire database after deleting Baby Herman..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running ldapdelete to remove a group..."
+$LDAPMODIFY -H $URI1 \
+ -D "cn=Manager,$BASEDN" -w secret \
+ >> $TESTOUT 2>&1 << EOF
+dn: cn=Toon Town,ou=Groups,$BASEDN
+changetype: delete
+EOF
+
+echo "Re-search the entire database..."
+echo "# Re-search the entire database after deleting Toon Town..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding groups with MAY member type schemas..."
+$LDAPMODIFY -H $URI1 \
+ -D "cn=Manager,$BASEDN" -w secret \
+ >> $TESTOUT 2>&1 <<EOF
+dn: cn=Roger Rabbit,ou=People,$BASEDN
+changetype: delete
+
+dn: cn=Jessica Rabbit,ou=People,$BASEDN
+changetype: delete
+
+dn: cn=person1,ou=People,$BASEDN
+changetype: add
+objectClass: person
+objectClass: groupMemberA
+objectClass: groupMemberB
+cn: person1
+sn: person1
+
+dn: cn=person2,ou=People,$BASEDN
+changetype: add
+objectClass: person
+objectClass: groupMemberA
+objectClass: groupMemberB
+cn: person2
+sn: person2
+
+dn: cn=group1,ou=Groups,$BASEDN
+changetype: add
+objectclass: groupA
+cn: group1
+memberA: cn=person1,ou=People,$BASEDN
+memberA: cn=person2,ou=People,$BASEDN
+
+dn: cn=group2,ou=Groups,$BASEDN
+changetype: add
+objectclass: groupB
+cn: group2
+memberB: cn=person1,ou=People,$BASEDN
+memberB: cn=person2,ou=People,$BASEDN
+
+dn: cn=group1,ou=Groups,$BASEDN
+changetype: modify
+delete: memberA
+
+EOF
+
+echo "Re-search the entire database..."
+echo "# Re-search the entire database after adding groups with MAY member type schemas..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running ldapmodify to reconfigure the schema used..."
+$LDAPADD -H $URI1 -D 'cn=config' -w `cat $CONFIGPWF` \
+ >> $TESTOUT 2>&1 <<EOF
+dn: olcOverlay={1}memberof,olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+replace: olcMemberOfMemberOfAD
+olcMemberOfMemberOfAD: memberOfC
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Updating groups to expose the new setting..."
+$LDAPMODIFY -H $URI1 \
+ -D "cn=Manager,$BASEDN" -w secret \
+ >> $TESTOUT 2>&1 <<EOF
+dn: cn=group1,ou=Groups,$BASEDN
+changetype: modify
+add: memberA
+memberA: cn=person1,ou=People,$BASEDN
+memberA: cn=person2,ou=People,$BASEDN
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Re-search the entire database..."
+echo "# Re-search the entire database after updating memberof configuration..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$MEMBEROFOUT
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test053-syncprov-glue b/tests/scripts/test053-syncprov-glue
new file mode 100755
index 0000000..3caa0d4
--- /dev/null
+++ b/tests/scripts/test053-syncprov-glue
@@ -0,0 +1,517 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+# This script tests a bug where syncprov used on a glue database
+# with a subordinate syncrepl consumer database looses a read-lock
+# on the glue suffix entry when a modification is received on the
+# syncrepl consumer. The bug is only triggered when there is an
+# active syncrepl consumers of the glue suffix entry.
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+if test $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+PRODDIR=$TESTDIR/prod
+PRO2DIR=$TESTDIR/pro2
+CONSDIR=$TESTDIR/cons
+CFPROD=$PRODDIR/slapd.d
+CFPRO2=$PRO2DIR/slapd.d
+CFCONS=$CONSDIR/slapd.d
+
+mkdir -p $TESTDIR
+mkdir -p $PRODDIR $CFPROD $PRODDIR/db $PRODDIR/ou1
+mkdir -p $PRO2DIR $CFPRO2 $PRO2DIR/db
+mkdir -p $CONSDIR $CFCONS $CONSDIR/db
+
+cd $TESTDIR
+
+KILLPIDS=
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+if test x"$SYNCMODE" = x ; then
+ SYNCMODE=rp
+fi
+case "$SYNCMODE" in
+ ro)
+ SYNCTYPE="type=refreshOnly interval=00:00:00:03"
+ ;;
+ rp)
+ SYNCTYPE="type=refreshAndPersist"
+ ;;
+ *)
+ echo "unknown sync mode $SYNCMODE"
+ exit 1;
+ ;;
+esac
+
+echo "Initializing provider configurations..."
+$SLAPADD -F $CFPROD -n 0 <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+olcServerID: 1
+
+dn: olcDatabase={0}config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW:< file://$CONFIGPWF
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Initializing provider2 configurations..."
+$SLAPADD -F $CFPRO2 -n 0 <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+
+dn: olcDatabase={0}config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW:< file://$CONFIGPWF
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+$SLAPADD -F $CFCONS -n 0 <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+
+dn: olcDatabase={0}config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW:< file://$CONFIGPWF
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting provider slapd on TCP/IP port $PORT1..."
+cd $PRODDIR
+$SLAPD -F slapd.d -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI1 \
+ '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 "Starting provider2 slapd on TCP/IP port $PORT2..."
+cd $PRO2DIR
+$SLAPD -F slapd.d -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI2 \
+ '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 "Starting consumer slapd on TCP/IP port $PORT3..."
+cd $CONSDIR
+$SLAPD -F slapd.d -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI3 \
+ '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
+
+for uri in $URI1 $URI2 $URI3; do
+ echo "Adding schema on $uri..."
+ $LDAPADD -D cn=config -H $uri -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
+
+ [ "$BACKENDTYPE" = mod ] || continue
+
+ echo "Adding backend module on $uri..."
+ $LDAPADD -D cn=config -H $uri -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 module ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+done
+
+echo "Adding databases on provider..."
+if [ "$SYNCPROV" = syncprovmod ]; then
+ $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+olcModuleLoad: syncprov.la
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for moduleLoad ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+
+nullExclude="" nullOK=""
+test $BACKEND = null && nullExclude="# " nullOK="OK"
+
+$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: $PRODDIR/db
+olcSuffix: $BASEDN
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for provider database config1 ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcOverlay={0}glue,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+olcOverlay: {0}glue
+
+dn: olcOverlay={1}syncprov,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: {1}syncprov
+
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: $PRODDIR/ou1
+olcSubordinate: TRUE
+olcSuffix: ou=ou1,$BASEDN
+olcRootDN: $MANAGERDN
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for provider database config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding databases on provider2..."
+if [ "$SYNCPROV" = syncprovmod ]; then
+ $LDAPADD -D cn=config -H $URI2 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+olcModuleLoad: syncprov.la
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for moduleLoad ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+
+$LDAPADD -D cn=config -H $URI2 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: $PRO2DIR/db
+olcSuffix: $BASEDN
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+
+dn: olcOverlay={0}syncprov,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: {0}syncprov
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for provider database config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding databases on consumer..."
+$LDAPADD -D cn=config -H $URI3 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: $CONSDIR/db
+olcSuffix: $BASEDN
+olcRootDN: $MANAGERDN
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for consumer database config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Populating provider..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: dc=example,dc=com
+objectClass: top
+objectClass: organization
+objectClass: dcObject
+dc: example
+o: Example, Inc
+
+dn: ou=ou1,dc=example,dc=com
+objectClass: top
+objectClass: organizationalUnit
+ou: ou1
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed to populate provider entry ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Populating provider2..."
+$LDAPADD -D "$MANAGERDN" -H $URI2 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: dc=example,dc=com
+objectClass: top
+objectClass: organization
+objectClass: dcObject
+dc: example
+o: Example, Inc
+
+dn: ou=ou1,dc=example,dc=com
+objectClass: top
+objectClass: organizationalUnit
+ou: ou1
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed to populate provider entry ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding syncrepl on provider..."
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+add: olcSyncRepl
+olcSyncRepl: rid=1 provider=$URI2 searchbase="ou=ou1,$BASEDN"
+ binddn="$MANAGERDN" bindmethod=simple credentials=$PASSWD
+ $SYNCTYPE retry="3 5 300 5" timeout=1
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed to add syncrepl consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding syncrepl consumer on consumer..."
+$LDAPMODIFY -D cn=config -H $URI3 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+add: olcSyncRepl
+olcSyncRepl: rid=1 provider=$URI1 searchbase="$BASEDN"
+ binddn="$MANAGERDN" bindmethod=simple credentials=$PASSWD
+ $SYNCTYPE retry="3 5 300 5" timeout=1
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed to add syncrepl consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check that consumer received changes..."
+RC=32
+for i in 0 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI3 \
+ -s base -b "ou=ou1,$BASEDN" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapmodify to modify provider2..."
+$LDAPADD -D "$MANAGERDN" -H $URI2 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=ou1,dc=example,dc=com
+changetype: modify
+add: description
+description: Modify1
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+sleep 1
+
+echo "Using ldapsearch to check that consumer received changes..."
+RC=32
+for i in 0 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI3 \
+ -s base -b "ou=ou1,$BASEDN" \
+ '(description=Modify1)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapmodify to modify glue suffix on provider..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: dc=example,dc=com
+changetype: modify
+add: description
+description: Test1
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed to modify suffix ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+test "$lock_bug" = 2 && exit 2
+
+echo ">>>>> Test succeeded"
+
+exit 0
diff --git a/tests/scripts/test054-syncreplication-parallel-load b/tests/scripts/test054-syncreplication-parallel-load
new file mode 100755
index 0000000..98644c9
--- /dev/null
+++ b/tests/scripts/test054-syncreplication-parallel-load
@@ -0,0 +1,377 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR4
+
+#
+# Test replication:
+# - start provider
+# - start consumer
+# - populate over ldap
+# - perform some modifies and deleted
+# - attempt to modify the consumer (referral or chain)
+# - retrieve database over ldap and compare against expected results
+#
+
+echo "Starting provider slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $SRPROVIDERCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Using ldapadd to create the context prefix entry in the provider..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDEREDCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting consumer slapd on TCP/IP port $PORT4..."
+. $CONFFILTER $BACKEND < $P1SRCONSUMERCONF > $CONF4
+$SLAPD -f $CONF4 -h $URI4 -d $LVL > $LOG4 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI4 \
+ '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
+
+MORELDIF=$TESTDIR/more.ldif
+TESTOUT1=$TESTDIR/testout1.out
+TESTOUT2=$TESTDIR/testout2.out
+sed -e 's/[Oo][Uu]=/ou=More /g' -e 's/^[Oo][Uu]: /ou: More /' \
+ -e 's/cn=Manager/cn=More Manager/g' \
+ -e 's/^cn: Manager/cn: More Manager/' \
+ $LDIFORDEREDNOCP > $MORELDIF
+
+echo "Using ldapadd to populate the provider directory..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDEREDNOCP > $TESTOUT1 2>&1 &
+C1PID=$!
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $MORELDIF > $TESTOUT2 2>&1 &
+C2PID=$!
+wait $C1PID $C2PID
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Stopping the provider, sleeping 10 seconds and restarting it..."
+kill -HUP "$PID"
+wait $PID
+sleep 10
+echo "RESTART" >> $LOG1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL >> $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Waiting 10 seconds to let the system catch up"
+sleep 10
+
+echo "Using ldapmodify to modify provider directory..."
+
+#
+# Do some modifications
+#
+
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+changetype: modify
+add: drink
+drink: Orange Juice
+-
+delete: sn
+sn: Jones
+-
+add: sn
+sn: Jones
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: drink
+drink: Iced Tea
+
+dn: cn=ITD Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: uniquemember
+uniquemember: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+uniquemember: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+-
+add: uniquemember
+uniquemember: cn=Dorothy Stevens, ou=Alumni Association, ou=People, dc=example,dc=com
+uniquemember: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: description
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+cn: Gern Jensen
+sn: Jensen
+uid: gjensen
+title: Chief Investigator, ITD
+postaladdress: ITD $ 535 W. William St $ Ann Arbor, MI 48103
+seealso: cn=All Staff, ou=Groups, dc=example,dc=com
+drink: Coffee
+homepostaladdress: 844 Brown St. Apt. 4 $ Ann Arbor, MI 48104
+description: Very odd
+facsimiletelephonenumber: +1 313 555 7557
+telephonenumber: +1 313 555 8343
+mail: gjensen@mailgw.example.com
+homephone: +1 313 555 8844
+
+dn: ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: organizationalUnit
+ou: Retired
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+cn: Rosco P. Coltrane
+sn: Coltrane
+uid: rosco
+description: Fat tycoon
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Rosco P. Coltrane
+deleteoldrdn: 1
+newsuperior: ou=Retired, ou=People, dc=example,dc=com
+
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: delete
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldappasswd to change some passwords..."
+$LDAPPASSWD -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ 'cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com' \
+ > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Stopping consumer to test recovery..."
+kill -HUP $CONSUMERPID
+wait $CONSUMERPID
+
+echo "Modifying more entries on the provider..."
+$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Rosco P. Coltrane, ou=Retired, ou=People, dc=example,dc=com
+changetype: delete
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+add: drink
+drink: Mad Dog 20/20
+
+dn: cn=Rosco P. Coltrane, ou=Retired, ou=People, dc=example,dc=com
+changetype: add
+objectclass: OpenLDAPperson
+sn: Coltrane
+uid: rosco
+cn: Rosco P. Coltrane
+
+EOMODS
+
+echo "Restarting consumer..."
+echo "RESTART" >> $LOG4
+$SLAPD -f $CONF4 -h $URI4 -d $LVL >> $LOG4 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$PID $CONSUMERPID"
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+if test ! $BACKLDAP = "ldapno" ; then
+ echo "Try updating the consumer slapd..."
+ $LDAPMODIFY -v -D "$MANAGERDN" -H $URI4 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example, dc=com
+changetype: modify
+add: description
+description: This write must fail because directed to a shadow context,
+description: unless the chain overlay is configured appropriately ;)
+
+EOMODS
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ # ITS#4964
+ echo "Trying to change some passwords on the consumer..."
+ $LDAPPASSWD -D "$MANAGERDN" -H $URI4 -w $PASSWD \
+ 'cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com' \
+ > $TESTOUT 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+fi
+
+OPATTRS="entryUUID creatorsName createTimestamp modifiersName modifyTimestamp"
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectclass=*)' '*' $OPATTRS > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI4 \
+ '(objectclass=*)' '*' $OPATTRS > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo "Filtering provider results..."
+$LDIFFILTER < $PROVIDEROUT > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER < $CONSUMEROUT > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test055-valregex b/tests/scripts/test055-valregex
new file mode 100755
index 0000000..326dee2
--- /dev/null
+++ b/tests/scripts/test055-valregex
@@ -0,0 +1,117 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+LVL=acl
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $VALREGEXCONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing attribute value regex substitution..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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
+
+cat /dev/null > $SEARCHOUT
+
+echo "# Try an attribute vale regex that match, but substitute does not"
+echo "# this should fail"
+$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com
+changetype: modify
+replace: sn
+sn: foobarbuz
+EOMODS
+RC=$?
+case $RC in
+50)
+ echo "ldapmodify failed as expected"
+ ;;
+0)
+ if test $BACKEND != null ; then
+ echo "ldapmodify should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "# Try an attribute vale regex that match and substitute does"
+echo "# this should succeed"
+$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com
+changetype: modify
+replace: sn
+sn: James A Jones 1
+EOMODS
+RC=$?
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+case $RC in
+0)
+ echo "ldapmodify succeed as expected"
+ ;;
+*)
+ echo "ldapmodify failed ($RC)!"
+ exit $RC
+ ;;
+esac
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test056-monitor b/tests/scripts/test056-monitor
new file mode 100755
index 0000000..0c5241f
--- /dev/null
+++ b/tests/scripts/test056-monitor
@@ -0,0 +1,162 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Starting slapd on TCP/IP port $PORT..."
+. $CONFFILTER $BACKEND < $SCHEMACONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+echo "Using ldapsearch to read connection monitor entries..."
+$LDAPSEARCH -S "" -b "$CONNECTIONSMONITORDN" -H $URI1 \
+ 'objectclass=*' \
+ structuralObjectClass entryDN \
+ monitorConnectionProtocol monitorConnectionOpsReceived \
+ monitorConnectionOpsExecuting monitorConnectionOpsPending \
+ monitorConnectionOpsCompleted monitorConnectionGet \
+ monitorConnectionRead monitorConnectionWrite \
+ monitorConnectionMask monitorConnectionAuthzDN \
+ monitorConnectionListener monitorConnectionLocalAddress \
+ > $SEARCHOUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Compare results, ignoring possible difference of IPv4/IPv6 localhost address
+localrewrite='s/=127\.0\.0\.1:/=LOCAL:/; s/=\[::1\]:/=LOCAL:/'
+echo "Filtering ldapsearch results..."
+sed -e "$localrewrite" < $SEARCHOUT | $LDIFFILTER > $SEARCHFLT
+echo "Filtering expected data..."
+. $CONFFILTER < $MONITOROUT1 | sed -e "$localrewrite" | $LDIFFILTER > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - connection monitor output is not correct"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Using ldapsearch to read database monitor entries..."
+$LDAPSEARCH -S "" -b "$DATABASESMONITORDN" -H $URI1 \
+ 'objectclass=*' \
+ structuralObjectClass entryDN namingContexts readOnly \
+ monitorIsShadow monitorContext \
+ > $SEARCHOUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER -b monitor < $SEARCHOUT > $SEARCHFLT
+
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $MONITOROUT2 > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - database monitor output is not correct"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Using ldapsearch to read statistics monitor entries..."
+$LDAPSEARCH -S "" -b "$STATISTICSMONITORDN" -H $URI1 \
+ '(|(cn=Entries)(cn=PDU)(cn=Referrals))' \
+ structuralObjectClass monitorCounter entryDN \
+ > $SEARCHOUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER -b monitor < $SEARCHOUT > $SEARCHFLT
+
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $MONITOROUT3 > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - statistics monitor output is not correct"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Using ldapsearch to read operation monitor entries..."
+$LDAPSEARCH -S "" -b "$OPERATIONSMONITORDN" -H $URI1 \
+ 'objectclass=*' \
+ structuralObjectClass monitorOpInitiated monitorOpCompleted entryDN \
+ > $SEARCHOUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER -b monitor < $SEARCHOUT > $SEARCHFLT
+
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $MONITOROUT4 > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - operations monitor output is not correct"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
+
diff --git a/tests/scripts/test057-memberof-refint b/tests/scripts/test057-memberof-refint
new file mode 100755
index 0000000..c30a4c1
--- /dev/null
+++ b/tests/scripts/test057-memberof-refint
@@ -0,0 +1,280 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 The OpenLDAP Foundation.
+## Portions Copyright 2008 Red Hat, Inc.
+## 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 $MEMBEROF = memberofno; then
+ echo "Memberof overlay not available, test skipped"
+ exit 0
+fi
+
+if test $REFINT = refintno; then
+ echo "Referential Integrity overlay not available, test skipped"
+ exit 0
+fi
+
+if test $BACKEND = wt ; then
+ echo "back-wt does not support subtree rename"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $TESTDIR/confdir
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $NAKEDCONF > $CONF1
+$SLAPD -f $CONF1 -F $TESTDIR/confdir -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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
+
+cat /dev/null > $TESTOUT
+
+indexInclude="" mainInclude="" nullExclude=""
+test $INDEXDB = indexdb || indexInclude="# "
+test $MAINDB = maindb || mainInclude="# "
+case $BACKEND in
+null) nullExclude="# " ;;
+esac
+
+if [ "$MEMBEROF" = memberofmod ]; then
+ echo "Inserting memberof overlay on provider..."
+ $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: ../servers/slapd/overlays
+olcModuleLoad: memberof.la
+olcModuleLoad: refint.la
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for moduleLoad ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+
+echo "Running ldapadd to build slapd config database..."
+$LDAPADD -H $URI1 -D 'cn=config' -w `cat $CONFIGPWF` \
+ >> $TESTOUT 2>&1 <<EOF
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+olcSuffix: $BASEDN
+olcRootDN: cn=Manager,$BASEDN
+olcRootPW:: c2VjcmV0
+olcMonitoring: TRUE
+${nullExclude}olcDbDirectory: $TESTDIR/db.1.a/
+${indexInclude}olcDbIndex: objectClass eq
+${indexInclude}olcDbIndex: cn pres,eq,sub
+${indexInclude}olcDbIndex: uid pres,eq,sub
+${indexInclude}olcDbIndex: sn pres,eq,sub
+${mainInclude}olcDbMode: 384
+
+# {0}memberof, {1}$BACKEND, config
+dn: olcOverlay={0}memberof,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcMemberOfConfig
+olcOverlay: {0}memberof
+olcMemberOfRefInt: TRUE
+olcMemberOfGroupOC: groupOfNames
+olcMemberOfMemberAD: member
+olcMemberOfMemberOfAD: memberOf
+
+# {1}refint, {1}$BACKEND, config
+dn: olcOverlay={1}refint,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcRefintConfig
+olcOverlay: {1}refint
+olcRefintAttribute: member
+olcRefintAttribute: memberOf
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running ldapadd to build slapd database..."
+$LDAPADD -H $URI1 \
+ -D "cn=Manager,$BASEDN" -w secret \
+ >> $TESTOUT 2>&1 << EOF
+dn: $BASEDN
+objectClass: organization
+objectClass: dcObject
+o: Example, Inc.
+dc: example
+
+dn: ou=People,$BASEDN
+objectClass: organizationalUnit
+ou: People
+
+dn: ou=Groups,$BASEDN
+objectClass: organizationalUnit
+ou: Groups
+
+dn: cn=Roger Rabbit,ou=People,$BASEDN
+objectClass: inetOrgPerson
+cn: Roger Rabbit
+sn: Rabbit
+
+dn: cn=Baby Herman,ou=People,$BASEDN
+objectClass: inetOrgPerson
+cn: Baby Herman
+sn: Herman
+
+dn: cn=Cartoonia,ou=Groups,$BASEDN
+objectClass: groupOfNames
+cn: Cartoonia
+member: cn=Roger Rabbit,ou=People,$BASEDN
+member: cn=Baby Herman,ou=People,$BASEDN
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Search the entire database..."
+echo "# Search the entire database..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running ldapmodify to rename subtree..."
+$LDAPMODIFY -H $URI1 \
+ -D "cn=Manager,$BASEDN" -w secret \
+ >> $TESTOUT 2>&1 << EOF
+dn: ou=People,$BASEDN
+changetype: modrdn
+newrdn: ou=Toons
+deleteoldrdn:1
+newsuperior: $BASEDN
+EOF
+
+# refint runs in a background thread, so it most likely won't complete
+# before the modify returns. Give it some time to execute.
+sleep $SLEEP0
+
+echo "Re-search the entire database..."
+echo "# Re-search the entire database..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running ldapmodify to rename subtree..."
+$LDAPMODIFY -H $URI1 \
+ -D "cn=Manager,$BASEDN" -w secret \
+ >> $TESTOUT 2>&1 << EOF
+dn: ou=Groups,$BASEDN
+changetype: modrdn
+newrdn: ou=Studios
+deleteoldrdn:1
+newsuperior: $BASEDN
+EOF
+
+sleep $SLEEP0
+
+echo "Re-search the entire database..."
+echo "# Re-search the entire database..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running ldapdelete to remove a member..."
+$LDAPMODIFY -H $URI1 \
+ -D "cn=Manager,$BASEDN" -w secret \
+ >> $TESTOUT 2>&1 << EOF
+dn: cn=Baby Herman,ou=Toons,$BASEDN
+changetype: delete
+EOF
+
+sleep $SLEEP0
+
+echo "Re-search the entire database..."
+echo "# Re-search the entire database..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ '(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$MEMBEROFREFINTOUT
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test058-syncrepl-asymmetric b/tests/scripts/test058-syncrepl-asymmetric
new file mode 100755
index 0000000..f950761
--- /dev/null
+++ b/tests/scripts/test058-syncrepl-asymmetric
@@ -0,0 +1,2483 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+# This script tests a configuration scenario as described in these URLs:
+#
+# http://www.openldap.org/lists/openldap-devel/200806/msg00041.html
+# http://www.openldap.org/lists/openldap-devel/200806/msg00054.html
+#
+# Search for "TEST:" to find each major test this script performs.
+
+# The configuration here consist of 3 "sites", each with a "provider" and
+# a "search" server. One of the sites is the "central", the other two
+# are called "site1" and "site2".
+
+# The following notations are used in variable names below to identify
+# these servers, the first number defines the $URL# and $PORT# variable
+# that server uses:
+#
+# 1: SMC_* Site Provider Central
+# 2: SM1_* Site Provider 1
+# 3: SM2_* Site Provider 2
+# 4: SSC_* Search Site Central
+# 5: SS1_* Search Site 1
+# 6: SS2_* Search Site 2
+
+# The provider servers all have a set of subordinate databases glued below
+# the same suffix database. Each of the providers are the provider for at
+# least one of these subordinate databases, but there are never more
+# than one provider for any single database. I.e, this is neither a
+# traditional single-provider configuration, nor what most people think
+# of as multi-provider, but more what can be called multiple providers.
+
+# The central provider replicates to the two other providers, and receives
+# updates from them of the backends they are the provider for. There is
+# no direct connection between the other two provider servers. All of the
+# providers have the syncprov overlay configured on the glue database.
+
+# The search servers replicates from the provider server at their site.
+# They all have a single database with the glue suffix, but their
+# database configuration doesn't matter much in this test. (This
+# database layout was originally created before gluing was introduced
+# in OpenLDAP, which is why the search servers doesn't use it).
+
+# The primary objective for gluing the backend databases is not to make
+# them look like one huge database but to create a common search suffix
+# for the clients. Searching is mostly done on the search servers, only
+# updates are done on the providers.
+
+# It varies which backends that are replicated to which server (hence
+# the name asymmetric in this test). Access control rules on the
+# providers are used to control what their consumers receives. The table
+# below gives an overview of which backend (the columns) that are
+# replicated to which server (the rows). A "M" defines the provider for
+# the backend, a "S" is a replica, and "-" means it is not replicated
+# there. Oh, the table probably looks wrong without the 4-position
+# tab-stops OpenLDAP uses...
+
+# glue ou1 ou2 sm1ou1 sm1ou2 sm2ou1 sm2ou2
+# smc M M M S S S -
+# sm1 S S - M M - -
+# sm2 S S S S - M M
+# ssc S S - - S - -
+# ss1 S S - S S - -
+# ss2 S S S - - S S
+
+# On the central provider syncrepl is configured on the subordinate
+# databases, as it varies which backends that exists on its providers.
+# Had it been used on the glue database then syncrepl would have removed
+# the backends replicated from site1 but not present on site2 when it
+# synchronizes with site2 (and vice versa).
+#
+# All the other servers uses syncrepl on the glue database, since
+# replicating more than one subordinate database from the same provider
+# creates (as of the writing of this test script) race conditions that
+# causes the replication to fail, as the race tests at the end shows.
+
+# The databases controlled by syncrepl all have $UPDATEDN as their
+# RootDN, while the provider servers has other RootDN values for the
+# backends they are the backend for them self. This violates the current
+# guidelines for gluing databases, which states that the same rootdn
+# should be used on all of them. Unfortunately, this cannot be done on
+# site providers 1 and 2. The backends they manage locally are either not
+# present on the central provider, or when so they are not replicated back
+# to their source, which causes syncrepl to try to remove the content of
+# these backends when it synchronizes with the central provider. The
+# differing rootdn values used on the backends controlled by syncrepl
+# and those managed locally prevents it from succeeding in this. As
+# noted above, moving syncrepl to the subordinate databases is currently
+# not an option since that creates race conditions.
+
+# The binddn values used in the syncrepl configurations are chosen to
+# make the configuration and access control rules easiest to set up. It
+# occasionally uses a DN that is also used as a RootDN. This is not a
+# good practice and should not be taken as an example for real
+# configurations!
+
+# This script will print the content of any invalid contextCSN values it
+# detects if the environment variable CSN_VERBOSE is non-empty. The
+# environment variable RACE_TESTS can be set to the number of race test
+# iterations the script should perform.
+
+if test "$BACKEND" = ldif ; then
+ echo "$BACKEND backend does not support access controls, test skipped"
+ exit 0
+fi
+
+echo "Test 058 is currently disabled"
+exit 0
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+if test $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+SMC_DIR=$TESTDIR/smc
+SM1_DIR=$TESTDIR/sm1
+SM2_DIR=$TESTDIR/sm2
+SS1_DIR=$TESTDIR/ss1
+SS2_DIR=$TESTDIR/ss2
+SSC_DIR=$TESTDIR/ssc
+
+MNUM=1
+
+mkdir -p $TESTDIR
+
+for dir in $SMC_DIR $SM1_DIR $SM2_DIR $SS1_DIR $SS2_DIR $SSC_DIR; do
+ mkdir -p $dir $dir/slapd.d $dir/db
+done
+
+mkdir -p $SMC_DIR/ou1 $SMC_DIR/sm1ou1 $SMC_DIR/sm1ou2
+mkdir -p $SMC_DIR/ou2 $SMC_DIR/sm2ou1
+mkdir -p $SM1_DIR/ou1 $SM1_DIR/sm1ou1 $SM1_DIR/sm1ou2
+mkdir -p $SM2_DIR/ou2 $SM2_DIR/sm1ou1 $SM2_DIR/sm2ou1 $SM2_DIR/sm2ou2
+
+cd $TESTDIR
+
+KILLPIDS=
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+ID=1
+
+if test $WAIT != 0 ; then
+ RETRY="1 60"
+else
+ RETRY="1 10"
+fi
+
+echo "Initializing provider configurations..."
+for dir in $SMC_DIR $SM1_DIR $SM2_DIR; do
+ $SLAPADD -F $dir/slapd.d -n 0 <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+olcServerID: $ID
+
+dn: olcDatabase={0}config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW:< file://$CONFIGPWF
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+ fi
+
+ ID=`expr $ID + 1`
+done
+
+echo "Initializing search configurations..."
+for dir in $SS1_DIR $SS2_DIR $SSC_DIR; do
+ $SLAPADD -F $dir/slapd.d -n 0 <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+
+dn: olcDatabase={0}config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW:< file://$CONFIGPWF
+
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+done
+
+echo "Starting central provider slapd on TCP/IP port $PORT1..."
+cd $SMC_DIR
+$SLAPD -F slapd.d -h $URI1 -d $LVL > $LOG1 2>&1 &
+SMC_PID=$!
+if test $WAIT != 0 ; then
+ echo PID $SMC_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $SMC_PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that central provider slapd is running..."
+for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting site1 provider slapd on TCP/IP port $PORT2..."
+cd $SM1_DIR
+$SLAPD -F slapd.d -h $URI2 -d $LVL > $LOG2 2>&1 &
+SM1_PID=$!
+if test $WAIT != 0 ; then
+ echo PID $SM1_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $SM1_PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that site1 provider is running..."
+for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting site2 provider slapd on TCP/IP port $PORT3..."
+cd $SM2_DIR
+$SLAPD -F slapd.d -h $URI3 -d $LVL > $LOG3 2>&1 &
+SM2_PID=$!
+if test $WAIT != 0 ; then
+ echo PID $SM2_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $SM2_PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that site2 provider is running..."
+for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI3 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting central search slapd on TCP/IP port $PORT4..."
+cd $SSC_DIR
+$SLAPD -F slapd.d -h $URI4 -d $LVL > $LOG4 2>&1 &
+SSC_PID=$!
+if test $WAIT != 0 ; then
+ echo PID $SSC_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $SSC_PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that central search slapd is running..."
+for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI4 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+
+echo "Starting site1 search slapd on TCP/IP port $PORT5..."
+cd $SS1_DIR
+$SLAPD -F slapd.d -h $URI5 -d $LVL > $LOG5 2>&1 &
+SS1_PID=$!
+if test $WAIT != 0 ; then
+ echo PID $SS1_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $SS1_PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that site1 search slapd is running..."
+for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI5 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+
+echo "Starting site2 search slapd on TCP/IP port $PORT6..."
+cd $SS2_DIR
+$SLAPD -F slapd.d -h $URI6 -d $LVL > $LOG6 2>&1 &
+SS2_PID=$!
+if test $WAIT != 0 ; then
+ echo PID $SS2_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $SS2_PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that site2 search slapd is running..."
+for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI6 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+for uri in $URI1 $URI2 $URI3 $URI4 $URI5 $URI6; do
+ echo "Adding schema on $uri..."
+ $LDAPADD -D cn=config -H $uri -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
+
+ [ "$BACKENDTYPE" = mod ] || continue
+
+ echo "Adding backend module on $uri..."
+ $LDAPADD -D cn=config -H $uri -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 module ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+done
+
+echo "Adding database config on central provider..."
+if [ "$SYNCPROV" = syncprovmod ]; then
+ $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+olcModuleLoad: syncprov.la
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for moduleLoad ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+
+nullExclude="" nullOK="" wantNoObj=32
+test $BACKEND = null && nullExclude="# " nullOK="OK" wantNoObj=0
+
+$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: $SMC_DIR/db
+olcSuffix: $BASEDN
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+
+dn: olcOverlay={0}glue,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+olcOverlay: {0}glue
+
+dn: olcOverlay={1}syncprov,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: {1}syncprov
+olcSpCheckpoint: 3 1
+
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: $SMC_DIR/ou1
+olcSubordinate: TRUE
+olcSuffix: ou=ou1,$BASEDN
+olcRootDN: $MANAGERDN
+
+dn: olcDatabase={2}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {2}$BACKEND
+${nullExclude}olcDbDirectory: $SMC_DIR/ou2
+olcSubordinate: TRUE
+olcSuffix: ou=ou2,$BASEDN
+olcRootDN: $MANAGERDN
+
+dn: olcDatabase={3}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {3}$BACKEND
+${nullExclude}olcDbDirectory: $SMC_DIR/sm1ou1
+olcSubordinate: TRUE
+olcSuffix: ou=sm1ou1,$BASEDN
+olcRootDN: $UPDATEDN
+
+dn: olcDatabase={4}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {4}$BACKEND
+${nullExclude}olcDbDirectory: $SMC_DIR/sm1ou2
+olcSubordinate: TRUE
+olcSuffix: ou=sm1ou2,$BASEDN
+olcRootDN: $UPDATEDN
+
+dn: olcDatabase={5}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {5}$BACKEND
+${nullExclude}olcDbDirectory: $SMC_DIR/sm2ou1
+olcSubordinate: TRUE
+olcSuffix: ou=sm2ou1,$BASEDN
+olcRootDN: $UPDATEDN
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for central provider database config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding database config on site1 provider..."
+if [ "$SYNCPROV" = syncprovmod ]; then
+ $LDAPADD -D cn=config -H $URI2 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+olcModuleLoad: syncprov.la
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for moduleLoad ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+
+$LDAPADD -D cn=config -H $URI2 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: $SM1_DIR/db
+olcSuffix: $BASEDN
+olcRootDN: $UPDATEDN
+
+dn: olcOverlay={0}glue,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+olcOverlay: {0}glue
+
+dn: olcOverlay={1}syncprov,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: {1}syncprov
+
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: $SM1_DIR/ou1
+olcSubordinate: TRUE
+olcSuffix: ou=ou1,$BASEDN
+olcRootDN: $UPDATEDN
+
+dn: olcDatabase={2}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {2}$BACKEND
+${nullExclude}olcDbDirectory: $SM1_DIR/sm1ou1
+olcSubordinate: TRUE
+olcSuffix: ou=sm1ou1,$BASEDN
+olcRootDN: ou=sm1ou1,$BASEDN
+olcRootPW: $PASSWD
+
+dn: olcDatabase={3}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {3}$BACKEND
+${nullExclude}olcDbDirectory: $SM1_DIR/sm1ou2
+olcSubordinate: TRUE
+olcSuffix: ou=sm1ou2,$BASEDN
+olcRootDN: ou=sm1ou1,$BASEDN
+
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for site1 provider database config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding database config on site2 provider..."
+if [ "$SYNCPROV" = syncprovmod ]; then
+ $LDAPADD -D cn=config -H $URI3 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+olcModuleLoad: syncprov.la
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for moduleLoad ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+
+$LDAPADD -D cn=config -H $URI3 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: $SM2_DIR/db
+olcSuffix: $BASEDN
+olcRootDN: $UPDATEDN
+
+dn: olcOverlay={0}glue,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+olcOverlay: {0}glue
+
+dn: olcOverlay={1}syncprov,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: {1}syncprov
+olcSpCheckpoint: 1 1
+
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: $SM2_DIR/ou2
+olcSubordinate: TRUE
+olcSuffix: ou=ou2,$BASEDN
+olcRootDN: $UPDATEDN
+
+dn: olcDatabase={2}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {2}$BACKEND
+${nullExclude}olcDbDirectory: $SM2_DIR/sm1ou1
+olcSubordinate: TRUE
+olcSuffix: ou=sm1ou1,$BASEDN
+olcRootDN: $UPDATEDN
+
+dn: olcDatabase={3}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {3}$BACKEND
+${nullExclude}olcDbDirectory: $SM2_DIR/sm2ou1
+olcSubordinate: TRUE
+olcSuffix: ou=sm2ou1,$BASEDN
+olcRootDN: ou=sm2ou1,$BASEDN
+olcRootPW: $PASSWD
+
+dn: olcDatabase={4}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {4}$BACKEND
+${nullExclude}olcDbDirectory: $SM2_DIR/sm2ou2
+olcSubordinate: TRUE
+olcSuffix: ou=sm2ou2,$BASEDN
+olcRootDN: ou=sm2ou1,$BASEDN
+
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for site2 provider database config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding access rules on central provider..."
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={-1}frontend,cn=config
+changetype: modify
+add: olcAccess
+olcAccess: to dn.exact=dc=example,dc=com
+ by * read
+olcAccess: to dn.subtree=ou=ou1,dc=example,dc=com
+ by * read
+olcAccess: to dn.subtree=ou=ou2,dc=example,dc=com
+ by dn.exact=ou=ou1,dc=example,dc=com none
+ by dn.exact=ou=ou2,dc=example,dc=com read
+ by dn.exact=dc=example,dc=com none
+ by * read
+olcAccess: to dn.subtree=ou=sm1ou1,dc=example,dc=com
+ by dn.exact=ou=ou1,dc=example,dc=com none
+ by dn.exact=ou=ou2,dc=example,dc=com read
+ by dn.exact=dc=example,dc=com none
+ by * read
+olcAccess: to dn.subtree=ou=sm1ou2,dc=example,dc=com
+ by dn.exact=ou=ou1,dc=example,dc=com none
+ by dn.exact=ou=ou2,dc=example,dc=com none
+ by dn.exact=dc=example,dc=com read
+ by * read
+olcAccess: to dn.subtree=ou=sm2ou1,dc=example,dc=com
+ by dn.exact=ou=ou1,dc=example,dc=com none
+ by dn.exact=ou=ou2,dc=example,dc=com none
+ by dn.exact=dc=example,dc=com none
+ by * read
+olcAccess: to * by * read
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for central provider access config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding access rules on site1 provider..."
+$LDAPMODIFY -D cn=config -H $URI2 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={-1}frontend,cn=config
+changetype: modify
+add: olcAccess
+olcAccess: to dn.subtree=dc=example,dc=com
+ by * read
+olcAccess: to * by * read
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for site1 provider access config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding access rules on site2 provider..."
+$LDAPMODIFY -D cn=config -H $URI3 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={-1}frontend,cn=config
+changetype: modify
+add: olcAccess
+olcAccess: to dn.exact=dc=example,dc=com
+ by * read
+olcAccess: to dn.subtree=ou=ou2,dc=example,dc=com
+ by * read
+olcAccess: to dn.subtree=ou=sm1ou1,dc=example,dc=com
+ by users none
+ by * read
+olcAccess: to dn.subtree=ou=sm2ou1,dc=example,dc=com
+ by * read
+olcAccess: to dn.subtree=ou=sm2ou2,dc=example,dc=com
+ by dn.exact=dc=example,dc=com read
+ by users none
+ by * read
+olcAccess: to * by * read
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for site2 provider access config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding database config on central search..."
+$LDAPADD -D cn=config -H $URI4 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: $SSC_DIR/db
+olcSuffix: $BASEDN
+olcRootDN: $UPDATEDN
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for central search database config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding database config on site1 search..."
+$LDAPADD -D cn=config -H $URI5 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: $SS1_DIR/db
+olcSuffix: $BASEDN
+olcRootDN: $UPDATEDN
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for site1 search database config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding database config on site2 search..."
+$LDAPADD -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: $SS2_DIR/db
+olcSuffix: $BASEDN
+olcRootDN: $UPDATEDN
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for site2 search database config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Populating central provider..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: dc=example,dc=com
+objectClass: top
+objectClass: organization
+objectClass: dcObject
+dc: example
+o: Example, Inc
+userPassword: $PASSWD
+
+dn: ou=ou1,dc=example,dc=com
+objectClass: top
+objectClass: organizationalUnit
+ou: ou1
+userPassword: $PASSWD
+
+dn: ou=ou2,dc=example,dc=com
+objectClass: top
+objectClass: organizationalUnit
+ou: ou2
+userPassword: $PASSWD
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed to populate central provider entry ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding syncrepl on site1 provider..."
+$LDAPMODIFY -D cn=config -H $URI2 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={4}$BACKEND,cn=config
+changetype: modify
+add: olcSyncRepl
+olcSyncRepl: rid=1 provider=$URI1 searchbase="$BASEDN"
+ binddn="ou=ou1,$BASEDN" bindmethod=simple credentials=$PASSWD
+ type=refreshAndPersist retry="$RETRY" timeout=1
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed to add syncrepl on site1 provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding syncrepl on site2 provider..."
+$LDAPMODIFY -D cn=config -H $URI3 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={5}$BACKEND,cn=config
+changetype: modify
+add: olcSyncRepl
+olcSyncRepl: rid=1 provider=$URI1 searchbase="$BASEDN"
+ binddn="ou=ou2,$BASEDN" bindmethod=simple credentials=$PASSWD
+ type=refreshAndPersist retry="$RETRY" timeout=1
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed to add syncrepl on site2 provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+sleep 1
+
+echo "Using ldapsearch to check that site1 provider received changes..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI2 \
+ -s base -b "ou=ou1,$BASEDN" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check that site2 provider received changes..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI3 \
+ -s base -b "ou=ou1,$BASEDN" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+sleep 1
+
+echo "Populating site1 provider..."
+$LDAPADD -D "ou=sm1ou1,$BASEDN" -H $URI2 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=sm1ou1,dc=example,dc=com
+objectClass: top
+objectClass: organizationalUnit
+ou: sm1ou1
+
+dn: ou=sm1ou2,dc=example,dc=com
+objectClass: top
+objectClass: organizationalUnit
+ou: sm1ou2
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed to populate site1 provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+sleep 1
+
+echo "Populating site2 provider..."
+$LDAPADD -D "ou=sm2ou1,$BASEDN" -H $URI3 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=sm2ou1,dc=example,dc=com
+objectClass: top
+objectClass: organizationalUnit
+ou: sm2ou1
+
+dn: ou=sm2ou2,dc=example,dc=com
+objectClass: top
+objectClass: organizationalUnit
+ou: sm2ou2
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed to populate site2 provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ERRORS=0
+
+# TEST:
+# Stop site1 provider when adding syncrepl to the central provider. When
+# site1 provider is started again both it and the central provider will have
+# the same number of contextCSN values, but the ones on central provider
+# will be the newest. The central provider will not update its contextCSN
+# values unless the bug in ITS#5597 have been fixed.
+echo "Stopping site1 provider..."
+kill -HUP "$SM1_PID"
+wait "$SM1_PID"
+KILLPIDS=`echo "$KILLPIDS " | sed -e "s/ $SM1_PID / /"`;
+SM1_PID=
+
+echo "Adding syncrepl on central provider..."
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={3}$BACKEND,cn=config
+changetype: modify
+add: olcSyncRepl
+olcSyncRepl: rid=3 provider=$URI2 searchbase="ou=sm1ou1,$BASEDN"
+ binddn="ou=sm1ou1,$BASEDN" bindmethod=simple credentials=$PASSWD
+ type=refreshAndPersist retry="$RETRY" timeout=1
+
+dn: olcDatabase={5}$BACKEND,cn=config
+changetype: modify
+add: olcSyncRepl
+olcSyncRepl: rid=5 provider=$URI3 searchbase="ou=sm2ou1,$BASEDN"
+ binddn="ou=sm2ou1,$BASEDN" bindmethod=simple credentials=$PASSWD
+ type=refreshAndPersist retry="$RETRY" timeout=1
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed to add syncrepl on central provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+sleep 1
+echo "Using ldapsearch to check that central provider received site2 entries..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI1 \
+ -s base -b "ou=sm2ou1,$BASEDN" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Test for ITS#6716, modify on central provider to ensure that the CSN
+# order is "sid2 < sid3 < sid1". When site1 provider starts it is likely
+# to sync with central provider before it syncs with site1 provider. When
+# central provider syncs with site1 provider they will share the sid1 and
+# sid3 CSNs, the additional sid2 CSN hold by site1 provider will be the
+# oldest. Central provider will not receive the changes made on site1
+# provider unless it completely ignores the CSNs presented by central
+# provider.
+echo "Using ldapmodify to modify central provider..."
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: dc=example,dc=com
+changetype: modify
+add: description
+description: Modify$MNUM
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+if test -z "$SM1_PID" ; then
+ echo "Restarting site1 provider slapd on TCP/IP port $PORT2..."
+ cd $SM1_DIR
+ $SLAPD -F slapd.d -h $URI2 -d $LVL >> $LOG2 2>&1 &
+ SM1_PID=$!
+ if test $WAIT != 0 ; then
+ echo PID $SM1_PID
+ read foo
+ fi
+ KILLPIDS="$KILLPIDS $SM1_PID"
+ cd $TESTWD
+ sleep 1
+fi
+sleep 1
+echo "Using ldapsearch to check that site1 provider is running..."
+for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check that central provider received site1 entries..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI1 \
+ -s base -b "ou=sm1ou1,$BASEDN" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check that site1 provider received central provider update..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI2 \
+ -s base -b "$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check that site2 provider received central provider update..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI3 \
+ -s base -b "$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Test done, now some more initialization...
+
+echo "Adding syncrepl consumer on central search..."
+$LDAPMODIFY -D cn=config -H $URI4 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+add: olcSyncRepl
+olcSyncRepl: rid=1 provider=$URI1 searchbase="$BASEDN"
+ binddn="$BASEDN" bindmethod=simple credentials=$PASSWD
+ type=refreshAndPersist retry="$RETRY" timeout=1
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed to add syncrepl on site1 search ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding syncrepl consumer on site1 search..."
+$LDAPMODIFY -D cn=config -H $URI5 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+add: olcSyncRepl
+olcSyncRepl: rid=1 provider=$URI2 searchbase="$BASEDN"
+ binddn="$BASEDN" bindmethod=simple credentials=$PASSWD
+ type=refreshAndPersist retry="$RETRY" timeout=1
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed to add syncrepl on site1 search ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding syncrepl consumer on site2 search..."
+$LDAPMODIFY -D cn=config -H $URI6 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+changetype: modify
+add: olcSyncRepl
+olcSyncRepl: rid=1 provider=$URI3 searchbase="$BASEDN"
+ binddn="$BASEDN" bindmethod=simple credentials=$PASSWD
+ type=refreshAndPersist retry="$RETRY" timeout=1
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed to add syncrepl on site2 search ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+sleep 1
+
+echo "Using ldapsearch to check that central search received changes..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI4 \
+ -s base -b "$BASEDN" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check that site1 search received changes..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI5 \
+ -s base -b "$BASEDN" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check that site2 search received changes..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI6 \
+ -s base -b "$BASEDN" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Create a script that will check the contextCSN values of all servers,
+# and restart them to re-synchronize if it finds any errors:
+cat > $TESTDIR/checkcsn.sh <<'EOF'
+#!/bin/sh
+
+CSN_ERRORS=0
+
+CSN1=`$LDAPSEARCH -H $URI1 -b $BASEDN -s base contextCSN | grep contextCSN | sort`
+CSN2=`$LDAPSEARCH -H $URI2 -b $BASEDN -s base contextCSN | grep contextCSN | sort`
+CSN3=`$LDAPSEARCH -H $URI3 -b $BASEDN -s base contextCSN | grep contextCSN | sort`
+CSN4=`$LDAPSEARCH -H $URI4 -b $BASEDN -s base contextCSN | grep contextCSN | sort`
+CSN5=`$LDAPSEARCH -H $URI5 -b $BASEDN -s base contextCSN | grep contextCSN | sort`
+CSN6=`$LDAPSEARCH -H $URI6 -b $BASEDN -s base contextCSN | grep contextCSN | sort`
+
+if test -z "$CSN1" ; then
+ echo "ERROR: contextCSN empty on central provider"
+ CSN_ERRORS=`expr $CSN_ERRORS + 1`
+fi
+nCSN=`echo "$CSN1" | wc -l`
+if test "$nCSN" -ne 3 ; then
+ echo "ERROR: Wrong contextCSN count on central provider, should be 3"
+ CSN_ERRORS=`expr $CSN_ERRORS + 1`
+ if test -n "$CSN_VERBOSE"; then
+ echo "$CSN1"
+ fi
+fi
+if test -z "$CSN2" -o "$CSN1" != "$CSN2" ; then
+ echo "ERROR: contextCSN mismatch between central provider and site1 provider"
+ CSN_ERRORS=`expr $CSN_ERRORS + 1`;
+ if test -n "$CSN_VERBOSE"; then
+ echo "contextCSN on central provider:"
+ echo "$CSN1"
+ echo "contextCSN on site1 provider:"
+ echo "$CSN2"
+ fi
+fi
+if test -z "$CSN3" -o "$CSN1" != "$CSN3" ; then
+ echo "ERROR: contextCSN mismatch between central provider and site2 provider"
+ CSN_ERRORS=`expr $CSN_ERRORS + 1`;
+ if test -n "$CSN_VERBOSE"; then
+ echo "contextCSN on central provider:"
+ echo "$CSN1"
+ echo "contextCSN on site2 provider:"
+ echo "$CSN3"
+ fi
+fi
+if test -z "$CSN4" -o "$CSN1" != "$CSN4" ; then
+ echo "ERROR: contextCSN mismatch between central provider and central search"
+ CSN_ERRORS=`expr $CSN_ERRORS + 1`;
+ if test -n "$CSN_VERBOSE"; then
+ echo "contextCSN on central provider:"
+ echo "$CSN1"
+ echo "contextCSN on central search:"
+ echo "$CSN4"
+ fi
+fi
+if test -z "$CSN5" -o "$CSN2" != "$CSN5" ; then
+ echo "ERROR: contextCSN mismatch between site1 provider and site1 search"
+ CSN_ERRORS=`expr $CSN_ERRORS + 1`;
+ if test -n "$CSN_VERBOSE"; then
+ echo "contextCSN on site1 provider:"
+ echo "$CSN2"
+ echo "contextCSN on site1 search:"
+ echo "$CSN5"
+ fi
+fi
+if test -z "$CSN6" -o "$CSN3" != "$CSN6" ; then
+ echo "ERROR: contextCSN mismatch between site2 provider and site2 search:"
+ CSN_ERRORS=`expr $CSN_ERRORS + 1`;
+ if test -n "$CSN_VERBOSE"; then
+ echo "contextCSN on site2 provider:"
+ echo "$CSN3"
+ echo "contextCSN on site2 search:"
+ echo "$CSN6"
+ fi
+fi
+
+if test $CSN_ERRORS != 0 ; then
+ echo "Stopping all servers to synchronize contextCSN..."
+ kill -HUP $KILLPIDS
+ for pid in $KILLPIDS ; do wait $pid ; done
+ KILLPIDS=
+
+ echo "Restarting site1 provider slapd on TCP/IP port $PORT2..."
+ cd $SM1_DIR
+ $SLAPD -F slapd.d -h $URI2 -d $LVL >> $LOG2 2>&1 &
+ SM1_PID=$!
+ if test $WAIT != 0 ; then
+ echo PID $SM1_PID
+ read foo
+ fi
+ KILLPIDS="$KILLPIDS $SM1_PID"
+ cd $TESTWD
+ sleep 1
+ echo "Using ldapsearch to check that site1 provider is running..."
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Restarting site2 provider slapd on TCP/IP port $PORT3..."
+ cd $SM2_DIR
+ $SLAPD -F slapd.d -h $URI3 -d $LVL >> $LOG3 2>&1 &
+ SM2_PID=$!
+ if test $WAIT != 0 ; then
+ echo PID $SM2_PID
+ read foo
+ fi
+ KILLPIDS="$KILLPIDS $SM2_PID "
+ cd $TESTWD
+ sleep 1
+ echo "Using ldapsearch to check that site2 provider is running..."
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI3 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Restarting central provider slapd on TCP/IP port $PORT1..."
+ cd $SMC_DIR
+ $SLAPD -F slapd.d -h $URI1 -d $LVL >> $LOG1 2>&1 &
+ SMC_PID=$!
+ if test $WAIT != 0 ; then
+ echo PID $SMC_PID
+ read foo
+ fi
+ KILLPIDS="$KILLPIDS $SMC_PID"
+ cd $TESTWD
+ sleep 1
+ echo "Using ldapsearch to check that central provider slapd is running..."
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Sleeping 5 seconds to allow contextCSN to synchronize..."
+ sleep 5
+
+ echo "Stopping site1 and site2 provider..."
+ kill -HUP $SM1_PID $SM2_PID
+ for pid in $SM1_PID $SM2_PID ; do wait $pid ; done
+ KILLPIDS=" $SMC_PID"
+
+ echo "Restarting site1 provider slapd on TCP/IP port $PORT2..."
+ cd $SM1_DIR
+ $SLAPD -F slapd.d -h $URI2 -d $LVL >> $LOG2 2>&1 &
+ SM1_PID=$!
+ if test $WAIT != 0 ; then
+ echo PID $SM1_PID
+ read foo
+ fi
+ KILLPIDS="$KILLPIDS $SM1_PID"
+ cd $TESTWD
+ sleep 1
+ echo "Using ldapsearch to check that site1 provider is running..."
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Restarting site2 provider slapd on TCP/IP port $PORT3..."
+ cd $SM2_DIR
+ $SLAPD -F slapd.d -h $URI3 -d $LVL >> $LOG3 2>&1 &
+ SM2_PID=$!
+ if test $WAIT != 0 ; then
+ echo PID $SM2_PID
+ read foo
+ fi
+ KILLPIDS="$KILLPIDS $SM2_PID"
+ cd $TESTWD
+ sleep 1
+ echo "Using ldapsearch to check that site2 provider is running..."
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI3 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Sleeping 5 seconds to allow contextCSN to synchronize..."
+ sleep 5
+
+ echo "Restarting central search slapd on TCP/IP port $PORT4..."
+ cd $SSC_DIR
+ $SLAPD -F slapd.d -h $URI4 -d $LVL >> $LOG4 2>&1 &
+ SSC_PID=$!
+ if test $WAIT != 0 ; then
+ echo PID $SSC_PID
+ read foo
+ fi
+ KILLPIDS="$KILLPIDS $SSC_PID"
+ cd $TESTWD
+ sleep 1
+ echo "Using ldapsearch to check that central search slapd is running..."
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI4 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Restarting site1 search slapd on TCP/IP port $PORT5..."
+ cd $SS1_DIR
+ $SLAPD -F slapd.d -h $URI5 -d $LVL >> $LOG5 2>&1 &
+ SS1_PID=$!
+ if test $WAIT != 0 ; then
+ echo PID $SS1_PID
+ read foo
+ fi
+ KILLPIDS="$KILLPIDS $SS1_PID"
+ cd $TESTWD
+ sleep 1
+ echo "Using ldapsearch to check that site1 search slapd is running..."
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI5 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Restarting site2 search slapd on TCP/IP port $PORT6..."
+ cd $SS2_DIR
+ $SLAPD -F slapd.d -h $URI6 -d $LVL >> $LOG6 2>&1 &
+ SS2_PID=$!
+ if test $WAIT != 0 ; then
+ echo PID $SS2_PID
+ read foo
+ fi
+ KILLPIDS="$KILLPIDS $SS2_PID"
+ cd $TESTWD
+ sleep 1
+ echo "Using ldapsearch to check that site2 search slapd is running..."
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI6 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Sleeping 5 seconds to allow contextCSN to synchronize..."
+ sleep 5
+
+ echo "Checking contextCSN after restart..."
+ CSN1=`$LDAPSEARCH -H $URI1 -b $BASEDN -s base contextCSN | grep contextCSN | sort`
+ CSN2=`$LDAPSEARCH -H $URI2 -b $BASEDN -s base contextCSN | grep contextCSN | sort`
+ CSN3=`$LDAPSEARCH -H $URI3 -b $BASEDN -s base contextCSN | grep contextCSN | sort`
+ CSN4=`$LDAPSEARCH -H $URI4 -b $BASEDN -s base contextCSN | grep contextCSN | sort`
+ CSN5=`$LDAPSEARCH -H $URI5 -b $BASEDN -s base contextCSN | grep contextCSN | sort`
+ CSN6=`$LDAPSEARCH -H $URI6 -b $BASEDN -s base contextCSN | grep contextCSN | sort`
+ if test -z "$CSN1" ; then
+ echo "ERROR: contextCSN empty on central provider"
+ CSN_ERRORS=`expr $CSN_ERRORS + 1`
+ fi
+
+ if test -z "$CSN2" -o "$CSN1" != "$CSN2" ; then
+ echo "ERROR: contextCSN mismatch between central provider and site1 provider"
+ CSN_ERRORS=`expr $CSN_ERRORS + 1`;
+ if test -n "$CSN_VERBOSE"; then
+ echo "contextCSN on central provider:"
+ echo "$CSN1"
+ echo "contextCSN on site1 provider:"
+ echo "$CSN2"
+ fi
+ fi
+ if test -z "$CSN3" -o "$CSN1" != "$CSN3" ; then
+ echo "ERROR: contextCSN mismatch between central provider and site2 provider"
+ CSN_ERRORS=`expr $CSN_ERRORS + 1`;
+ if test -n "$CSN_VERBOSE"; then
+ echo "contextCSN on central provider:"
+ echo "$CSN1"
+ echo "contextCSN on site2 provider:"
+ echo "$CSN3"
+ fi
+ fi
+ if test -z "$CSN4" -o "$CSN1" != "$CSN4" ; then
+ echo "ERROR: contextCSN mismatch between central provider and central search"
+ CSN_ERRORS=`expr $CSN_ERRORS + 1`;
+ if test -n "$CSN_VERBOSE"; then
+ echo "contextCSN on central provider:"
+ echo "$CSN1"
+ echo "contextCSN on central search:"
+ echo "$CSN4"
+ fi
+ fi
+ if test -z "$CSN5" -o "$CSN2" != "$CSN5" ; then
+ echo "ERROR: contextCSN mismatch between site1 provider and site1 search"
+ CSN_ERRORS=`expr $CSN_ERRORS + 1`;
+ if test -n "$CSN_VERBOSE"; then
+ echo "contextCSN on site1 provider:"
+ echo "$CSN2"
+ echo "contextCSN on site1 search:"
+ echo "$CSN5"
+ fi
+ fi
+ if test -z "$CSN6" -o "$CSN3" != "$CSN6" ; then
+ echo "ERROR: contextCSN mismatch between site2 provider and site2 search:"
+ CSN_ERRORS=`expr $CSN_ERRORS + 1`;
+ if test -n "$CSN_VERBOSE"; then
+ echo "contextCSN on site2 provider:"
+ echo "$CSN3"
+ echo "contextCSN on site2 search:"
+ echo "$CSN6"
+ fi
+ fi
+fi
+
+ERRORS=`expr $ERRORS + $CSN_ERRORS`
+
+EOF
+
+test $BACKEND = null && echo : > $TESTDIR/checkcsn.sh
+
+chmod +x $TESTDIR/checkcsn.sh
+
+
+echo "Checking contextCSN after initial replication..."
+. $TESTDIR/checkcsn.sh
+
+# TEST:
+# Test that updates to the first backend on central provider, which should
+# be replicated to all servers actually is so, and that the contextCSN is
+# updated everywhere:
+echo "Using ldapmodify to modify first backend on central provider..."
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=ou1,dc=example,dc=com
+changetype: modify
+add: description
+description: Modify$MNUM
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+sleep 1
+
+echo "Using ldapsearch to check replication to central search..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI4 \
+ -s base -b "ou=ou1,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check replication to site1 search..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI5 \
+ -s base -b "ou=ou1,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check replication to site2 search..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI6 \
+ -s base -b "ou=ou1,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Checking contextCSN after modify of first backend on central provider..."
+. $TESTDIR/checkcsn.sh
+
+# TEST:
+# Test that updates to the second backend on central provider is only
+# replicated to those search servers that should receive that backend.
+# The contextCSN should still be updated everywhere:
+MNUM=`expr $MNUM + 1`
+echo "Using ldapmodify to modify second backend on central provider..."
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=ou2,dc=example,dc=com
+changetype: modify
+add: description
+description: Modify$MNUM
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+sleep 1
+
+echo "Using ldapsearch to check replication to site2 search..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI6 \
+ -s base -b "ou=ou2,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check no replication to site1 provider..."
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI2 \
+ -s base -b "ou=ou2,$BASEDN" \
+ "(description=Modify$NMUM)" 2>&1 | awk '/^dn:/ {print "NOK"}'`
+ if test "x$RESULT" = "xNOK" ; then
+ echo "Change was replicated to site1 search!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ sleep 1
+done
+
+echo "Using ldapsearch to check no replication to central search..."
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI4 \
+ -s base -b "ou=ou2,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "NOK"}'`
+ if test "x$RESULT" = "xNOK" ; then
+ echo "Change was replicated to central search!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ sleep 1
+done
+
+echo "Checking contextCSN after modify of second backend on central provider..."
+. $TESTDIR/checkcsn.sh
+
+# TEST:
+# Test that updates to the first backend on site1 provider, which should be
+# replicated everywhere except to central and site2 search. The contextCSN
+# should be updated on all servers:
+MNUM=`expr $MNUM + 1`
+echo "Using ldapmodify to modify first backend on site1 provider..."
+$LDAPMODIFY -D "ou=sm1ou1,$BASEDN" -H $URI2 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=sm1ou1,dc=example,dc=com
+changetype: modify
+add: description
+description: Modify$MNUM
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+sleep 1
+
+echo "Using ldapsearch to check replication to site1 search..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI5 \
+ -s base -b "ou=sm1ou1,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check replication to site2 provider..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI3 \
+ -s base -b "ou=sm1ou1,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check no replication to site2 search..."
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI6 \
+ -s base -b "ou=sm1ou2,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "NOK"}'`
+ if test "x$RESULT" = "xNOK" ; then
+ echo "Change was replicated to central search!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ sleep 1
+done
+
+echo "Using ldapsearch to check no replication to central search..."
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI4 \
+ -s base -b "ou=sm1ou2,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "NOK"}'`
+ if test "x$RESULT" = "xNOK" ; then
+ echo "Change was replicated to central search!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ sleep 1
+done
+
+echo "Checking contextCSN after modify of first backend on site1 provider..."
+. $TESTDIR/checkcsn.sh
+
+
+# TEST:
+# Test updates to the second backend on site1 provider, which should only be
+# replicated to site1 search. The contextCSN should be updated everywhere.
+MNUM=`expr $MNUM + 1`
+echo "Using ldapmodify to modify second backend on site1 provider..."
+$LDAPMODIFY -D "ou=sm1ou1,$BASEDN" -H $URI2 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=sm1ou2,dc=example,dc=com
+changetype: modify
+add: description
+description: Modify$MNUM
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+sleep 1
+
+
+echo "Using ldapsearch to check replication to site1 search..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI5 \
+ -s base -b "ou=sm1ou2,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check no replication to central provider..."
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI1 \
+ -s base -b "ou=sm1ou2,$BASEDN" \
+ "(description=Modify$NMUM)" 2>&1 | awk '/^dn:/ {print "NOK"}'`
+ if test "x$RESULT" = "xNOK" ; then
+ echo "Change was replicated to site2 search!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ sleep 1
+done
+
+echo "Checking contextCSN after modify of second backend on site1 provider..."
+. $TESTDIR/checkcsn.sh
+
+
+# TEST:
+# Test updates to first backend on site2 provider, which should be
+# replicated to the central servers, but not site1. The contextCSN
+# should be updated everywhere:
+MNUM=`expr $MNUM + 1`
+echo "Using ldapmodify to modify first backend on site2 provider..."
+$LDAPMODIFY -D "ou=sm2ou1,$BASEDN" -H $URI3 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=sm2ou1,dc=example,dc=com
+changetype: modify
+add: description
+description: Modify$MNUM
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+sleep 1
+
+echo "Using ldapsearch to check replication to central provider..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI1 \
+ -s base -b "ou=sm2ou1,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check replication to site2 search..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI6 \
+ -s base -b "ou=sm2ou1,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check no replication to site1 provider..."
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI2 \
+ -s base -b "ou=sm2ou1,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "NOK"}'`
+ if test "x$RESULT" = "xNOK" ; then
+ echo "Change was replicated to site2 search!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ sleep 1
+done
+
+echo "Using ldapsearch to check no replication to central search..."
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI4 \
+ -s base -b "ou=sm2ou1,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "NOK"}'`
+ if test "x$RESULT" = "xNOK" ; then
+ echo "Change was replicated to site2 search!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ sleep 1
+done
+
+echo "Checking contextCSN after modify of first backend on site2 provider..."
+. $TESTDIR/checkcsn.sh
+
+
+# TEST:
+# Test updates to the second backend on site2 provider, which should only be
+# replicated to site2 search. As always, contextCSN should be updated
+# everywhere:
+MNUM=`expr $MNUM + 1`
+echo "Using ldapmodify to modify second backend on site2 provider..."
+$LDAPMODIFY -D "ou=sm2ou1,$BASEDN" -H $URI3 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=sm2ou2,dc=example,dc=com
+changetype: modify
+add: description
+description: Modify$MNUM
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+sleep 1
+
+echo "Using ldapsearch to check replication to site2 search..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI6 \
+ -s base -b "ou=sm2ou2,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check no replication to central provider..."
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI4 \
+ -s base -b "ou=sm2ou2,$BASEDN" \
+ "(description=Modify$MNUM)" 2>&1 | awk '/^dn:/ {print "NOK"}'`
+ if test "x$RESULT" = "xNOK" ; then
+ echo "Change was replicated to central search!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ sleep 1
+done
+
+echo "Checking contextCSN after modify of second backend on site2 provider..."
+. $TESTDIR/checkcsn.sh
+
+# TEST:
+# Test that all contextCSN values are updated on the replicas when they
+# starts with an empty database. Start site2 provider first, then site2
+# search and finally central provider so that the site2 search's syncrepl
+# connection has been set up when site2 provider receives the database:
+echo "Stopping central provider and site2 servers to test start with empty db..."
+kill -HUP $SMC_PID $SM2_PID $SS2_PID
+for pid in $SMC_PID $SM2_PID $SS2_PID; do wait $pid ; done
+KILLPIDS=`echo "$KILLPIDS " | sed -e "s/ $SMC_PID / /"`;
+KILLPIDS=`echo "$KILLPIDS " | sed -e "s/ $SM2_PID / /"`;
+KILLPIDS=`echo "$KILLPIDS " | sed -e "s/ $SS2_PID / /"`;
+SMC_PID=
+SM2_PID=
+SS2_PID=
+rm -rf $SM2_DIR/db/*
+rm -rf $SS2_DIR/db/*
+
+echo "Starting site2 provider slapd on TCP/IP port $PORT3..."
+cd $SM2_DIR
+$SLAPD -F slapd.d -h $URI3 -d $LVL >> $LOG3 2>&1 &
+SM2_PID=$!
+if test $WAIT != 0 ; then
+ echo PID $SM2_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $SM2_PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that site2 provider slapd is running..."
+for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI3 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting site2 search slapd on TCP/IP port $PORT6..."
+cd $SS2_DIR
+$SLAPD -F slapd.d -h $URI6 -d $LVL >> $LOG6 2>&1 &
+SS2_PID=$!
+if test $WAIT != 0 ; then
+ echo PID $SS2_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $SS2_PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that site2 search slapd is running..."
+for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI6 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting central provider slapd on TCP/IP port $PORT1..."
+cd $SMC_DIR
+$SLAPD -F slapd.d -h $URI1 -d $LVL >> $LOG1 2>&1 &
+SMC_PID=$!
+if test $WAIT != 0 ; then
+ echo PID $SMC_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $SMC_PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that central provider slapd is running..."
+for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check that site2 provider received base..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI3 \
+ -s base -b "$BASEDN" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to check that site2 search received base..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI6 \
+ -s base -b "$BASEDN" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+sleep $SLEEP1
+
+echo "Checking contextCSN after site2 servers repopulated..."
+. $TESTDIR/checkcsn.sh
+
+if test $ERRORS -ne 0; then
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ echo "Found $ERRORS errors"
+ exit $ERRORS
+fi
+
+# TEST:
+# Adding syncrepl of the second site1 provider backend on central provider
+# will not initialize the database unless the contextCSN attribute is
+# stored in the suffix of the database and not the suffix of the glue
+# database:
+echo "Adding syncrepl of second site1 provider backend on central provider..."
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcDatabase={4}$BACKEND,cn=config
+changetype: modify
+add: olcSyncRepl
+olcSyncRepl: rid=4 provider=$URI2 searchbase="ou=sm1ou2,$BASEDN"
+ binddn="ou=sm1ou1,$BASEDN" bindmethod=simple credentials=$PASSWD
+ type=refreshAndPersist retry="$RETRY" timeout=1
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed to add syncrepl on central provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+sleep 1
+
+echo "Using ldapsearch to check that central provider received second site1 backend..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI1 \
+ -s base -b "ou=sm1ou2,$BASEDN" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ERROR: Second site1 backend not replicated to central provider"
+ ERRORS=`expr $ERRORS + 1`
+
+ echo "Restarting central provider slapd on TCP/IP port $PORT1..."
+ kill -HUP $SMC_PID
+ wait $SMC_PID
+ KILLPIDS=`echo "$KILLPIDS " | sed -e "s/ $SMC_PID / /"`;
+
+ cd $SMC_DIR
+ $SLAPD -F slapd.d -h $URI1 -c rid=4,csn=0 -d $LVL >> $LOG1 2>&1 &
+ SMC_PID=$!
+ if test $WAIT != 0 ; then
+ echo PID $SMC_PID
+ read foo
+ fi
+ KILLPIDS="$KILLPIDS $SMC_PID"
+ cd $TESTWD
+ echo "Using ldapsearch to check that central provider slapd is running..."
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to check that central provider received second site1 backend..."
+ RC=32
+ for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI1 \
+ -s base -b "ou=sm1ou2,$BASEDN" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+
+echo "Using ldapsearch to check that central search received second site1 backend..."
+RC=32
+for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI4 \
+ -s base -b "ou=sm1ou2,$BASEDN" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ERROR: Second site1 backend not replicated to central search"
+ ERRORS=`expr $ERRORS + 1`
+
+ echo "Restarting central search slapd on TCP/IP port $PORT4..."
+ kill -HUP $SSC_PID
+ wait $SSC_PID
+ KILLPIDS=`echo "$KILLPIDS " | sed -e "s/ $SSC_PID / /"`;
+
+ cd $SSC_DIR
+ $SLAPD -F slapd.d -h $URI4 -c rid=1,csn=0 -d $LVL >> $LOG4 2>&1 &
+ SSC_PID=$!
+ if test $WAIT != 0 ; then
+ echo PID $SSC_PID
+ read foo
+ fi
+ KILLPIDS="$KILLPIDS $SSC_PID"
+ cd $TESTWD
+ echo "Using ldapsearch to check that central search slapd is running..."
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI4 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Using ldapsearch to check that central search received second site1 backend..."
+ RC=32
+ for i in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI4 \
+ -s base -b "ou=sm1ou2,$BASEDN" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $i seconds for syncrepl to receive changes..."
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+
+
+# TEST:
+# Run race tests when more than one backend is replicated from the same
+# provider. This will usually fail long before 100 iterations unless
+# syncrepl stores the contextCSN in the suffix of its own database, and
+# that syncprov follows these rules before updating its own CSN when it
+# detects updates from syncrepl:
+# 1) A contextCSN value must have been stored in the suffix of all the
+# syncrepl configured databases within the glued syncprov database.
+# 2) Of all contextCSN values stored by syncrepl with the same SID,
+# syncprov must always select the one with the lowest csn value.
+test -z "$RACE_TESTS" && RACE_TESTS=10
+RACE_NUM=0
+RACE_ERROR=0
+
+SUB_DN=ou=sub,ou=sm1ou2,dc=example,dc=com
+
+while test $RACE_ERROR -eq 0 -a $RACE_NUM -lt $RACE_TESTS ; do
+ RACE_NUM=`expr $RACE_NUM + 1`
+ echo "Running $RACE_NUM of $RACE_TESTS syncrepl race tests..."
+
+ echo "Stopping central provider..."
+ kill -HUP $SMC_PID
+ wait $SMC_PID
+ KILLPIDS=`echo "$KILLPIDS " | sed -e "s/ $SMC_PID / /"`;
+
+ MNUM=`expr $MNUM + 1`
+ echo "Using ldapadd to add entry on site1 provider..."
+ $LDAPADD -D "ou=sm1ou1,$BASEDN" -H $URI2 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: $SUB_DN
+objectClass: top
+objectClass: organizationalUnit
+ou: sub
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Starting central provider again..."
+ cd $SMC_DIR
+ $SLAPD -F slapd.d -h $URI1 -d $LVL >> $LOG1 2>&1 &
+ SMC_PID=$!
+ KILLPIDS="$KILLPIDS $SMC_PID"
+ cd $TESTWD
+ echo "Using ldapsearch to check that central provider received entry..."
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$SUB_DN" -H $URI1 > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ERROR: entry not replicated to central provider!"
+ RACE_ERROR=1
+ break
+ fi
+
+ echo "Using ldapsearch to check that central search received entry..."
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$SUB_DN" -H $URI4 > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ERROR: entry not replicated to central provider!"
+ RACE_ERROR=1
+ break
+ fi
+
+ echo "Stopping central provider..."
+ kill -HUP $SMC_PID
+ wait $SMC_PID
+ KILLPIDS=`echo "$KILLPIDS " | sed -e "s/ $SMC_PID / /"`;
+
+ echo "Using ldapdelete to delete entry on site1 provider..."
+ $LDAPDELETE -D "ou=sm1ou1,$BASEDN" -H $URI2 -w $PASSWD "$SUB_DN"
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapdelete failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Starting central provider again..."
+ cd $SMC_DIR
+ $SLAPD -F slapd.d -h $URI1 -d $LVL >> $LOG1 2>&1 &
+ SMC_PID=$!
+ KILLPIDS="$KILLPIDS $SMC_PID"
+ cd $TESTWD
+
+ echo "Using ldapsearch to check that entry was deleted on central provider..."
+ RC=0
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$SUB_DN" -H $URI1 > /dev/null 2>&1
+ RC=$?
+ if test $RC = $wantNoObj; then break; fi
+ sleep $i
+ done
+
+ if test $RC != $wantNoObj; then
+ if test $RC != 0; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ echo "ERROR: Entry not removed on central provider!"
+ RACE_ERROR=1
+ break
+ fi
+
+ echo "Using ldapsearch to check that entry was deleted on central search..."
+ RC=0
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$SUB_DN" -H $URI4 > /dev/null 2>&1
+ RC=$?
+ if test $RC != 0; then break; fi
+ sleep $i
+ done
+
+ if test $RC != $wantNoObj; then
+ echo "ERROR: Entry not removed on central search! (RC=$RC)"
+ RACE_ERROR=1
+ break
+ fi
+done
+
+if test $RACE_ERROR != 0; then
+ echo "Race error found after $RACE_NUM of $RACE_TESTS iterations"
+ ERRORS=`expr $ERRORS + $RACE_ERROR`
+else
+ echo "No race errors found after $RACE_TESTS iterations"
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $ERRORS -ne 0; then
+ echo "Found $ERRORS errors"
+ echo ">>>>>> Exiting with a false success status for now"
+ exit 0
+fi
+
+echo ">>>>> Test succeeded"
+
+exit 0
diff --git a/tests/scripts/test059-consumer-config b/tests/scripts/test059-consumer-config
new file mode 100755
index 0000000..30e87e4
--- /dev/null
+++ b/tests/scripts/test059-consumer-config
@@ -0,0 +1,451 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+CFPRO=$TESTDIR/cfpro.d
+CFCON=$TESTDIR/cfcon.d
+
+mkdir -p $TESTDIR $DBDIR1A $DBDIR1B $DBDIR2A $CFPRO $CFCON
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+if test x"$SYNCMODE" = x ; then
+ SYNCMODE=rp
+fi
+case "$SYNCMODE" in
+ ro)
+ SYNCTYPE="type=refreshOnly interval=00:00:00:03"
+ ;;
+ rp)
+ SYNCTYPE="type=refreshAndPersist"
+ ;;
+ *)
+ echo "unknown sync mode $SYNCMODE"
+ exit 1;
+ ;;
+esac
+
+#
+# Test replication of dynamic config with alternate consumer config:
+# - start provider
+# - start consumer
+# - configure over ldap
+# - populate over ldap
+# - configure syncrepl over ldap
+# - retrieve database over ldap and compare against expected results
+#
+
+echo "Starting provider slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $DYNAMICCONF > $CONFLDIF
+$SLAPADD -F $CFPRO -n 0 -l $CONFLDIF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+$SLAPD -F $CFPRO -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI1 \
+ '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 "Inserting syncprov overlay on provider..."
+if [ "$SYNCPROV" = syncprovmod ]; then
+ $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: ../servers/slapd/overlays
+olcModuleLoad: syncprov.la
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for moduleLoad ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+read CONFIGPW < $CONFIGPWF
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for syncprov config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Consumers will not replicate the provider's actual cn=config.
+# Instead, they will use an alternate DB so that they may be
+# configured differently from the provider. This alternate DB
+# will also be a consumer for the real cn=schema,cn=config tree.
+# It has multi-provider enabled so that it can be written directly
+# while being a consumer of the main schema.
+echo "Configuring consumer config DB on provider..."
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+add: olcServerID
+olcServerID: 1
+
+dn: olcDatabase={1}ldif,cn=config
+changetype: add
+objectClass: olcDatabaseConfig
+objectClass: olcLdifConfig
+olcDatabase: {1}ldif
+olcDbDirectory: $DBDIR1A
+olcSuffix: cn=config,cn=consumer
+olcRootDN: cn=config,cn=consumer
+olcRootPW: repsecret
+olcAccess: to * by dn.base="cn=config" write
+
+dn: olcOverlay=syncprov,olcDatabase={1}ldif,cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+
+dn: cn=config,cn=consumer
+changetype: add
+objectClass: olcGlobal
+cn: consumerconfig
+
+dn: olcDatabase={0}config,cn=config,cn=consumer
+changetype: add
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW: topsecret
+olcSyncrepl: {0}rid=001 provider=$URI1 binddn="cn=config,cn=consumer"
+ bindmethod=simple credentials=repsecret searchbase="cn=config,cn=consumer"
+ $SYNCTYPE retry="3 5 300 5" timeout=3 suffixmassage="cn=config"
+olcUpdateRef: $URI1
+
+dn: olcDatabase={1}ldif,cn=config
+changetype: modify
+add: olcSyncrepl
+olcSyncrepl: {0}rid=001 provider=$URI1 binddn="cn=config"
+ bindmethod=simple credentials=$CONFIGPW searchbase="cn=schema,cn=config"
+ $SYNCTYPE retry="3 5 300 5" timeout=3
+ suffixmassage="cn=schema,cn=config,cn=consumer"
+-
+add: olcMultiProvider
+olcMultiProvider: TRUE
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for consumer DB config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting consumer slapd on TCP/IP port $PORT2..."
+$SLAPADD -F $CFCON -n 0 -l $CONFLDIF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$SLAPD -F $CFCON -h $URI2 -d $LVL > $LOG2 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI2 \
+ '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 "Configuring syncrepl on consumer..."
+$LDAPMODIFY -D cn=config -H $URI2 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: olcDatabase={0}config,cn=config
+changetype: modify
+add: olcSyncRepl
+olcSyncRepl: rid=001 provider=$URI1 binddn="cn=config,cn=consumer"
+ bindmethod=simple credentials=repsecret searchbase="cn=config,cn=consumer"
+ $SYNCTYPE retry="3 5 300 5" timeout=3
+ suffixmassage="cn=config"
+-
+add: olcUpdateRef
+olcUpdateRef: $URI1
+EOF
+
+sleep 1
+
+echo "Using ldapsearch to check that syncrepl received config changes..."
+RC=32
+for i in 0 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI2 -D cn=config -y $CONFIGPWF \
+ -s base -b "olcDatabase={0}config,cn=config" \
+ '(olcUpdateRef=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+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 provider..."
+$LDAPADD -D cn=config -H $URI1 -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
+
+echo "Using ldapsearch to check that syncrepl received the schema changes..."
+RC=32
+for i in 0 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI2 -D cn=config -y $CONFIGPWF \
+ -s sub -b "cn=schema,cn=config" \
+ '(cn=*openldap)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+done
+
+nullExclude="" nullOK=""
+test $BACKEND = null && nullExclude="# " nullOK="OK"
+
+if [ "$BACKENDTYPE" = mod ]; then
+ $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: ../servers/slapd/back-$BACKEND
+olcModuleLoad: back_$BACKEND.la
+
+dn: cn=module,cn=config,cn=consumer
+objectClass: olcModuleList
+cn: module
+olcModulePath: ../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 $URI1 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: olcDatabase={2}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {2}$BACKEND
+olcSuffix: $BASEDN
+${nullExclude}olcDbDirectory: $DBDIR1B
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+olcSyncRepl: rid=002 provider=$URI1 binddn="$MANAGERDN" bindmethod=simple
+ credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE
+ retry="3 5 300 5" timeout=3
+olcUpdateRef: $URI1
+
+dn: olcOverlay=syncprov,olcDatabase={2}${BACKEND},cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+
+dn: olcDatabase={1}$BACKEND,cn=config,cn=consumer
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+olcSuffix: $BASEDN
+${nullExclude}olcDbDirectory: $DBDIR2A
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+olcSyncRepl: rid=002 provider=$URI1 binddn="$MANAGERDN" bindmethod=simple
+ credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE
+ retry="3 5 300 5" timeout=3
+olcUpdateRef: $URI1
+
+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 $URI1 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: olcDatabase={2}$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 provider..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $LDIFORDERED \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for database config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapsearch to check that syncrepl received database changes..."
+RC=32
+for i in 0 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI2 \
+ -s base -b "cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ 'objectclass=*' > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI2 -w $PASSWD \
+ 'objectclass=*' > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo "Filtering provider results..."
+$LDIFFILTER < $PROVIDEROUT > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER < $CONSUMEROUT > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test060-mt-hot b/tests/scripts/test060-mt-hot
new file mode 100755
index 0000000..a571622
--- /dev/null
+++ b/tests/scripts/test060-mt-hot
@@ -0,0 +1,299 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+# The default debug level logs more than 1Gb:
+case "$SLAPD_DEBUG_MT_HOT/$SLAPD_DEBUG" in
+/0 | /0x0 | /0X0 | /none | /NONE | /32768 | /0x8000 | 0X8000 | /0100000) :;;
+*) SLAPD_DEBUG=${SLAPD_DEBUG_MT_HOT-stats} ;;
+esac
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+if test x$TESTLOOPS = x ; then
+ TESTLOOPS=50
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+#
+# Populate and start up slapd server with some random data
+#
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $MCONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Running slapindex to index slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPINDEX -f $CONF1
+RC=$?
+if test $RC != 0 ; then
+ echo "warning: slapindex failed ($RC)"
+ echo " assuming no indexing support"
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+echo $SLAPD -f $CONF1 -h $URI1 -d $LVL
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+# Perform a basic search, make sure of a functional setup
+echo "Testing basic monitor search..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITORDN" -H $URI1 \
+ '(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 "mt-hot read failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+cat /dev/null > $MTREADOUT
+
+echo "Monitor searches"
+# Perform a basic single threaded search on a single connection
+THR=1
+OUTER=1
+INNER=`expr $TESTLOOPS \* 1000`
+echo "Testing basic mt-hot search: $THR threads ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$MONITORDN" \
+ -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$MONITORDN" -f "(objectclass=*)" \
+ -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapd-mtread failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Perform a basic multi-threaded search on a single connection
+THR=5
+OUTER=1
+INNER=`expr $TESTLOOPS \* 200`
+echo "Testing basic mt-hot search: $THR threads ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$MONITORDN" \
+ -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$MONITORDN" -f "(objectclass=*)" \
+ -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapd-mtread failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Perform a basic multi-threaded search on a single connection
+THR=100
+OUTER=5
+INNER=`expr $TESTLOOPS \* 2`
+echo "Testing basic mt-hot search: $THR threads ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$MONITORDN" \
+ -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$MONITORDN" -f "(objectclass=*)" \
+ -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapd-mtread failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Perform a single threaded random DB search on a single connection
+echo "Random searches"
+THR=1
+OUTER=1
+INNER=`expr $TESTLOOPS \* 1000`
+echo "Testing random mt-hot search: $THR threads ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$BASEDN" -f "(objectclass=*)" \
+ -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$BASEDN" -f "(objectclass=*)" \
+ -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapd-mtread failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Perform a multi-threaded random DB search on a single connection
+THR=5
+OUTER=1
+INNER=`expr $TESTLOOPS \* 200`
+echo "Testing random mt-hot search: $THR threads ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$BASEDN" -f "(objectclass=*)" \
+ -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$BASEDN" -f "(objectclass=*)" \
+ -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapd-mtread failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Perform a multi-threaded random DB search on a single connection
+THR=100
+OUTER=5
+INNER=`expr $TESTLOOPS \* 2`
+echo "Testing random mt-hot search: $THR threads ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$BASEDN" -f "(objectclass=*)" \
+ -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$BASEDN" -f "(objectclass=*)" \
+ -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapd-mtread failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Perform a basic multi-threaded search using multiple connections
+echo "Multiple threads and connection searches"
+CONN=5
+THR=5
+OUTER=1
+INNER=`expr $TESTLOOPS \* 200`
+echo "Testing basic mt-hot search: $THR threads $CONN conns ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$MONITORDN" \
+ -c $CONN -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$MONITORDN" -f "(objectclass=*)" \
+ -c $CONN -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapd-mtread failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Perform a basic multi-threaded search using multiple connections
+CONN=5
+THR=50
+OUTER=5
+INNER=`expr $TESTLOOPS \* 20`
+echo "Testing basic mt-hot search: $THR threads $CONN conns ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$MONITORDN" \
+ -c $CONN -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$MONITORDN" -f "(objectclass=*)" \
+ -c $CONN -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapd-mtread failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Perform a multi-threaded random DB search using multiple connections
+CONN=5
+THR=100
+OUTER=5
+INNER=`expr $TESTLOOPS \* 2`
+echo "Testing random mt-hot search: $THR threads $CONN conns ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$BASEDN" -f "(objectclass=*)" \
+ -c $CONN -m $THR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$BASEDN" -f "(objectclass=*)" \
+ -c $CONN -m $THR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapd-mtread failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Perform a multi-threaded random reads and writes using single connection
+CONN=1
+THR=10
+WTHR=10
+OUTER=5
+INNER=`expr $TESTLOOPS \* 2`
+echo "Testing random mt-hot r/w search: $THR read threads $WTHR write threads $CONN conns ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$BASEDN" -f "(&(!(cn=rwtest*))(objectclass=*))" \
+ -c $CONN -m $THR -M $WTHR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$BASEDN" -f "(&(!(cn=rwtest*))(objectclass=*))" \
+ -c $CONN -m $THR -M $WTHR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapd-mtread failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Perform a multi-threaded random reads and writes using multiple connections
+CONN=5
+THR=10
+WTHR=10
+OUTER=5
+INNER=`expr $TESTLOOPS \* 2`
+echo "Testing random mt-hot r/w search: $THR read threads $WTHR write threads $CONN conns ($OUTER x $INNER) loops..."
+echo $SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$BASEDN" -f "(&(!(cn=rwtest*))(objectclass=*))" \
+ -c $CONN -m $THR -M $WTHR -L $OUTER -l $INNER
+$SLAPDMTREAD -H $URI1 -D "$MANAGERDN" -w $PASSWD \
+ -e "$BASEDN" -f "(&(!(cn=rwtest*))(objectclass=*))" \
+ -c $CONN -m $THR -M $WTHR -L $OUTER -l $INNER >> $MTREADOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapd-mtread failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+exit 0
diff --git a/tests/scripts/test061-syncreplication-initiation b/tests/scripts/test061-syncreplication-initiation
new file mode 100755
index 0000000..3e3b973
--- /dev/null
+++ b/tests/scripts/test061-syncreplication-initiation
@@ -0,0 +1,674 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+# This script tests race conditions related to setting up the syncrepl
+# refresh phase, especially when the provider is itself a consumer
+# refreshing from its provider again.
+
+# The configuration used is a provider->forwarder->consumer chain, where
+# the forwarder is restarted between add/delete of entries on the provider.
+
+echo "Running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+test "x$INITIATION_RACE_TESTS" = "x" && INITIATION_RACE_TESTS=1
+
+if test $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+RETRY="1 +"
+
+PROV_DIR=$TESTDIR/prov
+CONS_DIR=$TESTDIR/cons
+FWD1_DIR=$TESTDIR/fwd1
+FWD2_DIR=$TESTDIR/fwd2
+
+PROV_URI=$URI1
+CONS_URI=$URI2
+FWD1_URI=$URI3
+
+PROV_LOG=$LOG1
+CONS_LOG=$LOG2
+FWD1_LOG=$LOG3
+
+DIRS="$PROV_DIR $CONS_DIR $FWD1_DIR"
+URIS="$PROV_URI $CONS_URI $FWD1_URI"
+
+noObj=32
+nullExclude="" nullOK=""
+test $BACKEND = null && nullExclude="# " nullOK="OK" noObj=0
+
+mkdir -p $TESTDIR
+
+for dir in $DIRS; do
+ mkdir -p $dir $dir/slapd.d $dir/db
+done
+
+KILLPIDS=
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+case "$BACKEND" in
+ *) olcDbCheckpoint="# olcDbCheckpoint";;
+esac
+
+echo "Initializing server configurations"
+for dir in $DIRS; do
+ $SLAPADD -F $dir/slapd.d -n 0 <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+olcServerID: 1 $PROV_URI
+olcServerID: 2 $CONS_URI
+olcServerID: 3 $FWD1_URI
+
+dn: olcDatabase={0}config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW:< file://$CONFIGPWF
+
+EOF
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+ fi
+done
+
+echo "Starting provider slapd on $PROV_URI"
+cd $PROV_DIR
+$SLAPD -F slapd.d -h $PROV_URI -d $LVL >> $PROV_LOG 2>&1 &
+PROV_PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PROV_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PROV_PID"
+cd $TESTWD
+sleep 1
+for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $PROV_URI \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting forward1 slapd on $FWD1_URI"
+cd $FWD1_DIR
+$SLAPD -F slapd.d -h $FWD1_URI -d $LVL >> $FWD1_LOG 2>&1 &
+FWD1_PID=$!
+if test $WAIT != 0 ; then
+ echo PID $FWD1_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $FWD1_PID"
+cd $TESTWD
+sleep 1
+for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $FWD1_URI \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting consumer slapd on $CONS_URI"
+cd $CONS_DIR
+$SLAPD -F slapd.d -h $CONS_URI -d $LVL >> $CONS_LOG 2>&1 &
+CONS_PID=$!
+if test $WAIT != 0 ; then
+ echo PID $CONS_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONS_PID"
+cd $TESTWD
+sleep 1
+for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $CONS_URI \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to start..."
+ sleep $i
+done
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+for uri in $URIS; do
+ echo "Adding schema on $uri"
+ $LDAPADD -D cn=config -H $uri -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 ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ [ "$BACKENDTYPE" = mod ] || continue
+
+ echo "Adding backend module on $uri..."
+ $LDAPADD -D cn=config -H $uri -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 module ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+done
+
+syncprov_module=''
+[ "$AC_syncprov" = syncprovmod ] && syncprov_module="
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+olcModuleLoad: syncprov.la"
+
+for uri in $PROV_URI; do
+ echo "Adding database configuration on $uri"
+ $LDAPADD -D cn=config -H $uri -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: ./db
+$olcDbCheckpoint: 1024 5
+olcSuffix: $BASEDN
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+
+$syncprov_module
+
+dn: olcOverlay={0}syncprov,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: {0}syncprov
+olcSpCheckpoint: 1 1
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Populating provider on $uri"
+ $LDAPADD -D "$MANAGERDN" -H $PROV_URI -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: $BASEDN
+objectClass: top
+objectClass: organization
+objectClass: dcObject
+dc: example
+o: Example, Inc
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+done
+
+for uri in $FWD1_URI; do
+ echo "Adding database configuration on $uri"
+ $LDAPADD -D cn=config -H $uri -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: ./db
+$olcDbCheckpoint: 1024 5
+olcSuffix: $BASEDN
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+olcSyncRepl: rid=1 provider=$PROV_URI searchbase="$BASEDN"
+ binddn="$MANAGERDN" bindmethod=simple credentials=$PASSWD
+ type=refreshAndPersist retry="$RETRY" timeout=1
+
+$syncprov_module
+
+dn: olcOverlay={0}syncprov,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: {0}syncprov
+olcSpCheckpoint: 1 1
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+done
+
+for uri in $CONS_URI; do
+ echo "Adding database configuration on $uri"
+ $LDAPADD -D cn=config -H $uri -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: ./db
+$olcDbCheckpoint: 1024 5
+olcSuffix: $BASEDN
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+olcSyncRepl: rid=1 provider=$FWD1_URI searchbase="$BASEDN"
+ binddn="$MANAGERDN" bindmethod=simple credentials=$PASSWD
+ type=refreshAndPersist retry="$RETRY" timeout=1
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+done
+
+for uri in $FWD1_URI $CONS_URI; do
+ echo "Using ldapsearch to check that $uri received database..."
+ for i in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$BASEDN" -H $uri \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ test $RC = 0 && break
+ echo "Waiting $i seconds for slapd to receive database..."
+ sleep $i
+ done
+ if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+done
+
+RACE_NUM=0
+ERROR=0
+
+nEntries=10
+
+addEnd=1
+delEnd=1
+
+addIdx=1
+delIdx=1
+
+while test $ERROR -eq 0 -a $RACE_NUM -lt $INITIATION_RACE_TESTS ; do
+ RACE_NUM=`expr $RACE_NUM + 1`
+ echo "Running $RACE_NUM of $INITIATION_RACE_TESTS syncrepl initiation race tests..."
+
+ echo "Stopping forwarders for add test"
+ for pid in $FWD1_PID; do
+ kill -HUP $pid
+ wait $pid
+ KILLPIDS=`echo "$KILLPIDS " | sed -e "s/ $pid / /"`;
+ done
+
+ addStart=$addEnd
+ addEnd=`expr $addEnd + $nEntries`
+
+ echo "Using ldapadd to add $nEntries entries on provider"
+ while test $addIdx -lt $addEnd; do
+ $LDAPADD -D "$MANAGERDN" -H $PROV_URI -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=$addIdx,$BASEDN
+objectClass: top
+objectClass: organizationalUnit
+ou: $addIdx
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for entry $addIdx ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ addIdx=`expr $addIdx + 1`
+ done
+
+ echo "Starting forwarders again"
+ cd $FWD1_DIR
+ $SLAPD -F slapd.d -h $FWD1_URI -d $LVL >> $FWD1_LOG 2>&1 &
+ FWD1_PID=$!
+ KILLPIDS="$KILLPIDS $FWD1_PID"
+ cd $TESTWD
+
+ addEnd=`expr $addEnd + $nEntries`
+
+ echo "Using ldapadd to add $nEntries more entries on provider"
+ while test $addIdx -lt $addEnd; do
+ $LDAPADD -D "$MANAGERDN" -H $PROV_URI -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=$addIdx,$BASEDN
+objectClass: top
+objectClass: organizationalUnit
+ou: $addIdx
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for entry $addIdx ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ addIdx=`expr $addIdx + 1`
+ done
+
+ for uri in $FWD1_URI $CONS_URI; do
+ echo "Checking replication to $uri"
+ RC=32
+ i=$addStart
+ while test $i -lt $addEnd; do
+ for j in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $uri -s base -b "ou=$i,$BASEDN" 2>&1 \
+ | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $j seconds for $uri to receive entry $i..."
+ sleep $j
+ done
+ if test $RC != 0 ; then
+ echo "ERROR: Entry $i not replicated to $uri! ($RC)!"
+ ERROR=1
+ break
+ fi
+ i=`expr $i + 1`
+ done
+ if test $ERROR != 0; then break; fi
+ done
+ if test $ERROR != 0; then break; fi
+
+ echo "Stopping forwarders for add/delete test"
+ for pid in $FWD1_PID; do
+ kill -HUP $pid
+ wait $pid
+ KILLPIDS=`echo "$KILLPIDS " | sed -e "s/ $pid / /"`;
+ done
+
+ addStart=$addEnd
+ addEnd=`expr $addEnd + $nEntries`
+
+ echo "Using ldapadd to add $nEntries entries on provider"
+ while test $addIdx -lt $addEnd; do
+ $LDAPADD -D "$MANAGERDN" -H $PROV_URI -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=$addIdx,$BASEDN
+objectClass: top
+objectClass: organizationalUnit
+ou: $addIdx
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for entry $addIdx ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ addIdx=`expr $addIdx + 1`
+ done
+
+ delStart=$delEnd
+ delEnd=`expr $delEnd + $nEntries`
+
+ echo "Using ldapdelete to delete $nEntries entries on provider"
+ while test $delIdx -lt $delEnd; do
+ $LDAPDELETE -D "$MANAGERDN" -H $PROV_URI -w $PASSWD "ou=$delIdx,$BASEDN"
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapdelete failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ delIdx=`expr $delIdx + 1`
+ done
+
+ echo "Starting forwarders again"
+ cd $FWD1_DIR
+ $SLAPD -F slapd.d -h $FWD1_URI -d $LVL >> $FWD1_LOG 2>&1 &
+ FWD1_PID=$!
+ KILLPIDS="$KILLPIDS $FWD1_PID"
+ cd $TESTWD
+
+ addEnd=`expr $addEnd + $nEntries`
+ delEnd=`expr $delEnd + $nEntries`
+
+ echo "Using ldapadd to add $nEntries more entries on provider"
+ while test $addIdx -lt $addEnd; do
+ $LDAPADD -D "$MANAGERDN" -H $PROV_URI -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: ou=$addIdx,$BASEDN
+objectClass: top
+objectClass: organizationalUnit
+ou: $addIdx
+
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for entry $addIdx ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ addIdx=`expr $addIdx + 1`
+ done
+
+ echo "Using ldapdelete to delete $nEntries more entries on provider"
+ while test $delIdx -lt $delEnd; do
+ $LDAPDELETE -D "$MANAGERDN" -H $PROV_URI -w $PASSWD "ou=$delIdx,$BASEDN"
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapdelete failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ delIdx=`expr $delIdx + 1`
+ done
+
+ for uri in $FWD1_URI $CONS_URI; do
+ echo "Checking replication to $uri"
+ RC=32
+ i=$addStart
+ while test $i -lt $addEnd; do
+ for j in 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $uri -s base -b "ou=$i,$BASEDN" 2>&1 \
+ | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $j seconds for $uri to receive entry $i..."
+ sleep $j
+ done
+ if test $RC != 0 ; then
+ echo "ERROR: Entry $i not replicated to $uri! ($RC)!"
+ ERROR=1
+ break
+ fi
+ i=`expr $i + 1`
+ done
+ if test $ERROR != 0; then break; fi
+
+ i=$delStart
+ while test $i -lt $delEnd; do
+ for j in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "ou=$i,$BASEDN" -H $uri > /dev/null 2>&1
+ RC=$?
+ if test $RC = $noObj; then break; fi
+ echo "Waiting $j seconds for $uri to delete entry $i..."
+ sleep $j
+ done
+ if test $RC != $noObj; then
+ echo "ERROR: Entry $i not removed on $uri! (RC=$RC)"
+ ERROR=1
+ break
+ fi
+ i=`expr $i + 1`
+ done
+ if test $ERROR != 0; then break; fi
+ done
+ if test $ERROR != 0; then break; fi
+
+ echo "Stopping forwarders for delete test"
+ for pid in $FWD1_PID; do
+ kill -HUP $pid
+ wait $pid
+ KILLPIDS=`echo "$KILLPIDS " | sed -e "s/ $pid / /"`;
+ done
+
+ delStart=$delEnd
+ delEnd=`expr $delEnd + $nEntries`
+
+ echo "Using ldapdelete to delete entries on provider"
+ while test $delIdx -lt $delEnd; do
+ $LDAPDELETE -D "$MANAGERDN" -H $PROV_URI -w $PASSWD "ou=$delIdx,$BASEDN"
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapdelete failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ delIdx=`expr $delIdx + 1`
+ done
+
+ echo "Starting forwarders again"
+ cd $FWD1_DIR
+ $SLAPD -F slapd.d -h $FWD1_URI -d $LVL >> $FWD1_LOG 2>&1 &
+ FWD1_PID=$!
+ KILLPIDS="$KILLPIDS $FWD1_PID"
+ cd $TESTWD
+
+ delEnd=`expr $delEnd + $nEntries`
+
+ echo "Using ldapdelete to delete $nEntries more entries on provider"
+ while test $delIdx -lt $delEnd; do
+ $LDAPDELETE -D "$MANAGERDN" -H $PROV_URI -w $PASSWD "ou=$delIdx,$BASEDN"
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapdelete failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ delIdx=`expr $delIdx + 1`
+ done
+
+ for uri in $FWD1_URI $CONS_URI; do
+ echo "Checking replication to $uri"
+ RC=0
+ i=$delStart
+ while test $i -lt $delEnd; do
+ for j in 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "ou=$i,$BASEDN" -H $uri > /dev/null 2>&1
+ RC=$?
+ if test $RC = $noObj; then break; fi
+ echo "Waiting $j seconds for $uri to delete entry $i..."
+ sleep $j
+ done
+ if test $RC != $noObj; then
+ echo "ERROR: Entry $i not removed on $uri! (RC=$RC)"
+ ERROR=1
+ break
+ fi
+ i=`expr $i + 1`
+ done
+ if test $ERROR != 0; then break; fi
+ done
+ if test $ERROR != 0; then break; fi
+
+ sleep 1
+ echo "Checking contextCSN"
+ CSN_ERRORS=0
+ CSN1=`$LDAPSEARCH -H $URI1 -b $BASEDN -s base contextCSN | grep contextCSN`
+ CSN2=`$LDAPSEARCH -H $URI2 -b $BASEDN -s base contextCSN | grep contextCSN`
+ CSN3=`$LDAPSEARCH -H $URI3 -b $BASEDN -s base contextCSN | grep contextCSN`
+
+ if test -z "$CSN1" ; then
+ test $BACKEND = null && break
+ echo "ERROR: contextCSN empty on provider"
+ ERROR=1
+ break
+ fi
+ nCSN=`echo "$CSN1" | wc -l`
+ if test "$nCSN" -ne 1 ; then
+ echo "ERROR: Wrong contextCSN count on provider, should be 1"
+ echo "$CSN1"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+ if test -z "$CSN2" -o "$CSN1" != "$CSN2" ; then
+ echo "ERROR: contextCSN mismatch between provider and consumer"
+ echo "contextCSN on provider: $CSN1"
+ echo "contextCSN on consumer: $CSN2"
+ ERROR=1
+ break
+ fi
+ if test -z "$CSN3" -o "$CSN1" != "$CSN3" ; then
+ echo "ERROR: contextCSN mismatch between provider and forward1"
+ echo "contextCSN on provider: $CSN1"
+ echo "contextCSN on forward1: $CSN3"
+ ERROR=1
+ break
+ fi
+done
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $ERROR != 0; then
+ echo "Error found after $RACE_NUM of $INITIATION_RACE_TESTS iterations"
+ exit 1
+else
+ echo "No race errors found after $INITIATION_RACE_TESTS iterations"
+fi
+
+echo ">>>>> Test succeeded"
+
+exit 0
diff --git a/tests/scripts/test062-config-delete b/tests/scripts/test062-config-delete
new file mode 100755
index 0000000..afb87c4
--- /dev/null
+++ b/tests/scripts/test062-config-delete
@@ -0,0 +1,183 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+CONFDIR=$TESTDIR/slapd.d
+DBDIR=$TESTDIR/db
+RCOUT=$TESTDIR/rcout
+
+mkdir -p $TESTDIR $CONFDIR $DBDIR
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+#
+# Test dynamic add/delete of syncprov overlay:
+# - Create minimal back-conf setup
+# - Add syncprov overlay to the cn=config database
+# - Remove the overlay again
+#
+
+echo "Starting slapd on TCP/IP port $PORT1... $PWD"
+. $CONFFILTER $BACKEND < $DYNAMICCONF > $CONFLDIF
+$SLAPADD -F $CONFDIR -n 0 -l $CONFLDIF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+cd $TESTDIR
+$SLAPD -F ./slapd.d -h $URI1 -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 $URI1 \
+ '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 "Inserting syncprov overlay ..."
+if [ "$SYNCPROV" = syncprovmod ]; then
+ $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+olcModuleLoad: syncprov.la
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for moduleLoad ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+read CONFIGPW < $CONFIGPWF
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for syncrepl config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting a refreshAndPersist search in background"
+rm -f $RCOUT
+(
+ $LDAPSEARCH -D cn=config -H $URI1 -y $CONFIGPWF -bcn=config -E \!sync=rp >/dev/null 2>&1
+ RC=$?
+ echo $RC > $RCOUT
+ exit $RC
+) &
+
+SEARCHPID=$!
+
+sleep 2
+
+echo "Removing syncprov overlay again ..."
+$LDAPDELETE -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+olcOverlay={0}syncprov,olcDatabase={0}config,cn=config
+EOF
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapmodify failed for syncrepl config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+for i in 0 1 2 3 4; do
+ if test -f "$RCOUT" ; then
+ break
+ else
+ echo "Waiting 2 seconds for RefreshAndPersist search to end ..."
+ sleep 2
+ fi
+done
+
+if test -f "$RCOUT" ; then
+ wait $SEARCHPID
+ SEARCHRC=`cat $RCOUT`
+ echo "Checking return code of backgrounded RefreshAndPersist search ..."
+ if test 52 != "$SEARCHRC" ; then
+ echo "Error: Backgrounded ldapsearch returned the wrong error code: $SEARCHRC"
+ RC=1
+ else
+ echo "Exit code correct."
+ fi
+else
+ echo "Backgrounded ldapsearch did not exit after overlay removal."
+ kill -HUP $SEARCHPID
+ RC=2
+fi
+if test $RC != 0 ; then
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Running a refreshOnly search, should fail..."
+$LDAPSEARCH -D cn=config -H $URI1 -y $CONFIGPWF -bcn=config -E \!sync=ro > /dev/null 2>&1
+
+RC=$?
+if test $RC != 12 ; then
+ echo "ldapsearch should have failed with Critical extension is unavailable (12)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+else
+ echo "Failed with \"Critical extension is unavailable (12)\". Ok."
+fi
+
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test063-delta-multiprovider b/tests/scripts/test063-delta-multiprovider
new file mode 100755
index 0000000..8ce5906
--- /dev/null
+++ b/tests/scripts/test063-delta-multiprovider
@@ -0,0 +1,619 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+if test $ACCESSLOG = accesslogno; then
+ echo "Accesslog overlay not available, test skipped"
+ exit 0
+fi
+
+MPR=${MPR-4}
+
+XDIR=$TESTDIR/srv
+TMP=$TESTDIR/tmp
+
+mkdir -p $TESTDIR
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+if test x"$SYNCMODE" = x ; then
+ SYNCMODE=rp
+fi
+case "$SYNCMODE" in
+ ro)
+ SYNCTYPE="type=refreshOnly interval=00:00:00:03"
+ ;;
+ rp)
+ SYNCTYPE="type=refreshAndPersist interval=00:00:00:03"
+ ;;
+ *)
+ echo "unknown sync mode $SYNCMODE"
+ exit 1;
+ ;;
+esac
+
+#
+# Test delta-sync mpr
+# - start servers
+# - configure over ldap
+# - populate over ldap
+# - configure syncrepl over ldap
+# - break replication
+# - modify each server separately
+# - restore replication
+# - compare results
+#
+
+nullExclude=""
+test $BACKEND = null && nullExclude="# "
+
+KILLPIDS=
+
+echo "Initializing server configurations..."
+n=1
+while [ $n -le $MPR ]; do
+
+DBDIR=${XDIR}$n/db
+CFDIR=${XDIR}$n/slapd.d
+
+mkdir -p ${XDIR}$n $DBDIR.1 $DBDIR.2 $CFDIR
+
+cat > $TMP <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+EOF
+
+o=1
+while [ $o -le $MPR ]; do
+PORT=`expr $BASEPORT + $o`
+URI="ldap://${LOCALHOST}:$PORT/"
+echo "olcServerID: $o $URI" >> $TMP
+o=`expr $o + 1`
+done
+echo "" >> $TMP
+
+if [ "$SYNCPROV" = syncprovmod -o "$ACCESSLOG" = accesslogmod ]; then
+ cat <<EOF >> $TMP
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+EOF
+ if [ "$SYNCPROV" = syncprovmod ]; then
+ echo "olcModuleLoad: syncprov.la" >> $TMP
+ fi
+ if [ "$ACCESSLOG" = accesslogmod ]; then
+ echo "olcModuleLoad: accesslog.la" >> $TMP
+ fi
+ echo "" >> $TMP
+fi
+
+if [ "$BACKENDTYPE" = mod ]; then
+cat <<EOF >> $TMP
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/back-$BACKEND
+olcModuleLoad: back_$BACKEND.la
+
+EOF
+fi
+
+MYURI=`eval echo '$URI'$n`
+PROVIDERURI=`eval echo '$URI'$o`
+if test $INDEXDB = indexdb ; then
+INDEX1="olcDbIndex: objectClass,entryCSN,reqStart,reqDN,reqResult eq"
+INDEX2="olcDbIndex: objectClass,entryCSN,entryUUID eq"
+else
+INDEX1=
+INDEX2=
+fi
+cat >> $TMP <<EOF
+dn: cn=schema,cn=config
+objectclass: olcSchemaconfig
+cn: schema
+
+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
+
+dn: olcDatabase={0}config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW:< file://$CONFIGPWF
+
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+olcSuffix: cn=log
+${nullExclude}olcDbDirectory: ${DBDIR}.1
+olcRootDN: $MANAGERDN
+$INDEX1
+
+dn: olcOverlay=syncprov,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+olcSpNoPresent: TRUE
+olcSpReloadHint: TRUE
+
+dn: olcDatabase={2}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {2}$BACKEND
+olcSuffix: $BASEDN
+${nullExclude}olcDbDirectory: ${DBDIR}.2
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+EOF
+
+o=1
+while [ $o -le $MPR ]; do
+PORT=`expr $BASEPORT + $o`
+URI="ldap://${LOCALHOST}:$PORT/"
+cat >>$TMP <<EOF
+olcSyncRepl: rid=00$o provider=$URI binddn="$MANAGERDN" bindmethod=simple
+ credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE
+ retry="3 +" timeout=3 logbase="cn=log"
+ logfilter="(&(objectclass=auditWriteObject)(reqresult=0))"
+ syncdata=accesslog
+EOF
+o=`expr $o + 1`
+done
+
+cat >> $TMP <<EOF
+olcMultiProvider: TRUE
+$INDEX2
+
+dn: olcOverlay=syncprov,olcDatabase={2}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+
+dn: olcOverlay=accesslog,olcDatabase={2}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcAccessLogConfig
+olcOverlay: accesslog
+olcAccessLogDB: cn=log
+olcAccessLogOps: writes
+olcAccessLogSuccess: TRUE
+
+EOF
+cat <<EOF >> $TMP
+dn: olcDatabase={3}monitor,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olcmonitorConfig
+olcDatabase: {3}monitor
+
+EOF
+
+$SLAPADD -F $CFDIR -n 0 -d-1< $TMP > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+PORT=`eval echo '$PORT'$n`
+echo "Starting server $n on TCP/IP port $PORT..."
+cd ${XDIR}${n}
+LOG=`eval echo '$LOG'$n`
+$SLAPD -F slapd.d -h $MYURI -d $LVL > $LOG 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID $KILLPIDS"
+cd $TESTWD
+
+echo "Using ldapsearch to check that server $n is running..."
+sleep 1
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $MYURI \
+ '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
+
+if [ $n = 1 ]; then
+echo "Using ldapadd for context on server 1..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $LDIFORDEREDCP \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server $n database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+fi
+
+n=`expr $n + 1`
+done
+
+echo "Using ldapadd to populate server 1..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $LDIFORDEREDNOCP \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server $n database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+n=1
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MPR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+echo "Using ldapadd to populate server 2..."
+cp $LDIFADD1 $TESTDIR/add.ldif
+echo "displayName: The other" >>$TESTDIR/add.ldif
+$LDAPADD -D "$MANAGERDN" -H $URI2 -w $PASSWD -f $TESTDIR/add.ldif \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+THEDN="cn=James A Jones 2,ou=Alumni Association,ou=People,dc=example,dc=com"
+sleep 1
+for i in 1 2 3; do
+ $LDAPSEARCH -S "" -b "$THEDN" -H $URI1 \
+ -s base '(objectClass=*)' entryCSN > "${PROVIDEROUT}.$i" 2>&1
+ RC=$?
+
+ if test $RC = 0 ; then
+ break
+ fi
+
+ if test $RC != 32 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+done
+
+n=1
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MPR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+echo "Breaking replication between server 1 and 2..."
+n=1
+while [ $n -le 2 ]; do
+MYURI=`eval echo '$URI'$n`
+o=`expr $n - 1`
+$LDAPMODIFY -D cn=config -H $MYURI -y $CONFIGPWF > $TESTOUT 2>&1 <<EOF
+dn: olcDatabase={2}$BACKEND,cn=config
+changetype: modify
+delete: olcSyncRepl
+-
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server $n config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+n=`expr $n + 1`
+done
+
+echo "Using ldapmodify to force conflicts between server 1 and 2..."
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: description
+description: Amazing
+-
+add: displayName
+displayName: James the Second
+-
+delete: displayName
+displayName: The other
+-
+replace: mail
+mail: jaj2@mail.alumni.example.com
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI2 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+replace: employeetype
+-
+add: description
+description: Stupendous
+-
+add: displayName
+displayName: James II
+-
+delete: displayName
+displayName: The other
+-
+add: mail
+mail: jaj2@moo.net
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+delete: description
+description: Outstanding
+-
+add: description
+description: Mindboggling
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI2 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+delete: description
+description: OutStanding
+-
+add: description
+description: Bizarre
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: carLicense
+carLicense: 123-XYZ
+-
+add: employeeNumber
+employeeNumber: 32
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI2 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: employeeType
+employeeType: deadwood
+-
+add: employeeNumber
+employeeNumber: 64
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+replace: sn
+sn: Replaced later
+-
+replace: sn
+sn: Surname
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Restoring replication between server 1 and 2..."
+cat > $TMP <<EOF
+dn: olcDatabase={2}$BACKEND,cn=config
+changetype: modify
+add: olcSyncRepl
+EOF
+n=1
+while [ $n -le $MPR ]; do
+MYURI=`eval echo '$URI'$n`
+PROVIDERURI=`eval echo '$URI'$n`
+cat >> $TMP <<EOF
+olcSyncRepl: rid=00$n provider=$PROVIDERURI binddn="$MANAGERDN" bindmethod=simple
+ credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE
+ retry="3 +" timeout=3 logbase="cn=log"
+ logfilter="(&(objectclass=auditWriteObject)(reqresult=0))"
+ syncdata=accesslog
+EOF
+n=`expr $n + 1`
+done
+cat >> $TMP <<EOF
+-
+replace: olcMultiProvider
+olcMultiProvider: TRUE
+EOF
+n=1
+while [ $n -le 2 ]; do
+MYURI=`eval echo '$URI'$n`
+$LDAPMODIFY -D cn=config -H $MYURI -y $CONFIGPWF > $TESTOUT 2>&1 <$TMP
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server $n config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+n=`expr $n + 1`
+done
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+n=1
+while [ $n -le $MPR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER -s a < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MPR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test064-constraint b/tests/scripts/test064-constraint
new file mode 100755
index 0000000..5519123
--- /dev/null
+++ b/tests/scripts/test064-constraint
@@ -0,0 +1,220 @@
+#!/bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $CONSTRAINT = constraintno; then
+ echo "Constraint overlay not available, test skipped"
+ exit 0
+fi
+
+CONSTRAINTDIR="$DATADIR/constraint"
+ROOTLDIF="$CONSTRAINTDIR/root.ldif"
+USERLDIF="$CONSTRAINTDIR/user.ldif"
+RESULTOUT="$CONSTRAINTDIR/constraint.out"
+SCRIPTOUT="$TESTDIR/constraint.out"
+USERDN="cn=John Doe,ou=users,$BASEDN"
+
+CONFDIR=$TESTDIR/slapd.d
+mkdir -p $TESTDIR $CONFDIR $DBDIR1
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+cat > $TESTDIR/config.ldif <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+olcArgsFile: $TESTDIR/slapd.args
+olcPidFile: $TESTDIR/slapd.pid
+
+dn: cn=schema,cn=config
+objectClass: olcSchemaConfig
+cn: schema
+
+include: file://$TESTWD/schema/core.ldif
+include: file://$TESTWD/schema/cosine.ldif
+include: file://$TESTWD/schema/inetorgperson.ldif
+
+dn: olcDatabase=config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: config
+olcRootPW:< file://$CONFIGPWF
+EOF
+
+if [ "$BACKENDTYPE" = mod ]; then
+ cat >> $TESTDIR/config.ldif <<EOF
+
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/back-$BACKEND
+olcModuleLoad: back_$BACKEND.la
+EOF
+fi
+
+if [ "$CONSTRAINT" = constraintmod ]; then
+ cat >> $TESTDIR/config.ldif <<EOF
+
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+olcModuleLoad: constraint.la
+EOF
+fi
+
+cat >> $TESTDIR/config.ldif <<EOF
+
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olc${BACKEND}Config
+olcDatabase: $BACKEND
+olcSuffix: $BASEDN
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+olcDbDirectory: $TESTDIR/db.1.a
+EOF
+
+if [ "$INDEXDB" = indexdb ]; then
+ cat >> $TESTDIR/config.ldif <<EOF
+olcDbIndex: objectClass eq,pres
+olcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub
+EOF
+fi
+
+cat >> $TESTDIR/config.ldif <<EOF
+
+dn: olcOverlay=constraint,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcConstraintConfig
+olcOverlay: constraint
+olcConstraintAttribute: mail
+ count 3
+ restrict="ldap:///ou=users,$BASEDN??one?(objectClass=inetOrgPerson)"
+# check if restrict works (if not, this will apply to ou=users subtree as well
+# and some tests will fail)
+olcConstraintAttribute: mail count 1 restrict="ldap:///ou=groups,$BASEDN??one"
+olcConstraintAttribute: mail regex ^[[:alnum:]]+@example.com$
+olcConstraintAttribute: description count 2
+olcConstraintAttribute: jpegPhoto count 0
+# cn value has to be concatenated givenName SP sn
+olcConstraintAttribute: cn,sn,givenName
+ set "(this/givenName + [ ] + this/sn) & this/cn"
+ restrict="ldap:///$USERDN??sub?(objectClass=inetOrgPerson)"
+olcConstraintAttribute: uid
+ uri "ldap:///ou=groups,$BASEDN?uid?one?(objectClass=inetOrgPerson)"
+ restrict="ldap:///ou=users,$BASEDN??one"
+EOF
+
+$SLAPADD -F $CONFDIR -n 0 -l $TESTDIR/config.ldif
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -F $CONFDIR -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+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 "$MONITOR" -H $URI1 \
+ '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 basic structure..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $ROOTLDIF >/dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $PID
+ exit $RC
+fi
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $USERLDIF >/dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $PID
+ exit $RC
+fi
+
+echo "Running constraint tests..."
+for ldif in $CONSTRAINTDIR/*ok*.ldif $CONSTRAINTDIR/*fail*.ldif; do
+ ### reload
+ $LDAPDELETE -D "$MANAGERDN" -H $URI1 -w $PASSWD "$USERDN" >/dev/null 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapdelete failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $PID
+ exit $RC
+ fi
+ $LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $USERLDIF >/dev/null 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $PID
+ exit $RC
+ fi
+
+ ### info
+ echo -n " [$ldif]: "
+
+ ### modify
+ $LDAPMODIFY -H $URI1 -x -D "$MANAGERDN" -f $ldif -w $PASSWD >/dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ echo "OK" | tee -a $SCRIPTOUT
+ elif test $RC = 19 ; then
+ echo "FAIL" | tee -a $SCRIPTOUT
+ else
+ echo "UNEXPECTED ($RC)"
+ fi
+done
+
+echo "Comparing output..."
+$DIFF $SCRIPTOUT $RESULTOUT > $CMPOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "Comparison failed"
+ test $KILLSERVERS != no && kill -HUP $PID
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $PID
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test065-proxyauthz b/tests/scripts/test065-proxyauthz
new file mode 100755
index 0000000..e96c877
--- /dev/null
+++ b/tests/scripts/test065-proxyauthz
@@ -0,0 +1,255 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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>.
+
+PCACHETTL=${PCACHETTL-"1m"}
+PCACHENTTL=${PCACHENTTL-"1m"}
+PCACHESTTL=${PCACHESTTL-"1m"}
+PCACHE_ENTRY_LIMIT=${PCACHE_ENTRY_LIMIT-"6"}
+PCACHE_CCPERIOD=${PCACHE_CCPERIOD-"2"}
+PCACHETTR=${PCACHETTR-"2"}
+PCACHEBTTR=${PCACHEBTTR-"5"}
+
+. $SRCDIR/scripts/defines.sh
+
+LVL=0x100
+
+if test $PROXYCACHE = pcacheno; then
+ echo "Proxy cache overlay not available, test skipped"
+ exit 0
+fi
+
+if test $BACKLDAP = "ldapno" ; then
+ echo "LDAP backend not available, test skipped"
+ exit 0
+fi
+
+if test $BACKEND = ldif ; then
+ # The (mail=example.com*) queries hit a sizelimit, so which
+ # entry is returned depends on the ordering in the backend.
+ echo "Test does not support $BACKEND backend, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+# Test proxy caching:
+# - start provider
+# - start proxy cache
+# - populate provider
+# - perform a first search
+# - verify cacheability
+# - perform a second search with the same filter and same user
+# - verify answerability and cacheability of the bind
+# - perform a third search with the same user but a different filter
+# - verify cacheability of the bind and the non-answerability of the result
+
+echo "Starting provider slapd on TCP/IP port $PORT1..."
+. $CONFFILTER < $PROXYAUTHZPROVIDERCONF > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ -D "cn=Manager,dc=example,dc=com" -w secret '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 "Using ldapadd to populate the provider directory..."
+$LDAPADD -x -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDERED > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting proxy cache on TCP/IP port $PORT2..."
+. $CONFFILTER < $PROXYAUTHZCONF | sed \
+ -e "s/@TTL@/${PCACHETTL}/" \
+ -e "s/@NTTL@/${PCACHENTTL}/" \
+ -e "s/@STTL@/${PCACHENTTL}/" \
+ -e "s/@TTR@/${PCACHETTR}/" \
+ -e "s/@ENTRY_LIMIT@/${PCACHE_ENTRY_LIMIT}/" \
+ -e "s/@CCPERIOD@/${PCACHE_CCPERIOD}/" \
+ -e "s/@BTTR@/${PCACHEBTTR}/" \
+ > $CONF2
+
+$SLAPD -f $CONF2 -h $URI2 -d $LVL -d pcache > $LOG2 2>&1 &
+CACHEPID=$!
+if test $WAIT != 0 ; then
+ echo CACHEPID $CACHEPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CACHEPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that proxy slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ -D "cn=Manager,dc=example,dc=com" -w secret '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
+
+cat /dev/null > $SEARCHOUT
+
+echo "Making queries on the proxy cache..."
+CNT=0
+
+
+CNT=`expr $CNT + 1`
+USERDN="cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com"
+UPASSWD="jaj"
+echo "Query $CNT: $USERDN"
+echo "# Query $CNT: $USERDN" >> $SEARCHOUT
+
+$LDAPSEARCH -S "" -b "dc=example,dc=com" -s SUB -H $URI2 \
+ -D "$USERDN" -w "$UPASSWD" "(sn=je*)" sn >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Check that the bind is cached
+grep "CACHING BIND for $USERDN" $LOG2 > /dev/null
+
+RC=$?
+if test $RC != 0 ; then
+ echo "Refresh failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+ exit 1
+fi
+
+CNT=`expr $CNT + 1`
+USERDN="cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com"
+UPASSWD="jaj"
+echo "Query $CNT: (Bind should be cached)"
+echo "# Query $CNT: (Bind should be cached)" >> $SEARCHOUT
+
+$LDAPSEARCH -S "" -b "dc=example,dc=com" -s SUB -H $URI2 \
+ -D "$USERDN" -w "$UPASSWD" "(sn=je*)" sn >> $SEARCHOUT 2>> $TESTOUT
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+grep "CACHED BIND for $USERDN" $LOG2 > /dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "Refresh failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+ exit 1
+fi
+
+CNT=`expr $CNT + 1`
+USERDN="cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com"
+
+echo "Query $CNT: (Bind should be cached)"
+echo "# Query $CNT: (Bind should be cached)" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "dc=example,dc=com" -s SUB -H $URI2 \
+ -D "$USERDN" -w "$UPASSWD" "(sn=je*)" sn >> $SEARCHOUT 2>> $TESTOUT
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+RC=`grep "CACHED BIND for $USERDN" $LOG2 | wc -l`
+if test $RC != 2 ; then
+ echo "Bind wasn't answered from cache"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+ exit 1
+fi
+
+echo "=== New search on (sn=jo*)"
+cat /dev/null > $SEARCHOUT
+echo "# Query $CNT: (Bind should be cached)" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "dc=example,dc=com" -s SUB -H $URI2 \
+ -D "$USERDN" -w "$UPASSWD" "(sn=jo*)" sn >> $SEARCHOUT 2>> $TESTOUT
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+RC=`grep "CACHED BIND for $USERDN" $LOG2 | wc -l`
+if test $RC != 3 ; then
+ echo "Bind wasn't answered from cache"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+ exit 1
+fi
+
+RC=`grep "QUERY NOT ANSWERABLE" $LOG2 | wc -l`
+if test $RC != 3 ; then
+ echo "Search wasn't searched on remote peer"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+ exit 1
+fi
+
+RC=`grep "dn: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com" $SEARCHOUT | wc -l`
+if test $RC != 1 ; then
+ echo "Search wasn't retrieved on remote peer"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+ exit 1
+fi
+
+echo "Test succeeded"
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test066-autoca b/tests/scripts/test066-autoca
new file mode 100755
index 0000000..dd8b502
--- /dev/null
+++ b/tests/scripts/test066-autoca
@@ -0,0 +1,345 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+$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
diff --git a/tests/scripts/test067-tls b/tests/scripts/test067-tls
new file mode 100755
index 0000000..cd99fcf
--- /dev/null
+++ b/tests/scripts/test067-tls
@@ -0,0 +1,304 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $WITH_TLS = no ; then
+ echo "TLS support not available, test skipped"
+ exit 0
+fi
+
+openssl=`command -v openssl 2>/dev/null`
+certtool=`command -v certtool 2>/dev/null`
+base64=`command -v base64 2>/dev/null`
+
+mkdir -p $TESTDIR $DBDIR1
+cp -r $DATADIR/tls $TESTDIR
+
+cd $TESTWD
+
+if test -z "$TLS_PEERKEY_HASHALG"; then
+ TLS_PEERKEY_HASHALG=sha256
+fi
+if test -n "${openssl}"; then
+ TLS_PEERKEY="`"${openssl}" x509 -pubkey -noout -in $TESTDIR/tls/certs/localhost.crt | \
+ "${openssl}" rsa -pubin -outform der 2>/dev/null | \
+ "${openssl}" enc -base64 2>/dev/null`"
+
+ TLS_PEERKEY_HASHED="$TLS_PEERKEY_HASHALG:`"${openssl}" x509 -pubkey -noout -in $TESTDIR/tls/certs/localhost.crt | \
+ "${openssl}" rsa -pubin -outform der 2>/dev/null | \
+ "${openssl}" dgst "-$TLS_PEERKEY_HASHALG" -binary 2>/dev/null | \
+ "${openssl}" enc -base64 2>/dev/null`"
+
+ TLS_PEERKEY_HASHED_FAIL="$TLS_PEERKEY_HASHALG:`echo \"a fake key to hash\" | \
+ "${openssl}" dgst "-$TLS_PEERKEY_HASHALG" -binary 2>/dev/null | \
+ "${openssl}" enc -base64 2>/dev/null`"
+elif test -n "${certtool}" && test -n "${base64}"; then
+ echo "OpenSSL not found, falling back to certtool"
+ echo "This will not exercise hashed pin functionality"
+ TLS_PEERKEY="`"${certtool}" --certificate-pubkey --outder \
+ --infile $TESTDIR/tls/certs/localhost.crt \
+ --load-pubkey $TESTDIR/tls/certs/localhost.crt \
+ | "${base64}"`"
+else
+ echo "No way to extract the public key from certificate, key pinning tests will be skipped..."
+fi
+
+echo "Starting ldap:/// slapd on TCP/IP port $PORT1 and ldaps:/// slapd on $PORT2..."
+. $CONFFILTER $BACKEND < $TLSCONF > $CONF1
+$SLAPD -f $CONF1 -h "$URI1 $SURI2" -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI1 \
+ '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 -n "Using ldapsearch with startTLS with no server cert validation...."
+$LDAPSEARCH -o tls_reqcert=never -ZZ -b "" -s base -H $URIP1 \
+ '@extensibleObject' > $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch (startTLS) failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+else
+ echo "success"
+fi
+
+echo -n "Using ldapsearch with startTLS with hard require cert...."
+$LDAPSEARCH -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -o tls_reqcert=hard -ZZ -b "" -s base -H $URIP1 \
+ '@extensibleObject' > $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch (startTLS) failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+else
+ echo "success"
+fi
+
+if test $WITH_TLS_TYPE = openssl ; then
+ echo -n "Using ldapsearch with startTLS and specific protocol version...."
+ $LDAPSEARCH -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -o tls_reqcert=hard -o tls_protocol_min=3.3 -ZZ -b "" -s base -H $URIP1 \
+ '@extensibleObject' > $SEARCHOUT 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch (protocol-min) failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ else
+ echo "success"
+ fi
+fi
+
+echo -n "Using ldapsearch with StartTLS and pinning enabled but a pin that doesn't match..."
+$LDAPSEARCH -o tls_reqcert=never -o tls_peerkey_hash=abcd -ZZ \
+ -b "" -s base -H $URIP1 '@extensibleObject' > $SEARCHOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "ldapsearch (StartTLS) succeeded when it should have failed($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+else
+ echo "failed correctly with error code ($RC)"
+fi
+
+echo -n "Using ldapsearch with StartTLS and a valid plaintext pin..."
+if test -n "$TLS_PEERKEY"; then
+ $LDAPSEARCH -o tls_reqcert=hard -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt \
+ -o tls_peerkey_hash="${TLS_PEERKEY}" \
+ -ZZ -b "" -s base -H $URIP1 '@extensibleObject' > $SEARCHOUT 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch (StartTLS) failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ else
+ echo "success"
+ fi
+else
+ echo "skipped"
+fi
+
+echo -n "Using ldapsearch with StartTLS and an invalid hashed pin..."
+if test -n "$TLS_PEERKEY_HASHED_FAIL"; then
+ $LDAPSEARCH -o tls_reqcert=hard -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt \
+ -o tls_peerkey_hash="${TLS_PEERKEY_HASHED_FAIL}" \
+ -ZZ -b "" -s base -H $URIP1 '@extensibleObject' > $SEARCHOUT 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ echo "ldapsearch (StartTLS) succeeded when it should have failed($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ else
+ echo "failed correctly with error code ($RC)"
+ fi
+else
+ echo "skipped"
+fi
+
+echo -n "Using ldapsearch with StartTLS and a valid hashed pin..."
+if test -n "$TLS_PEERKEY_HASHED"; then
+ $LDAPSEARCH -o tls_reqcert=hard -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt \
+ -o tls_peerkey_hash="${TLS_PEERKEY_HASHED}" \
+ -ZZ -b "" -s base -H $URIP1 '@extensibleObject' > $SEARCHOUT 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch (StartTLS) failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ else
+ echo "success"
+ fi
+else
+ echo "skipped"
+fi
+
+echo -n "Using ldapsearch on $SURI2 with no server cert validation..."
+$LDAPSEARCH -o tls_reqcert=never -b "cn=Subschema" -s base -H $SURIP2 \
+ '(&(objectClasses=top)(objectClasses=2.5.6.0))' cn objectClass \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch (ldaps) failed($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+else
+ echo "success"
+fi
+
+echo -n "Using ldapsearch on $SURI2 with reqcert HARD and no CA cert. Should fail..."
+$LDAPSEARCH -o tls_reqcert=hard -b "cn=Subschema" -s base -H $SURIP2 \
+ '(&(objectClasses=top)(objectClasses=2.5.6.0))' cn objectClass \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "ldapsearch (ldaps) succeeded when it should have failed($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+else
+ echo "failed correctly with error code ($RC)"
+fi
+
+echo -n "Using ldapsearch on $SURI2 with CA cert and reqcert HARD..."
+$LDAPSEARCH -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -o tls_reqcert=hard -b "cn=Subschema" -s base -H $SURIP2 \
+ '(&(objectClasses=top)(objectClasses=2.5.6.0))' cn objectClass \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch (ldaps) failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+else
+ echo "success"
+fi
+
+echo -n "Using ldapsearch on $SURI2 with pinning enabled but a pin that doesn't match..."
+$LDAPSEARCH -o tls_reqcert=never -o tls_peerkey_hash=abcd \
+ -b "cn=Subschema" -s base -H $SURIP2 \
+ '(&(objectClasses=top)(objectClasses=2.5.6.0))' cn objectClass \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+ echo "ldapsearch (ldaps) succeeded when it should have failed($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+else
+ echo "failed correctly with error code ($RC)"
+fi
+
+echo -n "Using ldapsearch on $SURI2 with a valid plaintext pin..."
+if test -n "$TLS_PEERKEY"; then
+ $LDAPSEARCH -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -o tls_reqcert=hard \
+ -o tls_peerkey_hash="${TLS_PEERKEY}" -b "cn=Subschema" -s base -H $SURIP2 \
+ '(&(objectClasses=top)(objectClasses=2.5.6.0))' cn objectClass \
+ >> $SEARCHOUT 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch (ldaps) failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ else
+ echo "success"
+ fi
+else
+ echo "skipped"
+fi
+
+echo -n "Using ldapsearch on $SURI2 with an invalid hashed pin..."
+if test -n "$TLS_PEERKEY_HASHED_FAIL"; then
+ $LDAPSEARCH -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -o tls_reqcert=hard \
+ -o tls_peerkey_hash="${TLS_PEERKEY_HASHED_FAIL}" -b "cn=Subschema" -s base -H $SURIP2 \
+ '(&(objectClasses=top)(objectClasses=2.5.6.0))' cn objectClass \
+ >> $SEARCHOUT 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ echo "ldapsearch (ldaps) succeeded when it should have failed($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ else
+ echo "failed correctly with error code ($RC)"
+ fi
+else
+ echo "skipped"
+fi
+
+echo -n "Using ldapsearch on $SURI2 with a valid hashed pin..."
+if test -n "$TLS_PEERKEY_HASHED"; then
+ $LDAPSEARCH -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -o tls_reqcert=hard \
+ -o tls_peerkey_hash="${TLS_PEERKEY_HASHED}" -b "cn=Subschema" -s base -H $SURIP2 \
+ '(&(objectClasses=top)(objectClasses=2.5.6.0))' cn objectClass \
+ >> $SEARCHOUT 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapsearch (ldaps) failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ else
+ echo "success"
+ fi
+else
+ echo "skipped"
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+RC=0
+
+test $KILLSERVERS != no && wait
+
+exit $RC
diff --git a/tests/scripts/test068-sasl-tls-external b/tests/scripts/test068-sasl-tls-external
new file mode 100755
index 0000000..f79471b
--- /dev/null
+++ b/tests/scripts/test068-sasl-tls-external
@@ -0,0 +1,129 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $WITH_TLS = no ; then
+ echo "TLS support not available, test skipped"
+ exit 0
+fi
+
+if test $WITH_SASL = no ; then
+ echo "SASL support not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+cp -r $DATADIR/tls $TESTDIR
+
+cd $TESTWD
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $TLSSASLCONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting ldap:/// slapd on TCP/IP port $PORT1 and ldaps:/// slapd on $PORT2..."
+$SLAPD -f $CONF1 -h "$URI1 $SURI2" -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI1 \
+ '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 -n "Using ldapwhoami with SASL/EXTERNAL...."
+$LDAPSASLWHOAMI -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -o tls_reqcert=hard \
+ -o tls_cert=$TESTDIR/tls/certs/bjensen@mailgw.example.com.crt -o tls_key=$TESTDIR/tls/private/bjensen@mailgw.example.com.key -ZZ -Y EXTERNAL -H $URIP1 \
+ > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami (startTLS) failed ($RC)!"
+ exit $RC
+else
+ echo "success"
+fi
+
+echo -n "Validating mapped SASL ID..."
+echo 'dn:cn=barbara jensen,ou=information technology division,ou=people,dc=example,dc=com' > $TESTDIR/dn.out
+$CMP $TESTDIR/dn.out $TESTOUT > $CMPOUT
+
+RC=$?
+if test $RC != 0 ; then
+ echo "Comparison failed"
+ test $KILLSERVERS != no && kill -HUP $PID
+ exit $RC
+else
+ echo "success"
+fi
+
+# Exercise channel-bindings code in builds without SASL support
+for cb in "none" "tls-unique" "tls-endpoint" ; do
+
+ echo -n "Using ldapwhoami with SASL/EXTERNAL and SASL_CBINDING (${cb})...."
+
+ $LDAPSASLWHOAMI -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt \
+ -o tls_cert=$TESTDIR/tls/certs/bjensen@mailgw.example.com.crt \
+ -o tls_key=$TESTDIR/tls/private/bjensen@mailgw.example.com.key \
+ -o tls_reqcert=hard -o SASL_CBINDING=$cb -ZZ -Y EXTERNAL -H $URIP1 \
+ > $TESTOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $PID
+ exit $RC
+ else
+ echo "success"
+ fi
+done
+
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $RC != 0 ; then
+ echo ">>>>> Test failed"
+else
+ echo ">>>>> Test succeeded"
+ RC=0
+fi
+
+test $KILLSERVERS != no && wait
+
+exit $RC
diff --git a/tests/scripts/test069-delta-multiprovider-starttls b/tests/scripts/test069-delta-multiprovider-starttls
new file mode 100755
index 0000000..277c0a7
--- /dev/null
+++ b/tests/scripts/test069-delta-multiprovider-starttls
@@ -0,0 +1,581 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $WITH_TLS = no ; then
+ echo "TLS support not available, test skipped"
+ exit 0
+fi
+
+if test $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+if test $ACCESSLOG = accesslogno; then
+ echo "Accesslog overlay not available, test skipped"
+ exit 0
+fi
+
+MMR=2
+
+XDIR=$TESTDIR/srv
+TMP=$TESTDIR/tmp
+
+mkdir -p $TESTDIR
+cp -r $DATADIR/tls $TESTDIR
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+if test x"$SYNCMODE" = x ; then
+ SYNCMODE=rp
+fi
+case "$SYNCMODE" in
+ ro)
+ SYNCTYPE="type=refreshOnly interval=00:00:00:03"
+ ;;
+ rp)
+ SYNCTYPE="type=refreshAndPersist interval=00:00:00:03"
+ ;;
+ *)
+ echo "unknown sync mode $SYNCMODE"
+ exit 1;
+ ;;
+esac
+
+#
+# Test delta-sync mmr
+# - start servers
+# - configure over ldap
+# - populate over ldap
+# - configure syncrepl over ldap
+# - break replication
+# - modify each server separately
+# - restore replication
+# - compare results
+#
+
+nullExclude=""
+test $BACKEND = null && nullExclude="# "
+
+KILLPIDS=
+
+echo "Initializing server configurations..."
+n=1
+while [ $n -le $MMR ]; do
+
+DBDIR=${XDIR}$n/db
+CFDIR=${XDIR}$n/slapd.d
+
+mkdir -p ${XDIR}$n $DBDIR.1 $DBDIR.2 $CFDIR
+
+o=`expr 3 - $n`
+cat > $TMP <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+olcServerID: $n
+olcTLSCertificateFile: $TESTDIR/tls/certs/localhost.crt
+olcTLSCertificateKeyFile: $TESTDIR/tls/private/localhost.key
+
+EOF
+
+if [ "$SYNCPROV" = syncprovmod -o "$ACCESSLOG" = accesslogmod ]; then
+ cat <<EOF >> $TMP
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+EOF
+ if [ "$SYNCPROV" = syncprovmod ]; then
+ echo "olcModuleLoad: syncprov.la" >> $TMP
+ fi
+ if [ "$ACCESSLOG" = accesslogmod ]; then
+ echo "olcModuleLoad: accesslog.la" >> $TMP
+ fi
+ echo "" >> $TMP
+fi
+
+if [ "$BACKENDTYPE" = mod ]; then
+cat <<EOF >> $TMP
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/back-$BACKEND
+olcModuleLoad: back_$BACKEND.la
+
+EOF
+fi
+MYURI=`eval echo '$URI'$n`
+PROVIDERURI=`eval echo '$URIP'$o`
+if test $INDEXDB = indexdb ; then
+INDEX1="olcDbIndex: objectClass,entryCSN,reqStart,reqDN,reqResult eq"
+INDEX2="olcDbIndex: objectClass,entryCSN,entryUUID eq"
+else
+INDEX1=
+INDEX2=
+fi
+cat >> $TMP <<EOF
+dn: cn=schema,cn=config
+objectclass: olcSchemaconfig
+cn: schema
+
+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
+
+dn: olcDatabase={0}config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW:< file://$CONFIGPWF
+
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+olcSuffix: cn=log
+${nullExclude}olcDbDirectory: ${DBDIR}.1
+olcRootDN: $MANAGERDN
+$INDEX1
+
+dn: olcOverlay=syncprov,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+olcSpNoPresent: TRUE
+olcSpReloadHint: TRUE
+
+dn: olcDatabase={2}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {2}$BACKEND
+olcSuffix: $BASEDN
+${nullExclude}olcDbDirectory: ${DBDIR}.2
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+olcSyncRepl: rid=001 provider=$PROVIDERURI binddn="$MANAGERDN" bindmethod=simple
+ credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE
+ retry="3 +" timeout=3 logbase="cn=log"
+ logfilter="(&(objectclass=auditWriteObject)(reqresult=0))"
+ syncdata=accesslog tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt
+ starttls=critical
+olcMultiProvider: TRUE
+$INDEX2
+
+dn: olcOverlay=syncprov,olcDatabase={2}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+
+dn: olcOverlay=accesslog,olcDatabase={2}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcAccessLogConfig
+olcOverlay: accesslog
+olcAccessLogDB: cn=log
+olcAccessLogOps: writes
+olcAccessLogSuccess: TRUE
+
+EOF
+
+$SLAPADD -F $CFDIR -n 0 -d-1< $TMP > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+PORT=`eval echo '$PORT'$n`
+echo "Starting server $n on TCP/IP port $PORT..."
+cd ${XDIR}${n}
+LOG=`eval echo '$LOG'$n`
+$SLAPD -F slapd.d -h $MYURI -d $LVL > $LOG 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID $KILLPIDS"
+cd $TESTWD
+
+echo "Using ldapsearch to check that server $n is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $MYURI \
+ '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
+
+if [ $n = 1 ]; then
+echo "Using ldapadd for context on server 1..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $LDIFORDEREDCP \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server $n database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+fi
+
+n=`expr $n + 1`
+done
+
+echo "Using ldapadd to populate server 1..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $LDIFORDEREDNOCP \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server $n database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+n=1
+while [ $n -le $MMR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MMR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+echo "Using ldapadd to populate server 2..."
+$LDAPADD -D "$MANAGERDN" -H $URI2 -w $PASSWD -f $LDIFADD1 \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+THEDN="cn=James A Jones 2,ou=Alumni Association,ou=People,dc=example,dc=com"
+sleep 1
+for i in 1 2 3; do
+ $LDAPSEARCH -S "" -b "$THEDN" -H $URI1 \
+ -s base '(objectClass=*)' entryCSN > "${PROVIDEROUT}.$i" 2>&1
+ RC=$?
+
+ if test $RC = 0 ; then
+ break
+ fi
+
+ if test $RC != 32 ; then
+ echo "ldapsearch failed at replica ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+done
+
+n=1
+while [ $n -le $MMR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MMR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+echo "Breaking replication between server 1 and 2..."
+n=1
+while [ $n -le $MMR ]; do
+o=`expr 3 - $n`
+MYURI=`eval echo '$URI'$n`
+PROVIDERURI=`eval echo '$URIP'$o`
+$LDAPMODIFY -D cn=config -H $MYURI -y $CONFIGPWF > $TESTOUT 2>&1 <<EOF
+dn: olcDatabase={2}$BACKEND,cn=config
+changetype: modify
+replace: olcSyncRepl
+olcSyncRepl: rid=001 provider=$PROVIDERURI binddn="$MANAGERDN" bindmethod=simple
+ credentials=InvalidPw searchbase="$BASEDN" $SYNCTYPE
+ retry="3 +" timeout=3 logbase="cn=log"
+ logfilter="(&(objectclass=auditWriteObject)(reqresult=0))"
+ syncdata=accesslog tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt
+ starttls=critical
+-
+replace: olcMultiProvider
+olcMultiProvider: TRUE
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server $n config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+n=`expr $n + 1`
+done
+
+echo "Using ldapmodify to force conflicts between server 1 and 2..."
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: description
+description: Amazing
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI2 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: description
+description: Stupendous
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+delete: description
+description: Outstanding
+-
+add: description
+description: Mindboggling
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI2 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+delete: description
+description: OutStanding
+-
+add: description
+description: Bizarre
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: carLicense
+carLicense: 123-XYZ
+-
+add: employeeNumber
+employeeNumber: 32
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI2 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: employeeType
+employeeType: deadwood
+-
+add: employeeNumber
+employeeNumber: 64
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+replace: sn
+sn: Replaced later
+-
+replace: sn
+sn: Surname
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Restoring replication between server 1 and 2..."
+n=1
+while [ $n -le $MMR ]; do
+o=`expr 3 - $n`
+MYURI=`eval echo '$URI'$n`
+PROVIDERURI=`eval echo '$URIP'$o`
+$LDAPMODIFY -D cn=config -H $MYURI -y $CONFIGPWF > $TESTOUT 2>&1 <<EOF
+dn: olcDatabase={2}$BACKEND,cn=config
+changetype: modify
+replace: olcSyncRepl
+olcSyncRepl: rid=001 provider=$PROVIDERURI binddn="$MANAGERDN" bindmethod=simple
+ credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE
+ retry="3 +" timeout=3 logbase="cn=log"
+ logfilter="(&(objectclass=auditWriteObject)(reqresult=0))"
+ syncdata=accesslog tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt
+ starttls=critical
+-
+replace: olcMultiProvider
+olcMultiProvider: TRUE
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server $n config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+n=`expr $n + 1`
+done
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+n=1
+while [ $n -le $MMR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldap://${LOCALHOST}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER -s a < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MMR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test070-delta-multiprovider-ldaps b/tests/scripts/test070-delta-multiprovider-ldaps
new file mode 100755
index 0000000..3fb96cc
--- /dev/null
+++ b/tests/scripts/test070-delta-multiprovider-ldaps
@@ -0,0 +1,577 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $WITH_TLS = no ; then
+ echo "TLS support not available, test skipped"
+ exit 0
+fi
+
+if test $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+if test $ACCESSLOG = accesslogno; then
+ echo "Accesslog overlay not available, test skipped"
+ exit 0
+fi
+
+MMR=2
+
+XDIR=$TESTDIR/srv
+TMP=$TESTDIR/tmp
+
+mkdir -p $TESTDIR
+cp -r $DATADIR/tls $TESTDIR
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+if test x"$SYNCMODE" = x ; then
+ SYNCMODE=rp
+fi
+case "$SYNCMODE" in
+ ro)
+ SYNCTYPE="type=refreshOnly interval=00:00:00:03"
+ ;;
+ rp)
+ SYNCTYPE="type=refreshAndPersist interval=00:00:00:03"
+ ;;
+ *)
+ echo "unknown sync mode $SYNCMODE"
+ exit 1;
+ ;;
+esac
+
+#
+# Test delta-sync mmr
+# - start servers
+# - configure over ldap
+# - populate over ldap
+# - configure syncrepl over ldap
+# - break replication
+# - modify each server separately
+# - restore replication
+# - compare results
+#
+
+nullExclude=""
+test $BACKEND = null && nullExclude="# "
+
+KILLPIDS=
+
+echo "Initializing server configurations..."
+n=1
+while [ $n -le $MMR ]; do
+
+DBDIR=${XDIR}$n/db
+CFDIR=${XDIR}$n/slapd.d
+
+mkdir -p ${XDIR}$n $DBDIR.1 $DBDIR.2 $CFDIR
+
+o=`expr 3 - $n`
+cat > $TMP <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+olcServerID: $n
+olcTLSCertificateFile: $TESTDIR/tls/certs/localhost.crt
+olcTLSCertificateKeyFile: $TESTDIR/tls/private/localhost.key
+
+EOF
+
+if [ "$SYNCPROV" = syncprovmod -o "$ACCESSLOG" = accesslogmod ]; then
+ cat <<EOF >> $TMP
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+EOF
+ if [ "$SYNCPROV" = syncprovmod ]; then
+ echo "olcModuleLoad: syncprov.la" >> $TMP
+ fi
+ if [ "$ACCESSLOG" = accesslogmod ]; then
+ echo "olcModuleLoad: accesslog.la" >> $TMP
+ fi
+ echo "" >> $TMP
+fi
+
+if [ "$BACKENDTYPE" = mod ]; then
+cat <<EOF >> $TMP
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/back-$BACKEND
+olcModuleLoad: back_$BACKEND.la
+
+EOF
+fi
+MYURI=`eval echo '$SURIP'$n`
+PROVIDERURI=`eval echo '$SURIP'$o`
+if test $INDEXDB = indexdb ; then
+INDEX1="olcDbIndex: objectClass,entryCSN,reqStart,reqDN,reqResult eq"
+INDEX2="olcDbIndex: objectClass,entryCSN,entryUUID eq"
+else
+INDEX1=
+INDEX2=
+fi
+cat >> $TMP <<EOF
+dn: cn=schema,cn=config
+objectclass: olcSchemaconfig
+cn: schema
+
+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
+
+dn: olcDatabase={0}config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW:< file://$CONFIGPWF
+
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+olcSuffix: cn=log
+${nullExclude}olcDbDirectory: ${DBDIR}.1
+olcRootDN: $MANAGERDN
+$INDEX1
+
+dn: olcOverlay=syncprov,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+olcSpNoPresent: TRUE
+olcSpReloadHint: TRUE
+
+dn: olcDatabase={2}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {2}$BACKEND
+olcSuffix: $BASEDN
+${nullExclude}olcDbDirectory: ${DBDIR}.2
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+olcSyncRepl: rid=001 provider=$PROVIDERURI binddn="$MANAGERDN" bindmethod=simple
+ credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE
+ retry="3 +" timeout=3 logbase="cn=log"
+ logfilter="(&(objectclass=auditWriteObject)(reqresult=0))"
+ syncdata=accesslog tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt
+olcMultiProvider: TRUE
+$INDEX2
+
+dn: olcOverlay=syncprov,olcDatabase={2}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+
+dn: olcOverlay=accesslog,olcDatabase={2}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcAccessLogConfig
+olcOverlay: accesslog
+olcAccessLogDB: cn=log
+olcAccessLogOps: writes
+olcAccessLogSuccess: TRUE
+
+EOF
+$SLAPADD -F $CFDIR -n 0 -d-1< $TMP > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+PORT=`eval echo '$PORT'$n`
+echo "Starting server $n on TCP/IP port $PORT..."
+cd ${XDIR}${n}
+LOG=`eval echo '$LOG'$n`
+$SLAPD -F slapd.d -h $MYURI -d $LVL > $LOG 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID $KILLPIDS"
+cd $TESTWD
+
+echo "Using ldapsearch to check that server $n is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -s base -b "" -H $MYURI \
+ '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
+
+if [ $n = 1 ]; then
+echo "Using ldapadd for context on server 1..."
+$LDAPADD -D "$MANAGERDN" -H $SURIP1 -w $PASSWD -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -f $LDIFORDEREDCP \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server $n database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+fi
+
+n=`expr $n + 1`
+done
+
+echo "Using ldapadd to populate server 1..."
+$LDAPADD -D "$MANAGERDN" -H $SURIP1 -w $PASSWD -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -f $LDIFORDEREDNOCP \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server $n database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+n=1
+while [ $n -le $MMR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldaps://${LOCALIP}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MMR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+echo "Using ldapadd to populate server 2..."
+$LDAPADD -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -D "$MANAGERDN" -H $SURIP2 -w $PASSWD -f $LDIFADD1 \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+THEDN="cn=James A Jones 2,ou=Alumni Association,ou=People,dc=example,dc=com"
+sleep 1
+for i in 1 2 3; do
+ $LDAPSEARCH -S "" -b "$THEDN" -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -H $SURIP1 \
+ -s base '(objectClass=*)' entryCSN > "${PROVIDEROUT}.$i" 2>&1
+ RC=$?
+
+ if test $RC = 0 ; then
+ break
+ fi
+
+ if test $RC != 32 ; then
+ echo "ldapsearch failed at replica ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+done
+
+n=1
+while [ $n -le $MMR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldaps://${LOCALIP}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MMR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+echo "Breaking replication between server 1 and 2..."
+n=1
+while [ $n -le $MMR ]; do
+o=`expr 3 - $n`
+MYURI=`eval echo '$SURIP'$n`
+PROVIDERURI=`eval echo '$SURIP'$o`
+$LDAPMODIFY -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -D cn=config -H $MYURI -y $CONFIGPWF > $TESTOUT 2>&1 <<EOF
+dn: olcDatabase={2}$BACKEND,cn=config
+changetype: modify
+replace: olcSyncRepl
+olcSyncRepl: rid=001 provider=$PROVIDERURI binddn="$MANAGERDN" bindmethod=simple
+ credentials=InvalidPw searchbase="$BASEDN" $SYNCTYPE
+ retry="3 +" timeout=3 logbase="cn=log"
+ logfilter="(&(objectclass=auditWriteObject)(reqresult=0))"
+ syncdata=accesslog tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt
+-
+replace: olcMultiProvider
+olcMultiProvider: TRUE
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server $n config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+n=`expr $n + 1`
+done
+
+echo "Using ldapmodify to force conflicts between server 1 and 2..."
+$LDAPMODIFY -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -D "$MANAGERDN" -H $SURIP1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: description
+description: Amazing
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -D "$MANAGERDN" -H $SURIP2 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: description
+description: Stupendous
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -D "$MANAGERDN" -H $SURIP1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+delete: description
+description: Outstanding
+-
+add: description
+description: Mindboggling
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -D "$MANAGERDN" -H $SURIP2 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+delete: description
+description: OutStanding
+-
+add: description
+description: Bizarre
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -D "$MANAGERDN" -H $SURIP1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: carLicense
+carLicense: 123-XYZ
+-
+add: employeeNumber
+employeeNumber: 32
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -D "$MANAGERDN" -H $SURIP2 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: employeeType
+employeeType: deadwood
+-
+add: employeeNumber
+employeeNumber: 64
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -D "$MANAGERDN" -H $SURIP1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+replace: sn
+sn: Replaced later
+-
+replace: sn
+sn: Surname
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Restoring replication between server 1 and 2..."
+n=1
+while [ $n -le $MMR ]; do
+o=`expr 3 - $n`
+MYURI=`eval echo '$SURIP'$n`
+PROVIDERURI=`eval echo '$SURIP'$o`
+$LDAPMODIFY -D cn=config -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -H $MYURI -y $CONFIGPWF > $TESTOUT 2>&1 <<EOF
+dn: olcDatabase={2}$BACKEND,cn=config
+changetype: modify
+replace: olcSyncRepl
+olcSyncRepl: rid=001 provider=$PROVIDERURI binddn="$MANAGERDN" bindmethod=simple
+ credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE
+ retry="3 +" timeout=3 logbase="cn=log"
+ logfilter="(&(objectclass=auditWriteObject)(reqresult=0))"
+ syncdata=accesslog tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt
+-
+replace: olcMultiProvider
+olcMultiProvider: TRUE
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server $n config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+n=`expr $n + 1`
+done
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+n=1
+while [ $n -le $MMR ]; do
+PORT=`expr $BASEPORT + $n`
+URI="ldaps://${LOCALIP}:$PORT/"
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER -s a < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MMR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test071-dirsync b/tests/scripts/test071-dirsync
new file mode 100755
index 0000000..455629b
--- /dev/null
+++ b/tests/scripts/test071-dirsync
@@ -0,0 +1,377 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+# requires MSAD_URI, MSAD_SUFFIX, MSAD_ADMINDN, MSAD_ADMINPW
+if test -z "$MSAD_URI"; then
+ echo "No MSAD envvars set, test skipped"
+ exit 0
+fi
+if test $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR2
+
+URI1=$MSAD_URI
+BASEDN="ou=OpenLDAPtest,$MSAD_SUFFIX"
+DC=`echo $MSAD_SUFFIX | sed -e 's/dc=//' -e 's/,.*//'`
+
+#
+# Test replication:
+# - populate MSAD over ldap
+# - start consumer
+# - perform some modifies and deletes
+# - attempt to modify the consumer (referral)
+# - retrieve database over ldap and compare against expected results
+#
+
+# Notes:
+# We use a separate OU under the MSAD suffix to contain our test objects,
+# since we can't just wipe out the entire directory when starting over.
+# The replication search filter is thus more convoluted than would normally
+# be needed. Typically it would only need (|(objectclass=user)(objectclass=group))
+#
+# MSAD does referential integrity by default, so to get 1-to-1 modifications
+# we must add users before creating groups that reference them, and we
+# should delete group memberships before deleting users. If we delete
+# users first, MSAD will automatically remove them from their groups,
+# but won't notify us of these changed groups.
+# We could use the refint overlay to duplicate this behavior, but that's
+# beyond the scope of this test.
+
+echo "Using ldapsearch to check that MSAD is running..."
+$LDAPSEARCH -D $MSAD_ADMINDN -w $MSAD_ADMINPW -s base -b "$MSAD_SUFFIX" -H $MSAD_URI 'objectclass=*' > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+echo "Using ldapdelete to delete old MSAD test tree, if any..."
+$LDAPDELETE -D "$MSAD_ADMINDN" -H $MSAD_URI -w $MSAD_ADMINPW -r "$BASEDN"
+RC=$?
+
+echo "Using ldapadd to create the test context entry in MSAD..."
+sed -e "s/dc=example,dc=com/$MSAD_SUFFIX/" < $LDIFDIRSYNCCP | \
+ $LDAPADD -D "$MSAD_ADMINDN" -H $MSAD_URI -w $MSAD_ADMINPW > /dev/null 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting consumer slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $DIRSYNC1CONF | . $CONFDIRSYNC > $CONF2
+$SLAPADD -f $CONF2 <<EOMODS
+dn: $MSAD_SUFFIX
+dc: $DC
+objectclass: organization
+objectclass: dcObject
+o: OpenLDAP Testing
+
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '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 "Using ldapsearch to check that consumer received context entry..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$BASEDN" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for syncrepl to catch up..."
+ sleep 5
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapadd to populate MSAD..."
+sed -e "s/dc=example,dc=com/$BASEDN/" < $LDIFDIRSYNCNOCP | \
+ $LDAPADD -D "$MSAD_ADMINDN" -H $MSAD_URI -w $MSAD_ADMINPW > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapmodify to modify provider directory..."
+
+#
+# Do some modifications
+#
+
+$LDAPMODIFY -v -H $MSAD_URI -D "$MSAD_ADMINDN" -w $MSAD_ADMINPW > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, $BASEDN
+changetype: modify
+add: carLicense
+carLicense: Orange Juice
+-
+delete: sn
+sn: Jones
+-
+add: sn
+sn: Jones
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, $BASEDN
+changetype: modify
+replace: carLicense
+carLicense: Iced Tea
+carLicense: Mad Dog 20/20
+
+dn: cn=ITD Staff,ou=Groups,$BASEDN
+changetype: modify
+delete: uniquemember
+uniquemember: cn=James A Jones 2, ou=Information Technology Division, ou=People, $BASEDN
+uniquemember: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, $BASEDN
+-
+add: uniquemember
+uniquemember: cn=Dorothy Stevens, ou=Alumni Association, ou=People, $BASEDN
+uniquemember: cn=James A Jones 1, ou=Alumni Association, ou=People, $BASEDN
+
+dn: cn=All Staff,ou=Groups,$BASEDN
+changetype: modify
+replace: description
+description: The whole universe
+-
+delete: member
+member: cn=James A Jones 2,ou=Information Technology Division,ou=People,$BASEDN
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, $BASEDN
+changetype: add
+objectclass: inetorgperson
+objectclass: domainrelatedobject
+cn: Gern Jensen
+sn: Jensen
+uid: gjensen
+title: Chief Investigator, ITD
+postaladdress: ITD $ 535 W. William St $ Ann Arbor, MI 48103
+seealso: cn=All Staff, ou=Groups, $BASEDN
+carLicense: Coffee
+homepostaladdress: 844 Brown St. Apt. 4 $ Ann Arbor, MI 48104
+description: Very odd
+facsimiletelephonenumber: +1 313 555 7557
+telephonenumber: +1 313 555 8343
+mail: gjensen@mailgw.example.com
+homephone: +1 313 555 8844
+associateddomain: test.openldap.org
+
+dn: ou=Retired, ou=People, $BASEDN
+changetype: add
+objectclass: organizationalUnit
+ou: Retired
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, $BASEDN
+changetype: add
+objectclass: inetorgperson
+objectclass: domainrelatedobject
+cn: Rosco P. Coltrane
+sn: Coltrane
+uid: rosco
+associateddomain: test.openldap.org
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, $BASEDN
+changetype: modrdn
+newrdn: cn=Rosco P. Coltrane
+deleteoldrdn: 1
+newsuperior: ou=Retired, ou=People, $BASEDN
+
+dn: ou=testdomain1,$BASEDN
+changetype: modrdn
+newrdn: ou=itsdomain1
+deleteoldrdn: 1
+
+dn: ou=itsdomain1,$BASEDN
+changetype: modify
+replace: description
+description: Example, Inc. ITS test domain
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Performing modrdn alone on the provider..."
+$LDAPMODIFY -v -H $MSAD_URI -D "$MSAD_ADMINDN" -w $MSAD_ADMINPW > \
+ $TESTOUT 2>&1 << EOMODS
+dn: ou=testdomain2,$BASEDN
+changetype: modrdn
+newrdn: ou=itsdomain2
+deleteoldrdn: 1
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Performing modify alone on the provider..."
+$LDAPMODIFY -v -H $MSAD_URI -D "$MSAD_ADMINDN" -w $MSAD_ADMINPW > \
+ $TESTOUT 2>&1 << EOMODS
+dn: ou=itsdomain2,$BASEDN
+changetype: modify
+replace: description
+description: Example, Inc. itsdomain2 test domain
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Performing larger modify on the provider..."
+$LDAPMODIFY -v -H $MSAD_URI -D "$MSAD_ADMINDN" -w $MSAD_ADMINPW > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, $BASEDN
+changetype: delete
+
+dn: cn=Alumni Assoc Staff,ou=Groups,$BASEDN
+changetype: modify
+replace: description
+description: blablabla
+-
+replace: member
+member: cn=Manager,$BASEDN
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,$BASEDN
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,$BASEDN
+member: cn=Jane Doe,ou=Alumni Association,ou=People,$BASEDN
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,$BASEDN
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,$BASEDN
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,$BASEDN
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+OPATTRS="entryUUID creatorsName createTimestamp modifiersName modifyTimestamp"
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -D $MSAD_ADMINDN -w $MSAD_ADMINPW -S "" -H $MSAD_URI -b "$MSAD_SUFFIX" -E \!dirsync=0/0 -o ldif_wrap=120 \
+ '(associatedDomain=test.openldap.org)' > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 -o ldif_wrap=120 \
+ '(objectclass=*)' > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo "Filtering provider results..."
+$LDIFFILTER -s a < $PROVIDEROUT | sed -e 's/CN=/cn=/g' -e 's/OU=/ou=/g' -e 's/DC=/dc=/g' > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER -s a < $CONSUMEROUT > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test072-dsee-sync b/tests/scripts/test072-dsee-sync
new file mode 100755
index 0000000..bb3ba7a
--- /dev/null
+++ b/tests/scripts/test072-dsee-sync
@@ -0,0 +1,331 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+DSADM=`command -v dsadm`
+if test -z "$DSADM"; then
+ echo "DSEE dsadm not in path, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR2
+
+#
+# Test replication:
+# - start provider
+# - start consumer
+# - populate over ldap
+# - perform some modifies and deleted
+# - attempt to modify the consumer (referral)
+# - retrieve database over ldap and compare against expected results
+#
+
+DSEEPW=secret21
+DSEEDN="cn=Directory Manager"
+DSEEPWF=$TESTDIR/dseepw
+
+echo "secret21" > $DSEEPWF
+
+echo "Setting up DSEE provider slapd on TCP/IP port $PORT1..."
+dsadm create -p $PORT1 -w $DSEEPWF $DBDIR1
+dsadm start $DBDIR1
+dsconf create-suffix -c -p $PORT1 -w $DSEEPWF $BASEDN
+dsconf set-server-prop -p $PORT1 -w $DSEEPWF moddn-enabled:on
+dsconf set-server-prop -p $PORT1 -w $DSEEPWF retro-cl-enabled:on
+dsadm restart $DBDIR1
+KILLPIDS=`basename $DBDIR1/locks/server/*`
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$BASEDN" -H $URI1 \
+ '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 "Starting consumer slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $DSEESYNC1CONF > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ '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
+
+# using LDIFDIRSYNCNOCP to avoid custom OpenLDAP schema
+echo "Using ldapadd to populate the provider directory..."
+$LDAPADD -D "$DSEEDN" -H $URI1 -w $DSEEPW < \
+ $LDIFDIRSYNCNOCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapmodify to modify provider directory..."
+
+#
+# Do some modifications
+#
+
+$LDAPMODIFY -v -D "$DSEEDN" -H $URI1 -w $DSEEPW > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+changetype: modify
+add: carLicense
+carLicense: Orange Juice
+-
+delete: sn
+sn: Jones
+-
+add: sn
+sn: Jones
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: carLicense
+carLicense: Iced Tea
+carLicense: Mad Dog 20/20
+
+dn: cn=ITD Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: uniquemember
+uniquemember: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+uniquemember: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+-
+add: uniquemember
+uniquemember: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com
+uniquemember: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com
+
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: description
+
+dn: cn=Gern Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com
+changetype: add
+objectclass: inetOrgPerson
+cn: Gern Jensen
+sn: Jensen
+uid: gjensen
+title: Chief Investigator, ITD
+postaladdress: ITD $ 535 W. William St $ Ann Arbor, MI 48103
+seealso: cn=All Staff,ou=Groups,dc=example,dc=com
+carLicense: Coffee
+homepostaladdress: 844 Brown St. Apt. 4 $ Ann Arbor, MI 48104
+description: Very odd
+facsimiletelephonenumber: +1 313 555 7557
+telephonenumber: +1 313 555 8343
+mail: gjensen@mailgw.example.com
+homephone: +1 313 555 8844
+
+dn: ou=Retired,ou=People,dc=example,dc=com
+changetype: add
+objectclass: organizationalUnit
+ou: Retired
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: inetOrgPerson
+cn: Rosco P. Coltrane
+sn: Coltrane
+uid: rosco
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Rosco P. Coltrane
+deleteoldrdn: 1
+newsuperior: ou=Retired,ou=People,dc=example,dc=com
+
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: delete
+
+dn: ou=testdomain1,dc=example,dc=com
+changetype: modrdn
+newrdn: ou=itsdomain1
+deleteoldrdn: 1
+
+dn: ou=itsdomain1,dc=example,dc=com
+changetype: modify
+replace: description
+description: Example, Inc. ITS test domain
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Performing modrdn alone on the provider..."
+$LDAPMODIFY -v -D "$DSEEDN" -H $URI1 -w $DSEEPW > \
+ $TESTOUT 2>&1 << EOMODS
+dn: ou=testdomain2,dc=example,dc=com
+changetype: modrdn
+newrdn: ou=itsdomain2
+deleteoldrdn: 1
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Performing modify alone on the provider..."
+$LDAPMODIFY -v -D "$DSEEDN" -H $URI1 -w $DSEEPW > \
+ $TESTOUT 2>&1 << EOMODS
+dn: ou=itsdomain2,dc=example,dc=com
+changetype: modify
+replace: description
+description: Example, Inc. itsdomain2 test domain
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Performing larger modify on the provider..."
+$LDAPMODIFY -v -D "$DSEEDN" -H $URI1 -w $DSEEPW > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Alumni Assoc Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+replace: cn
+cn: Alumni Assoc Staff
+-
+replace: description
+description: blablabla
+-
+replace: member
+member: cn=Manager,dc=example,dc=com
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+OPATTRS="creatorsName createTimestamp modifiersName modifyTimestamp"
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -D "$DSEEDN" -w $DSEEPW \
+ '(objectclass=*)' '*' $OPATTRS > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI2 \
+ '(objectclass=*)' '*' $OPATTRS > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo "Filtering provider results..."
+$LDIFFILTER -s a < $PROVIDEROUT > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER -s a < $CONSUMEROUT > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test073-asyncmeta b/tests/scripts/test073-asyncmeta
new file mode 100755
index 0000000..eabd4a3
--- /dev/null
+++ b/tests/scripts/test073-asyncmeta
@@ -0,0 +1,620 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+echo ""
+
+if test $BACKASYNCMETA = asyncmetano ; then
+ echo "asyncmeta backend not available, test skipped"
+ exit 0
+fi
+
+if test $BACKLDAP = ldapno ; then
+ echo "ldap backend not available, test skipped"
+ exit 0
+fi
+
+rm -rf $TESTDIR
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $METACONF1 > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ '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 "Using ldapadd to populate the database..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDERED > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $METACONF2 > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+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 "$MONITOR" -H $URI2 \
+ '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 "Using ldapadd to populate the database..."
+$LDAPADD -D "$METAMANAGERDN" -H $URI2 -w $PASSWD < \
+ $LDIFMETA >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT3..."
+. $CONFFILTER $BACKEND < $ASYNCMETACONF > $CONF3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+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 "$MONITOR" -H $URI3 \
+ '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
+
+cat /dev/null > $SEARCHOUT
+
+BASEDN="o=Example,c=US"
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+# ITS#4195: spurious matchedDN when the search scopes the main target,
+# and the searchBase is not present, so that target returns noSuchObject
+BASEDN="ou=Meta,o=Example,c=US"
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+#
+# Do some modifications
+#
+
+BASEDN="o=Example,c=US"
+echo "Modifying database \"$BASEDN\"..."
+$LDAPMODIFY -v -D "cn=Manager,$BASEDN" -H $URI3 -w $PASSWD \
+ -M >> $TESTOUT 2>&1 << EOMODS
+# These operations (updates with objectClass mapping) triggered ITS#3499
+dn: cn=Added Group,ou=Groups,$BASEDN
+changetype: add
+objectClass: groupOfNames
+objectClass: uidObject
+cn: Added Group
+member: cn=Added Group,ou=Groups,$BASEDN
+uid: added
+
+dn: cn=Another Added Group,ou=Groups,$BASEDN
+changetype: add
+objectClass: groupOfNames
+cn: Another Added Group
+member: cn=Added Group,ou=Groups,$BASEDN
+member: cn=Another Added Group,ou=Groups,$BASEDN
+
+dn: cn=Another Added Group,ou=Groups,$BASEDN
+changetype: modify
+add: objectClass
+objectClass: uidObject
+-
+add: uid
+uid: added
+-
+
+dn: cn=Added Group,ou=Groups,$BASEDN
+changetype: modify
+delete: objectClass
+objectClass: uidObject
+-
+delete: uid
+-
+
+dn: ou=Meta,$BASEDN
+changetype: modify
+add: description
+description: added to "ou=Meta,$BASEDN"
+-
+
+dn: ou=Who's going to handle this?,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Who's going to handle this?
+description: added
+description: will be deleted
+
+dn: ou=Same as above,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Same as above
+description: added right after "Who's going to handle this?"
+description: will be preserved
+
+dn: ou=Who's going to handle this?,$BASEDN
+changetype: delete
+
+dn: ou=Who's going to handle this?,ou=Meta,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Who's going to handle this?
+description: added
+description: will be deleted
+
+dn: ou=Same as above,ou=Meta,$BASEDN
+changetype: add
+objectClass: organizationalUnit
+ou: Same as above
+description: added right after "Who's going to handle this?"
+description: will be preserved
+
+dn: cn=Added User,ou=Same as above,ou=Meta,$BASEDN
+changetype: add
+objectClass: inetOrgPerson
+cn: Added User
+sn: User
+userPassword: secret
+
+dn: ou=Who's going to handle this?,ou=Meta,$BASEDN
+changetype: delete
+EOMODS
+
+RC=$?
+#if test $RC != 0 ; then
+# echo "Modify failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Modify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Searching base=\"$BASEDN\"..."
+echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+BASEDN="o=Example,c=US"
+echo " base=\"$BASEDN\"..."
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" -M "$FILTER" '*' ref \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+BASEDN="o=Example,c=US"
+FILTER="(seeAlso=cn=all staff,ou=Groups,$BASEDN)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"seeAlso\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"seeAlso\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" "$FILTER" seeAlso \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+FILTER="(uid=example)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"uid\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"uid\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" "$FILTER" uid \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+FILTER="(member=cn=Another Added Group,ou=Groups,$BASEDN)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"member\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"member\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -b "$BASEDN" "$FILTER" member \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Waiting 10 seconds for cached connections to timeout..."
+sleep 10
+
+echo "Searching with a timed out connection..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"member\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"" >> $SEARCHOUT
+echo "# with a timed out connection..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 -D "cn=Manager,$BASEDN" -w $PASSWD \
+ -b "$BASEDN" "$FILTER" member \
+ >> $SEARCHOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "Search failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+# NOTE: cannot send to $SEARCHOUT because the returned entries
+# are not predictable...
+echo "Checking server-enforced size limit..."
+echo "# Checking server-enforced size limit..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 \
+ -D "cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN" -w bjorn \
+ -b "$BASEDN" "(objectClass=*)" 1.1 \
+ >> $TESTOUT 2>&1
+RC=$?
+case $RC,$BACKEND in
+ 4,* | 0,null)
+ ;;
+ 0,*)
+ echo "Search should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+# NOTE: cannot send to $SEARCHOUT because the returned entries
+# are not predictable...
+echo "Checking client-requested size limit..."
+echo "# Checking client-requested size limit..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -H $URI3 \
+ -D "cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN" -w bjorn \
+ -b "$BASEDN" -z 2 "(objectClass=*)" 1.1 \
+ >> $TESTOUT 2>&1
+RC=$?
+case $RC,$BACKEND in
+ 4,* | 0,null)
+ ;;
+ 0,*)
+ echo "Search should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ *)
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $METAOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - meta search/modification didn't succeed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Binding as newly added user to database \"$BASEDN\"..."
+$LDAPWHOAMI -H $URI3 \
+ -D "cn=Added User,ou=Same as above,ou=Meta,$BASEDN" \
+ -w $PASSWD >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "WhoAmI failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC in
+ 0)
+ ;;
+ 51)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ echo "WhoAmI failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ ;;
+esac
+
+
+echo "Binding with incorrect password to database \"$BASEDN\"..."
+$LDAPWHOAMI -H $URI3 \
+ -D "cn=Added User,ou=Same as above,ou=Meta,$BASEDN" \
+ -w bogus >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "WhoAmI failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC,$BACKEND in
+ 0,null)
+ ;;
+ 0,*)
+ echo "WhoAmI should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ 51,*)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ ;;
+esac
+
+echo "Binding with non-existing user to database \"$BASEDN\"..."
+$LDAPWHOAMI -H $URI3 \
+ -D "cn=Non-existing User,ou=Same as above,ou=Meta,$BASEDN" \
+ -w bogus >> $TESTOUT 2>&1
+RC=$?
+#if test $RC != 0 ; then
+# echo "WhoAmI failed ($RC)!"
+# test $KILLSERVERS != no && kill -HUP $KILLPIDS
+# exit $RC
+#fi
+case $RC,$BACKEND in
+ 0,null)
+ ;;
+ 0,*)
+ echo "WhoAmI should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ ;;
+ 51,*)
+ echo "### Hit LDAP_BUSY problem; you may want to re-run the test"
+ ;;
+ *)
+ ;;
+esac
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test074-asyncmeta-concurrency b/tests/scripts/test074-asyncmeta-concurrency
new file mode 100755
index 0000000..09a14fd
--- /dev/null
+++ b/tests/scripts/test074-asyncmeta-concurrency
@@ -0,0 +1,226 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+echo ""
+
+if test $BACKASYNCMETA = asyncmetano ; then
+ echo "asyncmeta backend not available, test skipped"
+ exit 0
+fi
+
+if test $BACKLDAP = ldapno ; then
+ echo "ldap backend not available, test skipped"
+ exit 0
+fi
+
+if test x$TESTLOOPS = x ; then
+ TESTLOOPS=50
+fi
+
+if test x$TESTCHILDREN = x ; then
+ TESTCHILDREN=20
+fi
+
+rm -rf $TESTDIR
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $METACONF1 > $CONF1
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ '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 "Using ldapadd to populate the database..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
+ $LDIFORDERED > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $METACONF2 > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+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 "$MONITOR" -H $URI2 \
+ '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 "Using ldapadd to populate the database..."
+$LDAPADD -D "$METAMANAGERDN" -H $URI2 -w $PASSWD < \
+ $LDIFMETA >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT3..."
+. $CONFFILTER $BACKEND < $ASYNCMETACONF > $CONF3
+$SLAPD -f $CONF3 -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+
+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 "$MONITOR" -H $URI3 \
+ '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
+
+cat /dev/null > $SEARCHOUT
+
+mkdir -p $TESTDIR/$DATADIR
+METABASEDN="o=Example,c=US"
+for f in $DATADIR/do_* ; do
+ sed -e "s;$BASEDN;$METABASEDN;" $f > $TESTDIR/$f
+done
+
+# add a read that matches only the local database, but selects
+# also the remote as candidate; this should be removed to compare
+# execution times with test008...
+for f in $TESTDIR/$DATADIR/do_read.* ; do
+ echo "ou=Meta,$METABASEDN" >> $f
+done
+
+# add a read that matches a referral in the local database only,
+# but selects also the remote as candidate; this should be removed
+# to compare execution times with test008...
+for f in $TESTDIR/$DATADIR/do_read.* ; do
+ echo "cn=Somewhere,ou=Meta,$METABASEDN" >> $f
+done
+
+# add a bind that resolves to a referral
+for f in $TESTDIR/$DATADIR/do_bind.* ; do
+ echo "cn=Foo,ou=Meta,$METABASEDN" >> $f
+ echo "bar" >> $f
+ echo "" >> $f
+ echo "" >> $f
+done
+
+# fix test data to include back-monitor, if available
+# NOTE: copies do_* files from $TESTDIR/$DATADIR to $TESTDIR
+$MONITORDATA "$TESTDIR/$DATADIR" "$TESTDIR"
+
+BINDDN="cn=Manager,o=Local"
+PASSWD="secret"
+echo "Using tester for concurrent server access..."
+$SLAPDTESTER -P "$PROGDIR" -d "$TESTDIR" -H $URI3 \
+ -D "$BINDDN" -w $PASSWD -l $TESTLOOPS -j $TESTCHILDREN \
+ -r 20 -i '!REFERRAL' -i '*INVALID_CREDENTIALS' -SS
+RC=$?
+
+if test $RC != 0 ; then
+ echo "slapd-tester failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to retrieve all the entries..."
+$LDAPSEARCH -S "" -b "$METABASEDN" -H $URI3 \
+ 'objectClass=*' > $SEARCHOUT 2>&1
+RC=$?
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ exit $RC
+fi
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering original ldif used to create database..."
+$LDIFFILTER < $METACONCURRENCYOUT > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - slapd-asyncmeta search/modification didn't succeed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test075-dsee-persist b/tests/scripts/test075-dsee-persist
new file mode 100755
index 0000000..fff63ee
--- /dev/null
+++ b/tests/scripts/test075-dsee-persist
@@ -0,0 +1,421 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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
+
+OPATTRS="creatorsName createTimestamp modifiersName modifyTimestamp"
+
+DSADM=`command -v dsadm`
+if test -z "$DSADM"; then
+ echo "DSEE dsadm not in path, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR4
+
+#
+# Test replication:
+# - start provider
+# - start consumer
+# - populate over ldap
+# - perform some modifies and deleted
+# - attempt to modify the consumer (referral or chain)
+# - retrieve database over ldap and compare against expected results
+#
+
+DSEEPW=secret21
+DSEEDN="cn=Directory Manager"
+DSEEPWF=$TESTDIR/dseepw
+
+echo "secret21" > $DSEEPWF
+
+echo "Setting up DSEE provider slapd on TCP/IP port $PORT1..."
+dsadm create -p $PORT1 -w $DSEEPWF $DBDIR1
+dsadm start $DBDIR1
+dsconf create-suffix -c -p $PORT1 -w $DSEEPWF $BASEDN
+dsconf set-server-prop -p $PORT1 -w $DSEEPWF moddn-enabled:on
+dsconf set-server-prop -p $PORT1 -w $DSEEPWF retro-cl-enabled:on
+dsadm restart $DBDIR1
+PID=`basename $DBDIR1/locks/server/*`
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$BASEDN" -H $URI1 \
+ '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 "Starting consumer slapd on TCP/IP port $PORT4..."
+. $CONFFILTER $BACKEND < $DSEESYNC2CONF > $CONF4
+$SLAPD -f $CONF4 -h $URI4 -d $LVL > $LOG4 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI4 \
+ '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
+
+# using LDIFDIRSYNCNOCP to avoid custom OpenLDAP schema
+echo "Using ldapadd to populate the provider directory..."
+$LDAPADD -D "$DSEEDN" -H $URI1 -w $DSEEPW < \
+ $LDIFDIRSYNCNOCP > /dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -D "$DSEEDN" -w "$DSEEPW" \
+ '(objectclass=*)' '*' $OPATTRS > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI4 \
+ '(objectclass=*)' '*' $OPATTRS > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering provider results..."
+$LDIFFILTER -s a < $PROVIDEROUT > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER -s a < $CONSUMEROUT > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Stopping the provider, sleeping 10 seconds and restarting it..."
+kill -HUP "$PID"
+wait $PID
+sleep 10
+echo "RESTART" >> $LOG1
+dsadm start $DBDIR1
+PID=`basename $DBDIR1/locks/server/*`
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$BASEDN" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+echo "Waiting $SLEEP1 seconds for consumer to reconnect..."
+sleep $SLEEP1
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapmodify to modify provider directory..."
+
+#
+# Do some modifications
+#
+
+$LDAPMODIFY -v -D "$DSEEDN" -H $URI1 -w $DSEEPW > \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=James A Jones 1, ou=Alumni Association, ou=People, dc=example,dc=com
+changetype: modify
+add: carLicense
+carLicense: Orange Juice
+-
+delete: sn
+sn: Jones
+-
+add: sn
+sn: Jones
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: carLicense
+carLicense: Iced Tea
+
+dn: cn=ITD Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: uniquemember
+uniquemember: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+uniquemember: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+-
+add: uniquemember
+uniquemember: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com
+uniquemember: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com
+
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+changetype: modify
+delete: description
+
+dn: cn=Gern Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com
+changetype: add
+objectclass: inetOrgPerson
+cn: Gern Jensen
+sn: Jensen
+uid: gjensen
+title: Chief Investigator, ITD
+postaladdress: ITD $ 535 W. William St $ Ann Arbor, MI 48103
+seealso: cn=All Staff,ou=Groups,dc=example,dc=com
+carLicense: Coffee
+homepostaladdress: 844 Brown St. Apt. 4 $ Ann Arbor, MI 48104
+description: Very odd
+facsimiletelephonenumber: +1 313 555 7557
+facsimiletelephonenumber: +1 313 555 9998
+facsimiletelephonenumber: +1 313 555 9999
+telephonenumber: +1 313 555 8343
+mail: gjensen@mailgw.example.com
+homephone: +1 313 555 8844
+
+# modify attribute with no matching rule (ITS#6458)
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: facsimiletelephonenumber
+facsimiletelephonenumber: +1 313 555 9998
+facsimiletelephonenumber: +1 313 555 9999
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: facsimiletelephonenumber
+facsimiletelephonenumber: +1 313 555 9998
+facsimiletelephonenumber: +1 313 555 9999
+facsimiletelephonenumber: +1 313 555 7557
+
+dn: cn=Gern Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+replace: facsimiletelephonenumber
+facsimiletelephonenumber: +1 313 555 9998
+facsimiletelephonenumber: +1 313 555 9999
+
+dn: ou=Retired,ou=People,dc=example,dc=com
+changetype: add
+objectclass: organizationalUnit
+ou: Retired
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: add
+objectclass: inetOrgPerson
+cn: Rosco P. Coltrane
+sn: Coltrane
+uid: rosco
+description: Fat tycoon
+
+dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Rosco P. Coltrane
+deleteoldrdn: 1
+newsuperior: ou=Retired,ou=People,dc=example,dc=com
+
+dn: cn=James A Jones 2, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: delete
+
+dn: ou=testdomain1,dc=example,dc=com
+changetype: modrdn
+newrdn: ou=itsdomain1
+deleteoldrdn: 1
+
+dn: ou=itsdomain1,dc=example,dc=com
+changetype: modify
+replace: description
+description: Example, Inc. ITS test domain
+
+dn: ou=testdomain2,dc=example,dc=com
+changetype: modrdn
+newrdn: ou=itsdomain2
+deleteoldrdn: 1
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+## ldappasswd test removed, not supported on DSEE
+
+echo "Stopping consumer to test recovery..."
+kill -HUP $CONSUMERPID
+wait $CONSUMERPID
+
+echo "Modifying more entries on the provider..."
+$LDAPMODIFY -v -D "$DSEEDN" -H $URI1 -w $DSEEPW >> \
+ $TESTOUT 2>&1 << EOMODS
+dn: cn=Rosco P. Coltrane, ou=Retired, ou=People, dc=example,dc=com
+changetype: delete
+
+dn: cn=Bjorn Jensen, ou=Information Technology Division, ou=People, dc=example,dc=com
+changetype: modify
+add: carLicense
+carLicense: Mad Dog 20/20
+
+dn: cn=Rosco P. Coltrane,ou=Retired,ou=People,dc=example,dc=com
+changetype: add
+objectclass: inetOrgPerson
+sn: Coltrane
+uid: rosco
+cn: Rosco P. Coltrane
+
+dn: ou=itsdomain2,dc=example,dc=com
+changetype: modify
+replace: description
+description: Example, Inc. itsdomain2 test domain
+
+# rename with a newly added newSuperior while the consumer is down (ITS#6472)
+dn: ou=New Branch,dc=example,dc=com
+changetype: add
+objectClass: organizationalUnit
+ou: New Branch
+
+dn: cn=Dorothy Stevens, ou=Alumni Association, ou=People, dc=example,dc=com
+changetype: modrdn
+newrdn: cn=Dorothy Stevens
+deleteoldrdn: 0
+newsuperior: ou=New Branch,dc=example,dc=com
+
+EOMODS
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Restarting consumer..."
+echo "RESTART" >> $LOG4
+$SLAPD -f $CONF4 -h $URI4 -d $LVL >> $LOG4 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$PID $CONSUMERPID"
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
+ -D "$DSEEDN" -w "$DSEEPW" \
+ '(objectclass=*)' '*' $OPATTRS > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -H $URI4 \
+ '(objectclass=*)' '*' $OPATTRS > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Filtering provider results..."
+$LDIFFILTER -s a < $PROVIDEROUT > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER -s a < $CONSUMEROUT > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test076-authid-rewrite b/tests/scripts/test076-authid-rewrite
new file mode 100755
index 0000000..383e4c3
--- /dev/null
+++ b/tests/scripts/test076-authid-rewrite
@@ -0,0 +1,646 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $WITH_SASL = no; then
+ echo "SASL authentication not available, test skipped"
+ exit 0
+fi
+
+CONFDIR=$TESTDIR/slapd.d
+MECH=DIGEST-MD5
+
+mkdir -p $TESTDIR $CONFDIR $DBDIR1
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+echo "Starting slapd on TCP/IP port $PORT1... $PWD"
+. $CONFFILTER $BACKEND < $DYNAMICCONF > $CONFLDIF
+$SLAPADD -F $CONFDIR -n 0 -l $CONFLDIF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+cd $TESTDIR
+$SLAPD -F ./slapd.d -h $URI1 -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 $URI1 \
+ '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 "Checking whether $MECH is supported..."
+$LDAPSEARCH -s base -b "" -H $URI1 \
+ 'objectClass=*' supportedSASLMechanisms > $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+grep "supportedSASLMechanisms: $MECH" $SEARCHOUT > $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "SASL mechanism $MECH is not available, test skipped"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 0
+fi
+
+echo "Adding schema and database..."
+$LDAPADD -H $URI1 -D cn=config -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
+
+if [ "$BACKENDTYPE" = mod ]; then
+ $LDAPADD -H $URI1 -D cn=config -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 -H $URI1 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+olcSuffix: $BASEDN
+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 -H $URI1 -D cn=config -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 "ldapmodify failed for index config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+
+echo "Using ldapadd to populate the database..."
+$LDAPADD -H $URI1 -D "$MANAGERDN" -w $PASSWD < $LDIFORDERED >>$TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo
+
+echo "Adding olcAuthzRegexp rule for static mapping..."
+$LDAPMODIFY -H $URI1 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+add: olcAuthzRegexp
+olcAuthzRegexp: uid=manager,cn=[^,]+,cn=auth $MANAGERDN
+EOF
+RC=$?
+if test $RC != 0; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=Manager
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $PASSWD
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo
+
+echo "Adding olcAuthzRegexp rule to search by uid..."
+$LDAPMODIFY -H $URI1 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+add: olcAuthzRegexp
+olcAuthzRegexp: uid=([^,]+),cn=[^,]+,cn=auth ldap:///$BASEDN??sub?(uid=\$1)
+EOF
+RC=$?
+if test $RC != 0; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=Manager
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $PASSWD
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=bjensen
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $ID
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo
+
+echo "Inserting olcAuthzRegexp rule before the last..."
+$LDAPMODIFY -H $URI1 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+add: olcAuthzRegexp
+olcAuthzRegexp: {1}uid=babs,cn=[^,]+,cn=auth ldap:///$BASEDN??sub?(uid=bjensen)
+EOF
+RC=$?
+if test $RC != 0; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=Manager
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $PASSWD
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=babs
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w bjensen
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=bjensen
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $ID
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo
+
+echo "Deleting the first olcAuthzRegexp rule..."
+$LDAPMODIFY -H $URI1 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+delete: olcAuthzRegexp
+olcAuthzRegexp: {0}
+EOF
+RC=$?
+if test $RC != 0; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=Manager
+echo "Testing ldapwhoami as $ID (should fail)..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $PASSWD
+RC=$?
+if test $RC != 49; then
+ echo "ldapwhoami unexpected result ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=babs
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w bjensen
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=bjensen
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $ID
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo
+
+echo "Updating an olcAuthzRegexp rule in place..."
+$LDAPMODIFY -H $URI1 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+delete: olcAuthzRegexp
+olcAuthzRegexp: {0}
+-
+add: olcAuthzRegexp
+olcAuthzRegexp: {0}uid=biff,cn=[^,]+,cn=auth ldap:///$BASEDN??sub?(uid=bjorn)
+EOF
+RC=$?
+if test $RC != 0; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=babs
+echo "Testing ldapwhoami as $ID (should fail)..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w bjensen
+RC=$?
+if test $RC != 49; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=biff
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w bjorn
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=bjensen
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $ID
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo
+
+echo "Deleting all olcAuthzRegexp rules..."
+$LDAPMODIFY -H $URI1 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+delete: olcAuthzRegexp
+EOF
+RC=$?
+if test $RC != 0; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=bjensen
+echo "Testing ldapwhoami as $ID (should fail)..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $ID
+RC=$?
+if test $RC != 49; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo
+
+echo "Initializing olcAuthIDRewrite engine..."
+$LDAPMODIFY -H $URI1 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+add: olcAuthIDRewrite
+olcAuthIDRewrite: rewriteEngine ON
+olcAuthIDRewrite: rewriteContext authid
+EOF
+RC=$?
+if test $RC != 0; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo
+
+echo "Adding olcAuthIDRewrite rule for static mapping..."
+$LDAPMODIFY -H $URI1 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+add: olcAuthIDRewrite
+olcAuthIDRewrite: rewriteRule uid=manager,cn=[^,]+,cn=auth $MANAGERDN :
+EOF
+RC=$?
+if test $RC != 0; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=Manager
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $PASSWD
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo
+
+echo "Adding olcAuthIDRewrite rule to search by uid..."
+$LDAPMODIFY -H $URI1 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+add: olcAuthIDRewrite
+olcAuthIDRewrite: rewriteRule uid=([^,]+),cn=[^,]+,cn=auth ldap:///$BASEDN??sub?(uid=\$1) :
+EOF
+RC=$?
+if test $RC != 0; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=Manager
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $PASSWD
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=bjensen
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $ID
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo
+
+echo "Inserting olcAuthIDRewrite rule before the last..."
+$LDAPMODIFY -H $URI1 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+add: olcAuthIDRewrite
+olcAuthIDRewrite: {3}rewriteRule uid=babs,cn=[^,]+,cn=auth ldap:///$BASEDN??sub?(uid=bjensen) :
+EOF
+RC=$?
+if test $RC != 0; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=Manager
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $PASSWD
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=babs
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w bjensen
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=bjensen
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $ID
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo
+
+echo "Deleting the first olcAuthIDRewrite rule..."
+$LDAPMODIFY -H $URI1 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+delete: olcAuthIDRewrite
+olcAuthIDRewrite: {2}
+EOF
+RC=$?
+if test $RC != 0; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=Manager
+echo "Testing ldapwhoami as $ID (should fail)..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $PASSWD
+RC=$?
+if test $RC != 49; then
+ echo "ldapwhoami unexpected result ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=babs
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w bjensen
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=bjensen
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $ID
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo
+
+echo "Updating an olcAuthIDRewrite rule in place..."
+$LDAPMODIFY -H $URI1 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+delete: olcAuthIDRewrite
+olcAuthIDRewrite: {2}
+-
+add: olcAuthIDRewrite
+olcAuthIDRewrite: {2}rewriteRule uid=biff,cn=[^,]+,cn=auth ldap:///$BASEDN??sub?(uid=bjorn) :
+EOF
+RC=$?
+if test $RC != 0; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=babs
+echo "Testing ldapwhoami as $ID (should fail)..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w bjensen
+RC=$?
+if test $RC != 49; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=biff
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w bjorn
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=bjensen
+echo "Testing ldapwhoami as $ID..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $ID
+RC=$?
+if test $RC != 0; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo
+
+echo "Deleting all olcAuthIDRewrite rules..."
+$LDAPMODIFY -H $URI1 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+delete: olcAuthIDRewrite
+EOF
+RC=$?
+if test $RC != 0; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ID=bjensen
+echo "Testing ldapwhoami as $ID (should fail)..."
+$LDAPSASLWHOAMI -H $URI1 -Y $MECH -U $ID -w $ID
+RC=$?
+if test $RC != 49; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test077-sasl-gssapi b/tests/scripts/test077-sasl-gssapi
new file mode 100755
index 0000000..4d4e260
--- /dev/null
+++ b/tests/scripts/test077-sasl-gssapi
@@ -0,0 +1,255 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $WITH_SASL = no ; then
+ echo "SASL support not available, test skipped"
+ exit 0
+fi
+
+CONFDIR=$TESTDIR/slapd.d
+CONFLDIF=$TESTDIR/slapd.ldif
+
+mkdir -p $TESTDIR $DBDIR1 $CONFDIR
+cp -r $DATADIR/tls $TESTDIR
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+echo "Starting KDC for SASL/GSSAPI tests..."
+. $SRCDIR/scripts/setup_kdc.sh
+
+echo "Configuring slapd..."
+cat > $CONFLDIF <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+olcSaslHost: localhost
+olcSaslRealm: $KRB5REALM
+olcTLSCACertificateFile: $TESTDIR/tls/ca/certs/testsuiteCA.crt
+olcTLSCertificateFile: $TESTDIR/tls/certs/localhost.crt
+olcTLSCertificateKeyFile: $TESTDIR/tls/private/localhost.key
+
+dn: cn=schema,cn=config
+objectClass: olcSchemaConfig
+cn: schema
+
+include: file://$ABS_SCHEMADIR/core.ldif
+
+dn: olcDatabase={0}config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW:< file://$TESTDIR/configpw
+
+EOF
+$SLAPADD -F $CONFDIR -n 0 -l $CONFLDIF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ kill $KDCPROC
+ exit $RC
+fi
+
+echo "Starting ldap:/// slapd on TCP/IP port $PORT1 and ldaps:/// slapd on $PORT2..."
+$SLAPD -F $CONFDIR -h "$URI1 $SURI2" -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 $URI1 \
+ '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)!"
+ kill $KDCPROC
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -x -H $URI1 -s "base" -b "" supportedSASLMechanisms > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ kill $KDCPROC
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+grep GSSAPI $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "failed: GSSAPI mechanism not in supportedSASLMechanisms."
+ kill $KDCPROC
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo -n "Using ldapwhoami with SASL/GSSAPI: "
+$LDAPSASLWHOAMI -N -Y GSSAPI -H $URI1 > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ kill $KDCPROC
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+else
+ echo "success"
+fi
+
+echo -n "Validating mapped SASL/GSSAPI ID: "
+echo "dn:uid=$KUSER,cn=$KRB5REALM,cn=gssapi,cn=auth" > $TESTDIR/dn.out
+$CMP $TESTDIR/dn.out $TESTOUT > $CMPOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "Comparison failed"
+ kill $KDCPROC
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+else
+ echo "success"
+fi
+
+if test $WITH_TLS = no ; then
+ echo "SASL/GSSAPI: TLS support not available, skipping TLS part."
+else
+ echo -n "Using ldapwhoami with SASL/GSSAPI with start-tls: "
+ $LDAPSASLWHOAMI -N -Y GSSAPI -H $URI1 -ZZ -o tls_reqcert=allow \
+ -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt \
+ > $TESTOUT 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ kill $KDCPROC
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ else
+ echo "success"
+ fi
+
+ echo -n "Using ldapwhoami with SASL/GSSAPI with ldaps: "
+ $LDAPSASLWHOAMI -N -Y GSSAPI -H $SURI2 -o tls_reqcert=allow \
+ -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt \
+ > $TESTOUT 2>&1
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ kill $KDCPROC
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ else
+ echo "success"
+ fi
+fi
+
+if test $WITH_TLS = no ; then
+ echo "TLS support not available, skipping channel-binding test"
+elif test $HAVE_SASL_GSS_CBIND = no ; then
+ echo "SASL has no channel-binding support in GSSAPI, test skipped"
+else
+ echo "Testing SASL/GSSAPI with SASL_CBINDING..."
+
+ for acb in "none" "tls-unique" "tls-endpoint" ; do
+
+ echo "Modifying slapd's olcSaslCBinding to ${acb} ..."
+ $LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+replace: olcSaslCBinding
+olcSaslCBinding: ${acb}
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ kill $KDCPROC
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ for icb in "none" "tls-unique" "tls-endpoint" ; do
+
+ # The gnutls implementation of "tls-unique" seems broken
+ if test $icb = "tls-unique" -o $acb = "tls-unique" ; then
+ if test $WITH_TLS_TYPE = gnutls ; then
+ continue
+ fi
+ fi
+
+ fail="no"
+ if test $icb != $acb -a $acb != "none" ; then
+ # This currently fails in MIT, but it is planned to be
+ # fixed not to fail like in heimdal - avoid testing.
+ if test $icb = "none" ; then
+ continue
+ fi
+ # Otherwise unmatching bindings are expected to fail.
+ fail="yes"
+ fi
+
+ echo -n "Using ldapwhoami with SASL/GSSAPI and SASL_CBINDING "
+ echo -n "(client: ${icb}, server: ${acb}): "
+
+ $LDAPSASLWHOAMI -N -Y GSSAPI -H $URI1 -ZZ -o tls_reqcert=allow \
+ -o tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt \
+ -o SASL_CBINDING=$icb > $TESTOUT 2>&1
+
+ RC=$?
+ if test $RC != 0 ; then
+ if test $fail = "no" ; then
+ echo "test failed ($RC)!"
+ kill $KDCPROC
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+ elif test $fail = "yes" ; then
+ echo "failed: command succeeded unexpectedly."
+ kill $KDCPROC
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+ fi
+
+ echo "success"
+ RC=0
+ done
+ done
+fi
+
+
+kill $KDCPROC
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $RC != 0 ; then
+ echo ">>>>> Test failed"
+else
+ echo ">>>>> Test succeeded"
+ RC=0
+fi
+
+test $KILLSERVERS != no && wait
+
+exit $RC
diff --git a/tests/scripts/test078-persistent-sessionlog b/tests/scripts/test078-persistent-sessionlog
new file mode 100755
index 0000000..8f3d07f
--- /dev/null
+++ b/tests/scripts/test078-persistent-sessionlog
@@ -0,0 +1,652 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+if test $ACCESSLOG = accesslogno; then
+ echo "Accesslog overlay not available, test skipped"
+ exit 0
+fi
+
+MMR=2
+
+XDIR=$TESTDIR/srv
+TMP=$TESTDIR/tmp
+
+mkdir -p $TESTDIR
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+if test x"$SYNCMODE" = x ; then
+ SYNCMODE=rp
+fi
+case "$SYNCMODE" in
+ ro)
+ SYNCTYPE="type=refreshOnly interval=00:00:00:03"
+ ;;
+ rp)
+ SYNCTYPE="type=refreshAndPersist interval=00:00:00:03"
+ ;;
+ *)
+ echo "unknown sync mode $SYNCMODE"
+ exit 1;
+ ;;
+esac
+
+#
+# Test delta-sync mmr
+# - start servers
+# - configure over ldap
+# - populate over ldap
+# - configure syncrepl over ldap
+# - break replication
+# - modify each server separately
+# - restore replication
+# - compare results
+#
+
+nullExclude=""
+test $BACKEND = null && nullExclude="# "
+
+KILLPIDS=
+
+echo "Initializing server configurations..."
+n=1
+while [ $n -le $MMR ]; do
+
+DBDIR=${XDIR}$n/db
+CFDIR=${XDIR}$n/slapd.d
+
+mkdir -p ${XDIR}$n $DBDIR.1 $DBDIR.2 $CFDIR
+
+o=`expr 3 - $n`
+cat > $TMP <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+olcServerID: $n
+
+EOF
+
+if [ "$SYNCPROV" = syncprovmod -o "$ACCESSLOG" = accesslogmod ]; then
+ cat <<EOF >> $TMP
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+EOF
+ if [ "$SYNCPROV" = syncprovmod ]; then
+ echo "olcModuleLoad: syncprov.la" >> $TMP
+ fi
+ if [ "$ACCESSLOG" = accesslogmod ]; then
+ echo "olcModuleLoad: accesslog.la" >> $TMP
+ fi
+ echo "" >> $TMP
+fi
+
+if [ "$BACKENDTYPE" = mod ]; then
+cat <<EOF >> $TMP
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/back-$BACKEND
+olcModuleLoad: back_$BACKEND.la
+
+EOF
+fi
+MYURI=`eval echo '$URI'$n`
+PROVIDERURI=`eval echo '$URI'$o`
+if test $INDEXDB = indexdb ; then
+INDEX1="olcDbIndex: objectClass,entryCSN,reqStart,reqDN,reqResult eq"
+INDEX2="olcDbIndex: objectClass,entryCSN,entryUUID eq"
+else
+INDEX1=
+INDEX2=
+fi
+cat >> $TMP <<EOF
+dn: cn=schema,cn=config
+objectclass: olcSchemaconfig
+cn: schema
+
+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
+
+dn: olcDatabase={0}config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW:< file://$CONFIGPWF
+
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+olcSuffix: cn=log
+${nullExclude}olcDbDirectory: ${DBDIR}.1
+olcRootDN: $MANAGERDN
+$INDEX1
+
+dn: olcOverlay=syncprov,olcDatabase={1}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+olcSpNoPresent: TRUE
+olcSpReloadHint: TRUE
+
+dn: olcDatabase={2}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {2}$BACKEND
+olcSuffix: $BASEDN
+${nullExclude}olcDbDirectory: ${DBDIR}.2
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+olcSyncRepl: rid=001 provider=$PROVIDERURI binddn="$MANAGERDN" bindmethod=simple
+ credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE retry="3 +" timeout=3
+olcMirrorMode: TRUE
+$INDEX2
+
+dn: olcOverlay=syncprov,olcDatabase={2}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+olcSpSessionlogSource: cn=log
+
+dn: olcOverlay=accesslog,olcDatabase={2}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcAccessLogConfig
+olcOverlay: accesslog
+olcAccessLogDB: cn=log
+olcAccessLogOps: writes
+olcAccessLogSuccess: TRUE
+
+EOF
+$SLAPADD -F $CFDIR -n 0 -d-1< $TMP > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+PORT=`eval echo '$PORT'$n`
+echo "Starting server $n on TCP/IP port $PORT..."
+cd ${XDIR}${n}
+LOG=`eval echo '$LOG'$n`
+$SLAPD -F slapd.d -h $MYURI -d $LVL > $LOG 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID $KILLPIDS"
+cd $TESTWD
+
+echo "Using ldapsearch to check that server $n is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $MYURI \
+ '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
+
+if [ $n = 1 ]; then
+echo "Using ldapadd for context on server 1..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $LDIFORDEREDCP \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server $n database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+fi
+
+n=`expr $n + 1`
+done
+
+echo "Using ldapadd to populate server 1..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $LDIFORDEREDNOCP \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+n=1
+while [ $n -le $MMR ]; do
+URI=`eval echo '$URI'$n`
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MMR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+echo "Using ldapadd to populate server 2..."
+$LDAPADD -D "$MANAGERDN" -H $URI2 -w $PASSWD -f $LDIFADD1 \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+THEDN="cn=James A Jones 2,ou=Alumni Association,ou=People,dc=example,dc=com"
+sleep 1
+for i in 1 2 3; do
+ $LDAPSEARCH -S "" -b "$THEDN" -H $URI1 \
+ -s base '(objectClass=*)' entryCSN > "${PROVIDEROUT}.$i" 2>&1
+ RC=$?
+
+ if test $RC = 0 ; then
+ break
+ fi
+
+ if test $RC != 32 ; then
+ echo "ldapsearch failed at slave ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+done
+
+n=1
+while [ $n -le $MMR ]; do
+URI=`eval echo '$URI'$n`
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MMR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+echo "Retrieving syncrepl cookie..."
+cookie=`$LDAPRSEARCH -b "$BASEDN" -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ -E "sync=ro" 'objectclass=*' 1.1 | grep cookie | sed "s/.*cookie: //"`
+
+if test -z "$cookie"; then
+ echo "Failed to retrieve cookie from server!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Deleting an entry from server 1..."
+$LDAPDELETE -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ "cn=Mark Elliot,ou=Alumni Association,ou=People,$BASEDN" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapdelete failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+
+echo "Restarting servers..."
+kill -HUP $KILLPIDS
+wait
+KILLPIDS=""
+n=1
+while [ $n -le $MMR ]; do
+o=`expr 3 - $n`
+MYURI=`eval echo '$URI'$n`
+PROVIDERURI=`eval echo '$URI'$o`
+
+echo "Starting server $n again..."
+cd ${XDIR}${n}
+LOG=`eval echo '$LOG'$n`
+echo "RESTART" >> $LOG
+#if test $n = 2; then
+#echo $SLAPD -F slapd.d -h $MYURI -d $LVL
+#else
+$SLAPD -F slapd.d -h $MYURI -d $LVL > $LOG 2>&1 &
+#fi
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID $KILLPIDS"
+cd $TESTWD
+
+echo "Using ldapsearch to check that server $n is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $MYURI \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for slapd to start..."
+ sleep 5
+done
+
+echo "Breaking replication between server $n and $o..."
+$LDAPMODIFY -D cn=config -H $MYURI -y $CONFIGPWF > $TESTOUT 2>&1 <<EOF
+dn: olcDatabase={2}$BACKEND,cn=config
+changetype: modify
+replace: olcSyncRepl
+olcSyncRepl: rid=001 provider=$PROVIDERURI binddn="$MANAGERDN" bindmethod=simple
+ credentials=InvalidPw searchbase="$BASEDN" $SYNCTYPE retry="3 +" timeout=3
+-
+replace: olcMirrorMode
+olcMirrorMode: TRUE
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server $n config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+n=`expr $n + 1`
+done
+
+echo "Using ldapmodify to force conflicts between server 1 and 2..."
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: description
+description: Amazing
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI2 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: description
+description: Stupendous
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+delete: description
+description: Outstanding
+-
+add: description
+description: Mindboggling
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI2 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+delete: description
+description: OutStanding
+-
+add: description
+description: Bizarre
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: carLicense
+carLicense: 123-XYZ
+-
+add: employeeNumber
+employeeNumber: 32
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI2 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+add: employeeType
+employeeType: deadwood
+-
+add: employeeNumber
+employeeNumber: 64
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 << EOF
+dn: $THEDN
+changetype: modify
+replace: sn
+sn: Replaced later
+-
+replace: sn
+sn: Surname
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Deleting an entry from both servers..."
+$LDAPDELETE -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ "cn=John Doe,ou=Information Technology Division,ou=People,$BASEDN" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapdelete failed for server 1 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPDELETE -D "$MANAGERDN" -H $URI2 -w $PASSWD \
+ "cn=John Doe,ou=Information Technology Division,ou=People,$BASEDN" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapdelete failed for server 2 database ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Restoring replication between server 1 and 2..."
+n=1
+while [ $n -le $MMR ]; do
+o=`expr 3 - $n`
+MYURI=`eval echo '$URI'$n`
+PROVIDERURI=`eval echo '$URI'$o`
+$LDAPMODIFY -D cn=config -H $MYURI -y $CONFIGPWF > $TESTOUT 2>&1 <<EOF
+dn: olcDatabase={2}$BACKEND,cn=config
+changetype: modify
+replace: olcSyncRepl
+olcSyncRepl: rid=001 provider=$PROVIDERURI binddn="$MANAGERDN" bindmethod=simple
+ credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE retry="3 +" timeout=3
+-
+replace: olcMirrorMode
+olcMirrorMode: TRUE
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for server $n config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+n=`expr $n + 1`
+done
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo 2 >$TESTDIR/repl.test
+echo 1 >>$TESTDIR/repl.test
+
+n=1
+while [ $n -le $MMR ]; do
+URI=`eval echo '$URI'$n`
+
+echo "Using ldapsearch to read all the entries from server $n..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ 'objectclass=*' > $TESTDIR/server$n.out 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at server $n ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+$LDIFFILTER -s a < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
+
+echo "Checking server $n can remember which entries have been deleted even after it's been restarted..."
+$LDAPRSEARCH -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ -E "sync=ro/$cookie" 'objectclass=*' 1.1 | awk '/syncUUIDs/ {count++} END {print count}' >$TESTDIR/repl.out
+$LDAPRSEARCH -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
+ -E "sync=ro/$cookie" 'objectclass=*' 1.1 | grep SyncDone | awk '/refreshDeletes=1/ {count++} END {print count}' >>$TESTDIR/repl.out
+
+$CMP $TESTDIR/repl.out $TESTDIR/repl.test > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server did not respond with delete phase"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+n=2
+while [ $n -le $MMR ]; do
+echo "Comparing retrieved entries from server 1 and server $n..."
+$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - server 1 and server $n databases differ"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+n=`expr $n + 1`
+done
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test079-proxy-timeout b/tests/scripts/test079-proxy-timeout
new file mode 100755
index 0000000..d64449b
--- /dev/null
+++ b/tests/scripts/test079-proxy-timeout
@@ -0,0 +1,374 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $BACKLDAP = "ldapno" ; then
+ echo "LDAP backend not available, test skipped"
+ exit 0
+fi
+if test $RWM = "rwmno" ; then
+ echo "rwm (rewrite/remap) overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+#
+# Start slapd that acts as a remote LDAP server that will be proxied
+#
+echo "Running slapadd to build database for the remote slapd server..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting remote slapd server on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+SERVERPID=$!
+if test $WAIT != 0 ; then
+ echo SERVERPID $SERVERPID
+ read foo
+fi
+
+echo "Using ldapsearch to check that slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+#
+# Start ldapd that will proxy for the remote server
+#
+# Proxy is configured with two slapd-ldap backends:
+# - one with idle timeout set: dc=idle-timeout,$BASED
+# - one with connection TTL set: dc=conn-ttl,$BASEDN
+#
+echo "Starting slapd proxy on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $DATADIR/slapd-proxytimeout.conf > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PROXYPID=$!
+if test $WAIT != 0 ; then
+ echo PROXYPID $PROXYPID
+ read foo
+fi
+
+KILLPIDS="$SERVERPID $PROXYPID"
+
+echo "Using ldapsearch to check that slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for slapd to start..."
+ sleep $SLEEP1
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+##############################################################################
+#
+# Test 1: Test that shared connections are timed out
+#
+
+CONN_BEGINS=`date +%s`
+CONN_EXPIRES=`expr $CONN_BEGINS + $TIMEOUT`
+echo "Create shared connection towards remote LDAP (time_t now=$CONN_BEGINS timeout=$CONN_EXPIRES)"
+
+$LDAPSEARCH -b "dc=idle-timeout,$BASEDN" \
+ -D "cn=Manager,dc=local,dc=com" \
+ -H $URI2 \
+ -w $PASSWD \
+ 'objectclass=*' > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed for base: dc=idle-timeout,$BASEDN ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -b "dc=conn-ttl,$BASEDN" \
+ -D "cn=Manager,dc=local,dc=com" \
+ -H $URI2 \
+ -w $PASSWD \
+ 'objectclass=*' >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed for base: dc=conn-ttl,$BASEDN ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Check that connections are established by searching for olmDbConnURI from Monitor
+
+echo "Checking that proxy has created connections towards backend (time_t now=`date +%s`)"
+
+$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL \
+ -D "cn=Manager,dc=local,dc=com" \
+ -H $URI2 -w $PASSWD olmDbConnURI 2>&1 | \
+ tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "Error: LDAP connection to remote LDAP server is not found ($RC)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -b "cn=Connections,cn=database 3,cn=databases,cn=monitor" -s one -LLL \
+ -D "cn=Manager,dc=local,dc=com" \
+ -H $URI2 -w $PASSWD olmDbConnURI 2>&1 | \
+ tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "Error: LDAP connection to remote LDAP server is not found ($RC)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Wait for connections to be closed, either due to
+# - idle-timeout and
+# - conn-ttl
+# sleep 2 second overtime for robustness of the test case
+echo "Sleeping until idle-timeout and conn-ttl have passed"
+NOW=`date +%s`
+sleep `expr $CONN_EXPIRES - $NOW + 2`
+
+echo "Checking that proxy has closed expired connections towards the remote LDAP server (time_t now=`date +%s`)"
+
+$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL \
+ -D "cn=Manager,dc=local,dc=com" \
+ -H $URI2 -w $PASSWD olmDbConnURI 2>&1 | \
+ tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 1 ; then
+ echo "Error: LDAP connection to remote LDAP server was not closed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -b "cn=Connections,cn=database 3,cn=databases,cn=monitor" -s one -LLL \
+ -D "cn=Manager,dc=local,dc=com" \
+ -H $URI2 -w $PASSWD olmDbConnURI 2>&1 | \
+ tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 1 ; then
+ echo "Error: LDAP connection to remote LDAP server was not closed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+
+##############################################################################
+#
+# Test 2: Test that private connections are timed out
+#
+
+CONN_BEGINS=`date +%s`
+CONN_EXPIRES=`expr $CONN_BEGINS + $TIMEOUT`
+echo "Create private connection towards remote LDAP (time_t now=$CONN_BEGINS timeout=$CONN_EXPIRES)"
+
+# Create fifos that are used to pass searches from the test case to ldapsearch
+rm -f $TESTDIR/ldapsearch1.fifo $TESTDIR/ldapsearch2.fifo
+mkfifo $TESTDIR/ldapsearch1.fifo $TESTDIR/ldapsearch2.fifo
+
+# Execute ldapsearch on background and have it read searches from the fifo
+$LDAPSEARCH -b "dc=idle-timeout,$BASEDN" \
+ -D "cn=Barbara Jensen,ou=Information Technology Division,dc=idle-timeout,$BASEDN" \
+ -H $URI2 \
+ -w "bjensen" \
+ -f $TESTDIR/ldapsearch1.fifo >> $TESTOUT 2>&1 &
+LDAPSEARCHPIDS=$!
+
+$LDAPSEARCH -b "dc=conn-ttl,$BASEDN" \
+ -D "cn=Barbara Jensen,ou=Information Technology Division,dc=conn-ttl,$BASEDN" \
+ -H $URI2 \
+ -w "bjensen" \
+ -f $TESTDIR/ldapsearch2.fifo >> $TESTOUT 2>&1 &
+LDAPSEARCHPIDS="$LDAPSEARCHPIDS $!"
+
+# Open fifos as file descriptor
+exec 3>$TESTDIR/ldapsearch1.fifo
+exec 4>$TESTDIR/ldapsearch2.fifo
+
+# Trigger LDAP connections towards the proxy by executing a search
+echo 'objectclass=*' >&3
+echo 'objectclass=*' >&4
+
+# wait for ldapsearches (running as background processes) to execute search operations
+sleep 2
+
+echo "Checking that proxy has created connections towards backend (time_t now=`date +%s`)"
+
+$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL \
+ -D "cn=Manager,dc=local,dc=com" \
+ -H $URI2 -w $PASSWD olmDbConnURI 2>&1 | \
+ tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "Error: LDAP connection to remote LDAP server is not found ($RC)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS $LDAPSEARCHPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -b "cn=Connections,cn=database 3,cn=databases,cn=monitor" -s one -LLL \
+ -D "cn=Manager,dc=local,dc=com" \
+ -H $URI2 -w $PASSWD olmDbConnURI 2>&1 | \
+ tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "Error: LDAP connection to remote LDAP server is not found ($RC)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS $LDAPSEARCHPIDS
+ exit $RC
+fi
+
+# Wait for connections to be closed, either due to
+# - idle-timeout and
+# - conn-ttl
+# sleep 2 second overtime for robustness of the test case
+echo "Sleeping until idle-timeout and conn-ttl have passed"
+NOW=`date +%s`
+sleep `expr $CONN_EXPIRES - $NOW + 2`
+
+echo "Checking that proxy has closed expired connections towards the remote LDAP server (time_t now=`date +%s`)"
+
+$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL \
+ -D "cn=Manager,dc=local,dc=com" \
+ -H $URI2 -w $PASSWD olmDbConnURI 2>&1 | \
+ tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 1 ; then
+ echo "Error: LDAP connection to remote LDAP server was not closed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS $LDAPSEARCHPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -b "cn=Connections,cn=database 3,cn=databases,cn=monitor" -s one -LLL \
+ -D "cn=Manager,dc=local,dc=com" \
+ -H $URI2 -w $PASSWD olmDbConnURI 2>&1 | \
+ tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 1 ; then
+ echo "Error: LDAP connection to remote LDAP server was not closed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS $LDAPSEARCHPIDS
+ exit $RC
+fi
+
+# Close the file descriptors associated with the fifos.
+# This will trigger EOF to ldapsearch which will cause it to exit.
+exec 3>&-
+exec 4>&-
+
+
+##############################################################################
+#
+# Test 3: Check that idle-timeout is reset on activity
+#
+
+echo "Checking that idle-timeout is reset on activity"
+CONN_BEGINS=`date +%s`
+CONN_EXPIRES=`expr $CONN_BEGINS + $TIMEOUT`
+echo "Create cached connection: idle-timeout timeout starts (time_t now=$CONN_BEGINS, original_timeout=$CONN_EXPIRES)"
+$LDAPSEARCH -b "dc=idle-timeout,$BASEDN" \
+ -D "cn=Manager,dc=local,dc=com" \
+ -H $URI2 \
+ -w $PASSWD \
+ 'objectclass=*' >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed for base: dc=idle-timeout,$BASEDN ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# sleep until 2 seconds before idle-timeout, then extend the timeout by executing another search operation
+NOW=`date +%s`
+sleep `expr $CONN_EXPIRES - $NOW - 2`
+
+CONN_BEGINS=`date +%s`
+CONN_EXPIRES=`expr $CONN_BEGINS + $TIMEOUT`
+echo "Do another search to reset the timeout (time_t now=$CONN_BEGINS, new_timeout=$CONN_EXPIRES)"
+$LDAPSEARCH -b "dc=idle-timeout,$BASEDN" \
+ -D "cn=Manager,dc=local,dc=com" \
+ -H $URI2 \
+ -w $PASSWD \
+ 'objectclass=*' >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed for base: dc=idle-timeout,$BASEDN ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# sleep until 2 seconds before new extended idle-timeout, check that connection still exist
+NOW=`date +%s`
+sleep `expr $CONN_EXPIRES - $NOW - 2`
+echo "Check that connection is still alive due to idle-timeout reset (time_t now=`date +%s`)"
+$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL \
+ -D "cn=Manager,dc=local,dc=com" \
+ -H $URI2 -w $PASSWD olmDbConnURI 2>&1 | \
+ tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "Error: LDAP connection to remote LDAP server is not found ($RC)"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# sleep until 2 seconds after timeout, check that connection does not exist
+NOW=`date +%s`
+sleep `expr $CONN_EXPIRES - $NOW + 2`
+echo "Check that connection is closed after extended idle-timeout has passed (time_t now=`date +%s`)"
+$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL \
+ -D "cn=Manager,dc=local,dc=com" \
+ -H $URI2 -w $PASSWD olmDbConnURI 2>&1 | \
+ tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 1 ; then
+ echo "Error: LDAP connection to remote LDAP server was not closed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test080-hotp b/tests/scripts/test080-hotp
new file mode 100755
index 0000000..5bfd14a
--- /dev/null
+++ b/tests/scripts/test080-hotp
@@ -0,0 +1,295 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2016-2021 Ondřej Kuzník, Symas Corp.
+## Copyright 2021-2022 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 $OTP = otpno; then
+ echo "OTP overlay not available, test skipped"
+ exit 0
+fi
+
+OTP_DATA=$DATADIR/otp/hotp.ldif
+
+# OTPs for this token
+TOKEN_0=818800
+TOKEN_1=320382
+TOKEN_2=404533
+TOKEN_3=127122
+TOKEN_4=892599
+TOKEN_5=407030
+TOKEN_6=880935
+TOKEN_7=920291
+TOKEN_8=145192
+TOKEN_9=316404
+TOKEN_10=409144
+
+# OTPs for the second set of parameters
+TOKEN_SHA512_11=17544155
+TOKEN_SHA512_12=48953477
+
+mkdir -p $TESTDIR $DBDIR1
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+mkdir $TESTDIR/confdir
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "database config" >>$CONF1
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF1
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -F $TESTDIR/confdir -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep $SLEEP0
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting ${SLEEP1} seconds for slapd to start..."
+ sleep ${SLEEP1}
+done
+
+if [ "$OTP" = otpmod ]; then
+$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF \
+ >> $TESTOUT 2>&1 <<EOMOD
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+olcModuleLoad: otp.la
+EOMOD
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+fi
+
+echo "Loading test otp configuration..."
+$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \
+ >> $TESTOUT 2>&1 <<EOMOD
+dn: olcOverlay={0}otp,olcDatabase={1}$BACKEND,cn=config
+changetype: add
+objectClass: olcOverlayConfig
+EOMOD
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Provisioning tokens and configuration..."
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 < $OTP_DATA
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+
+echo "Authentication tests:"
+echo "\ttoken that's not valid yet..."
+$LDAPWHOAMI -D "$BABSDN" -H $URI1 -w "bjensen$TOKEN_10" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 49 ; then
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "\ta valid and expected token..."
+$LDAPWHOAMI -D "$BABSDN" -H $URI1 -w "bjensen$TOKEN_4" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "\ta valid token skipping some..."
+$LDAPWHOAMI -D "$BABSDN" -H $URI1 -w "bjensen$TOKEN_6" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "\treusing the same token..."
+$LDAPWHOAMI -D "$BABSDN" -H $URI1 -w "bjensen$TOKEN_6" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 49 ; then
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "\tanother account sharing the same token..."
+$LDAPWHOAMI -D "$BJORNSDN" -H $URI1 -w "bjorn$TOKEN_7" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "\ttrying an old token..."
+$LDAPWHOAMI -D "$BJORNSDN" -H $URI1 -w "bjorn$TOKEN_5" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 49 ; then
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "\tright token, wrong password..."
+$LDAPWHOAMI -D "$BJORNSDN" -H $URI1 -w "bjensen$TOKEN_8" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 49 ; then
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "\tmaking sure previous token has been retired too..."
+$LDAPWHOAMI -D "$BJORNSDN" -H $URI1 -w "bjorn$TOKEN_8" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 49 ; then
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "\tthe first token we tested that's just become valid..."
+$LDAPWHOAMI -D "$BABSDN" -H $URI1 -w "bjensen$TOKEN_10" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Reconfiguring token parameters..."
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >/dev/null 2>&1 << EOMODS
+dn: ou=Information Technology Division,ou=People,dc=example,dc=com
+changetype: modify
+replace: oathHOTPParams
+oathHOTPParams: ou=Alumni Association,ou=People,dc=example,dc=com
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "A new round of tests:"
+
+echo "\ta long token that's not valid yet..."
+$LDAPWHOAMI -D "$BABSDN" -H $URI1 -w "bjensen$TOKEN_SHA512_12" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 49 ; then
+ echo "ldapwhoami should have failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "\ta valid and expected token..."
+$LDAPWHOAMI -D "$BABSDN" -H $URI1 -w "bjensen$TOKEN_SHA512_11" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "\tthe previous long token that's just become valid..."
+$LDAPWHOAMI -D "$BABSDN" -H $URI1 -w "bjensen$TOKEN_SHA512_12" \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Retrieving token status..."
+$LDAPSEARCH -b "ou=Information Technology Division,ou=People,dc=example,dc=com" \
+ -H $URI1 objectclass=oathHOTPToken '@oathHOTPToken' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+LDIF=$DATADIR/otp/test001-out.ldif
+
+echo "Filtering ldapsearch results..."
+$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+echo "Filtering ldif with expected data..."
+$LDIFFILTER < $LDIF > $LDIFFLT
+echo "Comparing filter output..."
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test081-totp b/tests/scripts/test081-totp
new file mode 100755
index 0000000..052f0e6
--- /dev/null
+++ b/tests/scripts/test081-totp
@@ -0,0 +1,143 @@
+#!/bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2016-2021 Ondřej Kuzník, Symas Corp.
+## Copyright 2021-2022 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 $OTP = otpno; then
+ echo "OTP overlay not available, test skipped"
+ exit 0
+fi
+
+export URI1 MANAGERDN PASSWD BABSDN BJORNSDN
+
+OTP_DATA=$DATADIR/otp/totp.ldif
+
+mkdir -p $TESTDIR $DBDIR1
+
+for python in python3 python2 python2.7 python27 python ""; do
+ if test x"$python" = x; then
+ echo "Useable Python environment not found, skipping test"
+ exit 0
+ fi
+
+ "$python" "$0".py --check >>$TESTOUT 2>&1
+ RC=$?
+ case $RC in
+ 0)
+ break;;
+ 1)
+ echo "$python is missing some required modules, skipping"
+ python=""
+ continue;;
+ 127)
+ ;;
+ esac
+done
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $CONF > $ADDCONF
+$SLAPADD -f $ADDCONF -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+mkdir $TESTDIR/confdir
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "database config" >>$CONF1
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF1
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -F $TESTDIR/confdir -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep $SLEEP0
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting ${SLEEP1} seconds for slapd to start..."
+ sleep ${SLEEP1}
+done
+
+if [ "$OTP" = otpmod ]; then
+$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF \
+ >> $TESTOUT 2>&1 <<EOMOD
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+olcModuleLoad: otp.la
+EOMOD
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+fi
+
+echo "Loading test otp configuration..."
+$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \
+ >> $TESTOUT 2>&1 <<EOMOD
+dn: olcOverlay={0}otp,olcDatabase={1}$BACKEND,cn=config
+changetype: add
+objectClass: olcOverlayConfig
+EOMOD
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Provisioning tokens and configuration..."
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ >> $TESTOUT 2>&1 < $OTP_DATA
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+"$python" "$0".py
+RC=$?
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+if test $RC != 0 ; then
+ echo "Test failed ($RC)!"
+else
+ echo ">>>>> Test succeeded"
+fi
+
+test $KILLSERVERS != no && wait
+
+exit $RC
diff --git a/tests/scripts/test081-totp.py b/tests/scripts/test081-totp.py
new file mode 100755
index 0000000..aeedaf2
--- /dev/null
+++ b/tests/scripts/test081-totp.py
@@ -0,0 +1,182 @@
+# -*- coding: utf-8 -*-
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2016-2021 Ondřej Kuzník, Symas Corp.
+## Copyright 2021-2022 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>.
+
+from __future__ import print_function
+
+import hashlib
+import hmac
+import os
+import struct
+import sys
+import time
+
+import ldap
+from ldap.cidict import cidict as CIDict
+from ldap.ldapobject import LDAPObject
+
+if len(sys.argv) > 1 and sys.argv[1] == "--check":
+ raise SystemExit(0)
+
+
+def get_digits(h, digits):
+ offset = h[19] & 15
+ number = struct.unpack(">I", h[offset:offset+4])[0] & 0x7fffffff
+ number %= (10 ** digits)
+ return ("%0*d" % (digits, number)).encode()
+
+
+def get_hotp_token(secret, interval_no):
+ msg = struct.pack(">Q", interval_no)
+ h = hmac.new(secret, msg, hashlib.sha1).digest()
+ return get_digits(bytearray(h), 6)
+
+
+def get_interval(period=30):
+ return int(time.time() // period)
+
+
+def get_token_for(connection, dn, typ="totp"):
+ result = connection.search_s(dn, ldap.SCOPE_BASE)
+ dn, attrs = result[0]
+ attrs = CIDict(attrs)
+
+ tokendn = attrs['oath'+typ+'token'][0].decode()
+
+ result = connection.search_s(tokendn, ldap.SCOPE_BASE)
+ dn, attrs = result[0]
+ attrs = CIDict(attrs)
+
+ return dn, attrs
+
+
+def main():
+ uri = os.environ["URI1"]
+
+ managerdn = os.environ['MANAGERDN']
+ passwd = os.environ['PASSWD']
+
+ babsdn = os.environ['BABSDN']
+ babspw = b"bjensen"
+
+ bjornsdn = os.environ['BJORNSDN']
+ bjornspw = b"bjorn"
+
+ connection = LDAPObject(uri)
+
+ start = time.time()
+ connection.bind_s(managerdn, passwd)
+ end = time.time()
+
+ if end - start > 1:
+ print("It takes more than a second to connect and bind, "
+ "skipping potentially unstable test", file=sys.stderr)
+ raise SystemExit(0)
+
+ dn, token_entry = get_token_for(connection, babsdn)
+
+ paramsdn = token_entry['oathTOTPParams'][0].decode()
+ result = connection.search_s(paramsdn, ldap.SCOPE_BASE)
+ _, attrs = result[0]
+ params = CIDict(attrs)
+
+ secret = token_entry['oathSecret'][0]
+ period = int(params['oathTOTPTimeStepPeriod'][0].decode())
+
+ bind_conn = LDAPObject(uri)
+
+ interval_no = get_interval(period)
+ token = get_hotp_token(secret, interval_no-3)
+
+ print("Testing old tokens are not useable")
+ bind_conn.bind_s(babsdn, babspw+token)
+ try:
+ bind_conn.bind_s(babsdn, babspw+token)
+ except ldap.INVALID_CREDENTIALS:
+ pass
+ else:
+ raise SystemExit("Bind with an old token should have failed")
+
+ interval_no = get_interval(period)
+ token = get_hotp_token(secret, interval_no)
+
+ print("Testing token can only be used once")
+ bind_conn.bind_s(babsdn, babspw+token)
+ try:
+ bind_conn.bind_s(babsdn, babspw+token)
+ except ldap.INVALID_CREDENTIALS:
+ pass
+ else:
+ raise SystemExit("Bind with a reused token should have failed")
+
+ token = get_hotp_token(secret, interval_no+1)
+ try:
+ bind_conn.bind_s(babsdn, babspw+token)
+ except ldap.INVALID_CREDENTIALS:
+ raise SystemExit("Bind should have succeeded")
+
+ dn, token_entry = get_token_for(connection, babsdn)
+ last = int(token_entry['oathTOTPLastTimeStep'][0].decode())
+ if last != interval_no+1:
+ SystemExit("Unexpected counter value %d (expected %d)" %
+ (last, interval_no+1))
+
+ print("Resetting counter and testing secret sharing between accounts")
+ connection.modify_s(dn, [(ldap.MOD_REPLACE, 'oathTOTPLastTimeStep', [])])
+
+ interval_no = get_interval(period)
+ token = get_hotp_token(secret, interval_no)
+
+ try:
+ bind_conn.bind_s(bjornsdn, bjornspw+token)
+ except ldap.INVALID_CREDENTIALS:
+ raise SystemExit("Bind should have succeeded")
+
+ try:
+ bind_conn.bind_s(babsdn, babspw+token)
+ except ldap.INVALID_CREDENTIALS:
+ pass
+ else:
+ raise SystemExit("Bind with a reused token should have failed")
+
+ print("Testing token is retired even with a wrong password")
+ connection.modify_s(dn, [(ldap.MOD_REPLACE, 'oathTOTPLastTimeStep', [])])
+
+ interval_no = get_interval(period)
+ token = get_hotp_token(secret, interval_no)
+
+ try:
+ bind_conn.bind_s(babsdn, b"not the password"+token)
+ except ldap.INVALID_CREDENTIALS:
+ pass
+ else:
+ raise SystemExit("Bind with an incorrect password should have failed")
+
+ try:
+ bind_conn.bind_s(babsdn, babspw+token)
+ except ldap.INVALID_CREDENTIALS:
+ pass
+ else:
+ raise SystemExit("Bind with a reused token should have failed")
+
+ token = get_hotp_token(secret, interval_no+1)
+ try:
+ bind_conn.bind_s(babsdn, babspw+token)
+ except ldap.INVALID_CREDENTIALS:
+ raise SystemExit("Bind should have succeeded")
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/tests/scripts/test082-remoteauth b/tests/scripts/test082-remoteauth
new file mode 100755
index 0000000..b20a6f9
--- /dev/null
+++ b/tests/scripts/test082-remoteauth
@@ -0,0 +1,417 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2016-2021 Ondřej Kuzník, Symas Corp.
+## Copyright 1998-2022 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 $WITH_TLS = no ; then
+ echo "TLS support not available, test skipped"
+ exit 0
+fi
+
+if test $REMOTEAUTH = remoteauthno; then
+ echo "RemoteAuth overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2 $TESTDIR/confdir
+cp -r $DATADIR/tls $TESTDIR
+
+. $CONFFILTER < $DATADIR/remoteauth/default_domain > $TESTDIR/default_domain
+
+. $CONFFILTER $BACKEND < $TLSCONF > $CONF1
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "database config" >>$CONF1
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF1
+echo "TLSCACertificateFile $TESTDIR/tls/ca/certs/testsuiteCA.crt" >>$CONF1
+
+$SLAPD -Tt -n 0 -f $CONF1 -F $TESTDIR/confdir -d $LVL > $LOG1 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "slaptest failed ($RC)!"
+ exit $RC
+fi
+
+echo -n "Running slapadd to build slapd database... "
+$SLAPADD -F $TESTDIR/confdir -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "DB tweaks..."
+$SLAPMODIFY -F $TESTDIR/confdir >>$LOG1 2>&1 <<EOMODS
+dn: $MELLIOTDN
+changetype: modify
+add: o
+o: self
+-
+replace: seeAlso
+seeAlso: $BJORNSDN
+
+dn: $JOHNDDN
+changetype: modify
+replace: seeAlso
+seeAlso: $BJORNSDN
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "slapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1 for configuration..."
+$SLAPD -F $TESTDIR/confdir -h $URI1 -d $LVL >> $LOG1 2>&1 &
+REMOTEAUTH_PID=$!
+if test $WAIT != 0 ; then
+ echo REMOTEAUTH_PID $REMOTEAUTH_PID
+ read foo
+fi
+KILLPIDS="$REMOTEAUTH_PID"
+
+sleep $SLEEP0
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting ${SLEEP1} seconds for slapd to start..."
+ sleep ${SLEEP1}
+done
+
+if [ "$REMOTEAUTH" = remoteauthmod ]; then
+$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF \
+ >> $TESTOUT 2>&1 <<EOMOD
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+olcModuleLoad: remoteauth.la
+EOMOD
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+fi
+
+echo "Loading test remoteauth configuration..."
+. $CONFFILTER $BACKEND < $DATADIR/remoteauth/config.ldif | \
+$LDAPADD -v -D cn=config -H $URI1 -y $CONFIGPWF \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo -n "Preparing second server on $URI2 and $SURIP3... "
+. $CONFFILTER $BACKEND < $TLSCONF | sed -e "s,$DBDIR1,$DBDIR2," > $CONF2
+
+echo -n "loading data... "
+$SLAPADD -f $CONF2 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo -n "tweaking DB contents... "
+$SLAPMODIFY -f $CONF2 >>$LOG2 2>&1 <<EOMODS
+dn: $BJORNSDN
+changetype: modify
+replace: userPassword
+userPassword: bjorn2
+EOMODS
+RC=$?
+if test $RC != 0 ; then
+ echo "slapmodify failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "starting up... "
+$SLAPD -f $CONF2 -h "$URI2 $SURIP3" -d $LVL > $LOG2 2>&1 &
+BACKEND_PID=$!
+if test $WAIT != 0 ; then
+ echo BACKEND_PID $BACKEND_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $BACKEND_PID"
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting ${SLEEP1} seconds for slapd to start..."
+ sleep ${SLEEP1}
+done
+
+if test $RC != 0 ; then
+ echo "failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+. $CONFFILTER $BACKEND < $TLSCONF > $CONF1
+
+echo "TLSCACertificateFile $TESTDIR/tls/ca/certs/testsuiteCA.crt" >>$CONF1
+echo "database config" >>$CONF1
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF1
+
+# We check basic remoteauth operation and generated configuration in these
+# circumstances:
+# 1. configured online through cn=config (what we set up above)
+# 2. the server from 1. restarted (loading from cn=config on startup)
+# 3. configured and started through a slapd.conf
+#
+# All of the above should present the same behaviour and cn=config output
+
+echo "Saving generated config before server restart..."
+echo "# search output from dynamically configured server..." >> $SERVER1OUT
+$LDAPSEARCH -D cn=config -H $URI1 -y $CONFIGPWF \
+ -b "olcOverlay={0}remoteauth,olcDatabase={1}$BACKEND,cn=config" \
+ >> $SERVER1OUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo -n "Checking bind handling... "
+
+$LDAPWHOAMI -H $URI1 -x -D "$BJORNSDN" -w bjorn >/dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+echo -n "1 "
+
+$LDAPWHOAMI -H $URI1 -x -D "$JOHNDDN" -w bjorn2 >/dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+echo -n "2 "
+
+$LDAPWHOAMI -H $URI1 -x -D "$MELLIOTDN" -w bjorn >/dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+echo -n "3 "
+
+echo "ok"
+
+echo "Stopping slapd on TCP/IP port $PORT1..."
+kill -HUP $REMOTEAUTH_PID
+KILLPIDS="$BACKEND_PID"
+sleep $SLEEP0
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -F $TESTDIR/confdir -h $URI1 -d $LVL >> $LOG1 2>&1 &
+REMOTEAUTH_PID=$!
+if test $WAIT != 0 ; then
+ echo REMOTEAUTH_PID $REMOTEAUTH_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $REMOTEAUTH_PID"
+
+sleep $SLEEP0
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting ${SLEEP1} seconds for slapd to start..."
+ sleep ${SLEEP1}
+done
+
+echo "Saving generated config after server restart..."
+echo "# search output from dynamically configured server after restart..." >> $SERVER2OUT
+$LDAPSEARCH -D cn=config -H $URI1 -y $CONFIGPWF \
+ -b "olcOverlay={0}remoteauth,olcDatabase={1}$BACKEND,cn=config" \
+ >> $SERVER2OUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo -n "Checking bind handling... "
+
+$LDAPWHOAMI -H $URI1 -x -D "$BJORNSDN" -w bjorn >/dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+echo -n "1 "
+
+$LDAPWHOAMI -H $URI1 -x -D "$JOHNDDN" -w bjorn2 >/dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+echo -n "2 "
+
+$LDAPWHOAMI -H $URI1 -x -D "$MELLIOTDN" -w bjorn >/dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+echo -n "3 "
+
+echo "ok"
+
+echo "Stopping slapd on TCP/IP port $PORT1..."
+kill -HUP $REMOTEAUTH_PID
+KILLPIDS="$BACKEND_PID"
+sleep $SLEEP0
+
+echo "Testing slapd.conf support..."
+sed -e "s,database.*monitor,\\
+TLSCACertificateFile $TESTDIR/tls/ca/certs/testsuiteCA.crt\\
+\\
+#remoteauthmod#moduleload ../servers/slapd/overlays/remoteauth.la\\
+include $TESTDIR/remoteauth.conf\\
+\\
+database monitor," $TLSCONF | . $CONFFILTER $BACKEND >$CONF1
+echo "database config" >>$CONF1
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF1
+
+. $CONFFILTER $BACKEND < $DATADIR/remoteauth/remoteauth.conf >$TESTDIR/remoteauth.conf
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL >> $LOG1 2>&1 &
+REMOTEAUTH_PID=$!
+if test $WAIT != 0 ; then
+ echo REMOTEAUTH_PID $REMOTEAUTH_PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $REMOTEAUTH_PID"
+
+sleep $SLEEP0
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting ${SLEEP1} seconds for slapd to start..."
+ sleep ${SLEEP1}
+done
+
+echo "Saving generated config from a slapd.conf sourced server..."
+echo "# search output from server running from slapd.conf..." >> $SERVER3OUT
+$LDAPSEARCH -D cn=config -H $URI1 -y $CONFIGPWF \
+ -b "olcOverlay={0}remoteauth,olcDatabase={1}$BACKEND,cn=config" \
+ >> $SERVER3OUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo -n "Checking bind handling... "
+
+$LDAPWHOAMI -H $URI1 -x -D "$BJORNSDN" -w bjorn >/dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+echo -n "1 "
+
+$LDAPWHOAMI -H $URI1 -x -D "$JOHNDDN" -w bjorn2 >/dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+echo -n "2 "
+
+$LDAPWHOAMI -H $URI1 -x -D "$MELLIOTDN" -w bjorn >/dev/null
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+echo -n "3 "
+
+echo "ok"
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+# LDIFFILTER doesn't (un)wrap long lines yet, so the result would differ
+#. $CONFFILTER $BACKEND < $DATADIR/remoteauth/config.ldif \
+# | $LDIFFILTER -s a > $SERVER6FLT
+
+# We've already filtered out the ordering markers, now sort the entries
+echo "Filtering ldapsearch results..."
+$LDIFFILTER -s a < $SERVER1OUT > $SERVER1FLT
+$LDIFFILTER -s a < $SERVER2OUT > $SERVER2FLT
+$LDIFFILTER -s a < $SERVER3OUT > $SERVER3FLT
+echo "Filtering expected entries..."
+
+echo "Comparing filter output..."
+#$CMP $SERVER6FLT $SERVER1FLT > $CMPOUT && \
+$CMP $SERVER1FLT $SERVER2FLT > $CMPOUT && \
+$CMP $SERVER2FLT $SERVER3FLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test083-argon2 b/tests/scripts/test083-argon2
new file mode 100755
index 0000000..01803b3
--- /dev/null
+++ b/tests/scripts/test083-argon2
@@ -0,0 +1,159 @@
+#!/bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2021-2022 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 $ARGON2 = argon2no; then
+ echo "argon2 overlay not available, test skipped"
+ exit 0
+fi
+
+USERDN="cn=argon2,$BASEDN"
+
+CONFDIR=$TESTDIR/slapd.d
+mkdir -p $TESTDIR $CONFDIR $DBDIR1
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+cat > $TESTDIR/config.ldif <<EOF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+olcArgsFile: $TESTDIR/slapd.args
+olcPidFile: $TESTDIR/slapd.pid
+
+dn: cn=schema,cn=config
+objectClass: olcSchemaConfig
+cn: schema
+
+include: file://$TESTWD/schema/core.ldif
+include: file://$TESTWD/schema/cosine.ldif
+include: file://$TESTWD/schema/inetorgperson.ldif
+EOF
+
+if [ "$BACKENDTYPE" = mod ]; then
+ cat >> $TESTDIR/config.ldif <<EOF
+
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/back-$BACKEND
+olcModuleLoad: back_$BACKEND.la
+EOF
+fi
+
+if [ "$ARGON2" = argon2yes ]; then
+ cat >> $TESTDIR/config.ldif <<EOF
+
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/pwmods
+olcModuleLoad: argon2.la
+EOF
+fi
+
+cat >> $TESTDIR/config.ldif <<EOF
+
+dn: olcDatabase={-1}frontend,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olcFrontendConfig
+olcDatabase: {-1}frontend
+olcPasswordHash: {ARGON2}
+
+dn: olcDatabase=config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: config
+olcRootPW:< file://$CONFIGPWF
+
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olc${BACKEND}Config
+olcDatabase: $BACKEND
+olcSuffix: $BASEDN
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+olcDbDirectory: $TESTDIR/db.1.a
+EOF
+
+if [ "$INDEXDB" = indexdb ]; then
+ cat >> $TESTDIR/config.ldif <<EOF
+olcDbIndex: objectClass eq,pres
+olcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub
+EOF
+fi
+
+$SLAPADD -F $CONFDIR -n 0 -l $TESTDIR/config.ldif
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -F $CONFDIR -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+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 "$MONITOR" -H $URI1 \
+ '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 basic structure..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $LDIFPASSWD >/dev/null 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $PID
+ exit $RC
+fi
+
+BINDPW=secret
+echo "Testing ldapwhoami as ${USERDN}..."
+$LDAPWHOAMI -H $URI1 -D "$USERDN" -w $BINDPW
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapwhoami failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $PID
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test084-deref b/tests/scripts/test084-deref
new file mode 100755
index 0000000..b176d8e
--- /dev/null
+++ b/tests/scripts/test084-deref
@@ -0,0 +1,94 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2021-2022 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 $DEREF = derefno; then
+ echo "Deref overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $DEREFCONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFDEREF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Testing slapd deref control operations..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ '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 "Sending deref control..."
+
+$LDAPSEARCH -b "$DEREFBASEDN" -H $URI1 \
+ -E 'deref=member:uid' > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Comparing output..."
+$CMP $SEARCHOUT $DEREFOUT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+test $KILLSERVERS != no && wait
+
+echo ">>>>> Test succeeded"
+
+exit 0
diff --git a/tests/scripts/test085-homedir b/tests/scripts/test085-homedir
new file mode 100755
index 0000000..3b98ca5
--- /dev/null
+++ b/tests/scripts/test085-homedir
@@ -0,0 +1,143 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2021-2022 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 $HOMEDIR = homedirno; then
+ echo "Homedir overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $TESTDIR/home $TESTDIR/archive
+
+# copy skel dir so we can create symlinks in it
+cp -r $DATADIR/homedir/skel $TESTDIR
+(cd $TESTDIR/skel; mkdir directory; ln -s directory symlink; cd directory; ln -s ../target "broken link")
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
+
+echo "Running slapadd to build slapd database..."
+. $CONFFILTER $BACKEND < $HOMEDIRCONF | sed "s/@MINUID@/`id -u`/" > $CONF1
+$SLAPADD -f $CONF1 -l $LDIF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+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 "$MONITOR" -H $URI1 \
+ '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 a new user..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD <<EOMOD >> $TESTOUT 2>&1
+dn: uid=user1,ou=People,$BASEDN
+objectClass: account
+objectClass: posixAccount
+uid: user1
+cn: One user
+uidNumber: `id -u`
+gidNumber: `id -g`
+homeDirectory: /home/user1
+EOMOD
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+sleep 1
+
+if ! test -e $TESTDIR/home/user1 ; then
+ echo "Home directory for user1 not created!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Moving home directory for user1..."
+$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD <<EOMOD >> $TESTOUT 2>&1
+dn: uid=user1,ou=People,$BASEDN
+changetype: modify
+replace: homeDirectory
+homeDirectory: /home/user1_new
+EOMOD
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+sleep 1
+
+if test -e $TESTDIR/home/user1 || ! test -e $TESTDIR/home/user1_new ; then
+ echo "Home directory for user1 not moved!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Removing user1, should get archived..."
+$LDAPDELETE -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ "uid=user1,ou=People,$BASEDN" >> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapdelete failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+sleep 1
+
+if test -e $TESTDIR/home/user1_new || \
+ ! test -e $TESTDIR/archive/user1_new-*-0.tar ; then
+ echo "Home directory for user1 not archived properly!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+test $KILLSERVERS != no && wait
+
+echo ">>>>> Test succeeded"
+
+exit 0
diff --git a/tests/scripts/test086-delta-consumer-config b/tests/scripts/test086-delta-consumer-config
new file mode 100755
index 0000000..d89af3f
--- /dev/null
+++ b/tests/scripts/test086-delta-consumer-config
@@ -0,0 +1,594 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+if test $ACCESSLOG = accesslogno; then
+ echo "Accesslog overlay not available, test skipped"
+ exit 0
+fi
+
+CFPRO=$TESTDIR/cfpro.d
+CFCON=$TESTDIR/cfcon.d
+
+mkdir -p $TESTDIR $DBDIR1A $DBDIR1B $DBDIR1C $DBDIR1D $DBDIR2A $CFPRO $CFCON
+
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+if test x"$SYNCMODE" = x ; then
+ SYNCMODE=rp
+fi
+case "$SYNCMODE" in
+ ro)
+ SYNCTYPE="type=refreshOnly interval=00:00:00:03"
+ ;;
+ rp)
+ SYNCTYPE="type=refreshAndPersist"
+ ;;
+ *)
+ echo "unknown sync mode $SYNCMODE"
+ exit 1;
+ ;;
+esac
+
+#
+# Test replication of dynamic config with alternate consumer config:
+# - start provider
+# - start consumer
+# - configure over ldap
+# - populate over ldap
+# - configure syncrepl over ldap
+# - retrieve database over ldap and compare against expected results
+#
+
+echo "Starting provider slapd on TCP/IP port $PORT1..."
+. $CONFFILTER $BACKEND < $DYNAMICCONF > $CONFLDIF
+$SLAPADD -F $CFPRO -n 0 -l $CONFLDIF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+$SLAPD -F $CFPRO -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$PID"
+
+sleep 1
+
+echo "Using ldapsearch to check that provider slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI1 \
+ '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 "Inserting syncprov and accesslog overlays on provider..."
+if [ "$SYNCPROV" = syncprovmod -a "$ACCESSLOG" = accesslogmod ]; then
+ $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: ../servers/slapd/overlays
+olcModuleLoad: syncprov.la
+olcModuleLoad: accesslog.la
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for moduleLoad of syncprov and accesslog ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+elif [ "$SYNCPROV" = syncprovmod ]; then
+ $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: ../servers/slapd/overlays
+olcModuleLoad: syncprov.la
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for moduleLoad of syncprov ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+elif [ "$ACCESSLOG" = accesslogmod ]; then
+ $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: ../servers/slapd/overlays
+olcModuleLoad: accesslog.la
+EOF
+ RC=$?
+ if test $RC != 0 ; then
+ echo "ldapadd failed for moduleLoad of accesslog ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+
+echo "Adding backend accesslog databases using $BACKEND..."
+if [ "$BACKENDTYPE" = mod ]; then
+ $LDAPADD -D cn=config -H $URI1 -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 moduleLoad of $BACKEND ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+ fi
+fi
+
+read CONFIGPW < $CONFIGPWF
+$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+olcSuffix: cn=accesslog
+${nullExclude}olcDbDirectory: $DBDIR1C
+olcRootDN: cn=config
+olcSizeLimit: unlimited
+olcTimeLimit: unlimited
+olcDbIndex: default eq
+olcDbIndex: entryCSN,objectClass,reqEnd,reqResult,reqStart,reqDN
+
+dn: olcOverlay=syncprov,olcDatabase={1}${BACKEND},cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+olcSpNoPresent: TRUE
+olcSpReloadHint: TRUE
+
+dn: olcDatabase={2}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olc${BACKEND}Config
+olcDatabase: {2}$BACKEND
+olcSuffix: cn=consumer-accesslog
+${nullExclude}olcDbDirectory: $DBDIR1D
+olcRootDN: cn=consumer,cn=config
+olcSizeLimit: unlimited
+olcTimeLimit: unlimited
+olcDbIndex: default eq
+olcDbIndex: entryCSN,objectClass,reqEnd,reqResult,reqStart,reqDN
+
+dn: olcOverlay=syncprov,olcDatabase={2}${BACKEND},cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+olcSpNoPresent: TRUE
+olcSpReloadHint: TRUE
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for accesslog databases using $BACKEND ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+
+dn: olcOverlay=accesslog,olcDatabase={0}config,cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcAccessLogConfig
+olcOverlay: accesslog
+olcAccessLogDB: cn=accesslog
+olcAccessLogOps: writes
+olcAccessLogPurge: 07+00:00 01+00:00
+olcAccessLogSuccess: TRUE
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for syncprov and accesslog overlay config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# Consumers will not replicate the provider's actual cn=config.
+# Instead, they will use an alternate DB so that they may be
+# configured differently from the provider. This alternate DB
+# will also be a consumer for the real cn=schema,cn=config tree.
+# It has multi-provider enabled so that it can be written directly
+# while being a consumer of the main schema.
+echo "Configuring accesslog config DB on provider..."
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=config
+changetype: modify
+add: olcServerID
+olcServerID: 1
+
+dn: olcDatabase={1}ldif,cn=config
+changetype: add
+objectClass: olcDatabaseConfig
+objectClass: olcLdifConfig
+olcDatabase: {1}ldif
+olcDbDirectory: $DBDIR1A
+olcSuffix: cn=config,cn=consumer
+olcRootDN: cn=config,cn=consumer
+olcRootPW: repsecret
+olcAccess: to * by dn.base="cn=config" write
+
+dn: olcOverlay=syncprov,olcDatabase={1}ldif,cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+
+dn: olcOverlay=accesslog,olcDatabase={1}ldif,cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcAccessLogConfig
+olcOverlay: accesslog
+olcAccessLogDB: cn=consumer-accesslog
+olcAccessLogOps: writes
+olcAccessLogPurge: 07+00:00 01+00:00
+olcAccessLogSuccess: TRUE
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for consumer DB config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting 3 seconds for syncrepl to make root accesslog entry..."
+sleep 3
+
+echo "Configuring consumer config DB on provider..."
+$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
+dn: cn=config,cn=consumer
+changetype: add
+objectClass: olcGlobal
+cn: consumerconfig
+
+dn: olcDatabase={0}config,cn=config,cn=consumer
+changetype: add
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW: topsecret
+olcSyncrepl: {0}rid=001 provider=$URI1 binddn="cn=config,cn=consumer"
+ bindmethod=simple credentials=repsecret searchbase="cn=config,cn=consumer"
+ $SYNCTYPE retry="3 5 300 5" timeout=3 suffixmassage="cn=config"
+olcUpdateRef: $URI1
+
+dn: olcDatabase={1}ldif,cn=config
+changetype: modify
+add: olcSyncrepl
+olcSyncrepl: {0}rid=001 provider=$URI1 binddn="cn=config"
+ bindmethod=simple credentials=$CONFIGPW searchbase="cn=schema,cn=config"
+ $SYNCTYPE retry="3 5 300 5" timeout=3
+ suffixmassage="cn=schema,cn=config,cn=consumer"
+# a dummy stanza we add to the beginning and remove again
+olcSyncrepl: {0}rid=006 provider=$URI6 binddn="cn=config"
+ bindmethod=simple credentials=$CONFIGPW searchbase="cn=schema,cn=config"
+ $SYNCTYPE retry="3 5 300 5" timeout=3
+ suffixmassage="cn=schema,cn=config,cn=consumer"
+-
+delete: olcSyncrepl
+olcSyncrepl: {0}
+-
+add: olcMultiProvider
+olcMultiProvider: TRUE
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed for consumer DB config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting consumer slapd on TCP/IP port $PORT2..."
+$SLAPADD -F $CFCON -n 0 -l $CONFLDIF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$SLAPD -F $CFCON -h $URI2 -d $LVL > $LOG2 2>&1 &
+CONSUMERPID=$!
+if test $WAIT != 0 ; then
+ echo CONSUMERPID $CONSUMERPID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $CONSUMERPID"
+
+sleep 1
+
+echo "Using ldapsearch to check that consumer slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI2 \
+ '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 "Configuring syncrepl on consumer..."
+$LDAPMODIFY -D cn=config -H $URI2 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: olcDatabase={0}config,cn=config
+changetype: modify
+add: olcSyncRepl
+olcSyncRepl: rid=001 provider=$URI1 binddn="cn=config,cn=consumer"
+ bindmethod=simple credentials=repsecret searchbase="cn=config,cn=consumer"
+ $SYNCTYPE retry="3 5 300 5" timeout=3 logbase="cn=consumer-accesslog"
+ logfilter="(&(objectclass=auditWriteObject)(reqresult=0))"
+ syncdata=accesslog suffixmassage="cn=config"
+-
+add: olcUpdateRef
+olcUpdateRef: $URI1
+EOF
+
+sleep 1
+
+echo "Using ldapsearch to check that syncrepl received config changes..."
+RC=32
+for i in 0 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI2 -D cn=config -y $CONFIGPWF \
+ -s base -b "olcDatabase={0}config,cn=config" \
+ '(olcUpdateRef=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+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 provider..."
+$LDAPADD -D cn=config -H $URI1 -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
+
+echo "Using ldapsearch to check that syncrepl received the schema changes..."
+RC=32
+for i in 0 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI2 -D cn=config -y $CONFIGPWF \
+ -s sub -b "cn=schema,cn=config" \
+ '(cn=*openldap)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+done
+
+if test "x$RESULT" != "xOK" ; then
+ echo "consumer never received complete schema!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+nullExclude="" nullOK=""
+test $BACKEND = null && nullExclude="# " nullOK="OK"
+
+if [ "$BACKENDTYPE" = mod ]; then
+ $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: cn=module,cn=config,cn=consumer
+objectClass: olcModuleList
+cn: module
+olcModulePath: ../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 $URI1 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: olcDatabase={2}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {2}$BACKEND
+olcSuffix: $BASEDN
+${nullExclude}olcDbDirectory: $DBDIR1B
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+olcSyncRepl: rid=002 provider=$URI1 binddn="$MANAGERDN" bindmethod=simple
+ credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE
+ retry="3 5 300 5" timeout=3
+olcUpdateRef: $URI1
+
+dn: olcOverlay=syncprov,olcDatabase={2}${BACKEND},cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+
+dn: olcDatabase={1}$BACKEND,cn=config,cn=consumer
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+olcSuffix: $BASEDN
+${nullExclude}olcDbDirectory: $DBDIR2A
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+olcSyncRepl: rid=002 provider=$URI1 binddn="$MANAGERDN" bindmethod=simple
+ credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE
+ retry="3 5 300 5" timeout=3
+olcUpdateRef: $URI1
+
+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 $URI1 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
+dn: olcDatabase={2}$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 provider..."
+$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $LDIFORDERED \
+ >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed for database config ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+sleep $SLEEP1
+
+echo "Using ldapsearch to check that syncrepl received database changes..."
+RC=32
+for i in 0 1 2 3 4 5; do
+ RESULT=`$LDAPSEARCH -H $URI2 \
+ -s base -b "cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com" \
+ '(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
+ if test "x$RESULT$nullOK" = "xOK" ; then
+ RC=0
+ break
+ fi
+ echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
+ sleep $SLEEP1
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the provider..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI1 -w $PASSWD \
+ 'objectclass=*' > $PROVIDEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at provider ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapsearch to read all the entries from the consumer..."
+$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI2 -w $PASSWD \
+ 'objectclass=*' > $CONSUMEROUT 2>&1
+RC=$?
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed at consumer ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo "Filtering provider results..."
+$LDIFFILTER < $PROVIDEROUT > $PROVIDERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER < $CONSUMEROUT > $CONSUMERFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $PROVIDERFLT $CONSUMERFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "test failed - provider and consumer databases differ"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0
diff --git a/tests/scripts/test087-librewrite b/tests/scripts/test087-librewrite
new file mode 100755
index 0000000..0dca1f5
--- /dev/null
+++ b/tests/scripts/test087-librewrite
@@ -0,0 +1,91 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $RWM = rwmno ; then
+ echo "rwm (Rewrite/remap) overlay not available, test skipped"
+ exit 0
+fi
+
+mkdir -p $TESTDIR
+
+echo "" >>$TESTOUT
+echo "# making a filter from a DN" > $TESTOUT
+echo "Testing DN unescaping then escaping for use in a filter..."
+for input in \
+ "uid=test\\20\\2c\\31\\\\" \
+ "uid=test,ou=People,dc=example,dc=com" \
+ "cn=test\\00)(uid=test,dc=example,dc=com" \
+ "cn=*" \
+ "cn=*\\\\" \
+ "cn=*\\" \
+ ; do
+
+ $TESTWD/../libraries/librewrite/rewrite -f $DATADIR/rewrite.conf \
+ -r testdn2filter "$input" >>$TESTOUT 2>/dev/null
+ if test $? != 0 ; then
+ echo "rewriting failed"
+ exit 1
+ fi
+done
+
+echo "" >>$TESTOUT
+echo "# pasting a DN into a filter" >> $TESTOUT
+echo "Testing filter escaping..."
+for input in \
+ "uid=test\\20\\31\\\\" \
+ "cn=test)(uid=test,dc=example,dc=com" \
+ "cn=*" \
+ "cn=*\\\\" \
+ "cn=*\\" \
+ ; do
+
+ $TESTWD/../libraries/librewrite/rewrite -f $DATADIR/rewrite.conf \
+ -r testdn2dnfilter "$input" >>$TESTOUT 2>/dev/null
+ if test $? != 0 ; then
+ echo "rewriting failed"
+ exit 1
+ fi
+done
+
+echo "" >>$TESTOUT
+echo "# pasting a filter into a DN" >> $TESTOUT
+echo "Testing filter unescaping then escaping the value into a DN..."
+for input in \
+ "(uid=test)" \
+ "(cn=something ,\\29+\\28 \\2A=)" \
+ "(description=test\\20\\31*)" \
+ "(description=test\\20\\31)" \
+ ; do
+
+ $TESTWD/../libraries/librewrite/rewrite -f $DATADIR/rewrite.conf \
+ -r testfilter2dn "$input" >>$TESTOUT 2>/dev/null
+ if test $? != 0 ; then
+ echo "rewriting failed"
+ exit 1
+ fi
+done
+
+$CMP $DATADIR/rewrite.out $TESTOUT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "comparison failed - rewriting did not complete correctly"
+ exit 1
+fi
+
+echo ">>>>> Test succeeded"
+exit 0
diff --git a/tests/scripts/test088-syncprov-glue-rwm b/tests/scripts/test088-syncprov-glue-rwm
new file mode 100755
index 0000000..307e05c
--- /dev/null
+++ b/tests/scripts/test088-syncprov-glue-rwm
@@ -0,0 +1,574 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2022 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 $BACKLDAP = ldapno; then
+ echo "LDAP backend not available, test skipped"
+ exit 0
+fi
+
+if test $RWM = rwmno; then
+ echo "rwm (rewrite/remap) overlay not available, test skipped"
+ exit 0
+fi
+
+if test $SYNCPROV = syncprovno; then
+ echo "Syncrepl provider overlay not available, test skipped"
+ exit 0
+fi
+
+RMTSUFFIX="dc=remote,$BASEDN"
+RMTROOTDN="cn=Manager,$RMTSUFFIX"
+
+RMTDIR=$TESTDIR/remote
+PR1DIR=$TESTDIR/provider1
+PR2DIR=$TESTDIR/provider2
+RMTCONF=$RMTDIR/slapd.d
+PR1CONF=$PR1DIR/slapd.d
+PR2CONF=$PR2DIR/slapd.d
+
+ENTRIES=$TESTDIR/entries.ldif
+SYNC1OUT=$TESTDIR/syncrepl1.out
+SYNC2OUT=$TESTDIR/syncrepl2.out
+
+mkdir -p $RMTDIR $RMTCONF $RMTDIR/db
+mkdir -p $PR1DIR $PR1CONF $PR1DIR/db
+mkdir -p $PR2DIR $PR2CONF $PR2DIR/db
+
+cd $TESTDIR
+
+KILLPIDS=
+
+$SLAPPASSWD -g -n > $CONFIGPWF
+
+cat <<EOF > $CONFLDIF
+dn: cn=config
+objectClass: olcGlobal
+cn: config
+
+dn: olcDatabase={0}config,cn=config
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW:< file://$CONFIGPWF
+
+dn: cn=schema,cn=config
+objectClass: olcSchemaConfig
+cn: schema
+
+include: file://$ABS_SCHEMADIR/core.ldif
+include: file://$ABS_SCHEMADIR/cosine.ldif
+include: file://$ABS_SCHEMADIR/nis.ldif
+include: file://$ABS_SCHEMADIR/inetorgperson.ldif
+
+dn: cn=module,cn=config
+objectClass: olcModuleList
+cn: module
+olcModulePath: $TESTWD/../servers/slapd/overlays
+EOF
+
+[ "$BACKENDTYPE" = mod ] && echo "olcModuleLoad: $TESTWD/../servers/slapd/back-$BACKEND/back_$BACKEND.la" >> $CONFLDIF
+
+echo "Initializing remote configurations..."
+cat $CONFLDIF - <<EOF | $SLAPADD -F $RMTCONF -n 0
+
+dn: olcDatabase={1}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {1}$BACKEND
+${nullExclude}olcDbDirectory: $RMTDIR/db
+olcSuffix: $RMTSUFFIX
+olcRootDN: $RMTROOTDN
+olcRootPW: $PASSWD
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+[ "$BACKLDAP" = ldapmod ] && echo "olcModuleLoad: $TESTWD/../servers/slapd/back-ldap/back_ldap.la" >> $CONFLDIF
+[ "$RWM" = rwmmod ] && echo "olcModuleLoad: rwm.la" >> $CONFLDIF
+[ "$SYNCPROV" = syncprovmod ] && echo "olcModuleLoad: syncprov.la" >> $CONFLDIF
+cat <<EOF >> $CONFLDIF
+
+dn: olcDatabase={1}ldap,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olcLDAPConfig
+olcDatabase: {1}ldap
+olcSuffix: ou=remote,ou=users,$BASEDN
+olcSubordinate: TRUE
+olcDbURI: $URI1
+olcDbIDAssertBind: bindmethod=simple
+ binddn="$RMTROOTDN"
+ credentials=$PASSWD
+ mode=none
+olcDbIDAssertAuthzFrom: dn.exact:$MANAGERDN
+olcRootDN: $MANAGERDN
+
+dn: olcOverlay={0}rwm,olcDatabase={1}ldap,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcRwmConfig
+olcOverlay: {0}rwm
+olcRwmRewrite: rwm-suffixmassage "ou=users,$RMTSUFFIX"
+EOF
+
+echo "Initializing provider1 configurations..."
+cat $CONFLDIF - <<EOF | $SLAPADD -F $PR1CONF -n 0
+
+dn: olcDatabase={2}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {2}$BACKEND
+${nullExclude}olcDbDirectory: $PR1DIR/db
+olcSuffix: $BASEDN
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+
+dn: olcOverlay={0}syncprov,olcDatabase={2}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: {0}syncprov
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Initializing provider2 configurations..."
+cat $CONFLDIF - <<EOF | $SLAPADD -F $PR2CONF -n 0
+
+dn: olcDatabase={2}$BACKEND,cn=config
+objectClass: olcDatabaseConfig
+${nullExclude}objectClass: olc${BACKEND}Config
+olcDatabase: {2}$BACKEND
+${nullExclude}olcDbDirectory: $PR2DIR/db
+olcSuffix: $BASEDN
+olcRootDN: $MANAGERDN
+olcRootPW: $PASSWD
+
+dn: olcOverlay={0}glue,olcDatabase={2}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcConfig
+olcOverlay: {0}glue
+
+dn: olcOverlay={1}syncprov,olcDatabase={2}$BACKEND,cn=config
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: {1}syncprov
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting remote slapd on TCP/IP port $PORT1..."
+cd $RMTDIR
+$SLAPD -F slapd.d -h $URI1 -d $LVL > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that remote slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI1 \
+ '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 "Starting provider1 slapd on TCP/IP port $PORT2..."
+cd $PR1DIR
+$SLAPD -F slapd.d -h $URI2 -d $LVL > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that provider1 slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI2 \
+ '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 "Starting provider2 slapd on TCP/IP port $PORT3..."
+cd $PR2DIR
+$SLAPD -F slapd.d -h $URI3 -d $LVL > $LOG3 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+KILLPIDS="$KILLPIDS $PID"
+cd $TESTWD
+sleep 1
+echo "Using ldapsearch to check that provider2 slapd is running..."
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "" -H $URI3 \
+ '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 "Populating remote database entries..."
+$LDAPADD -D "$RMTROOTDN" -H $URI1 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: $RMTSUFFIX
+objectClass: dcObject
+objectClass: organization
+dc: `echo $RMTSUFFIX | sed 's/^dc=\([^,]*\),.*/\1/'`
+o: Example, Inc
+
+dn: ou=users,$RMTSUFFIX
+objectClass: organizationalUnit
+ou: users
+EOF
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed to populate remote database entries ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+cat <<EOF > $ENTRIES
+dn: $BASEDN
+objectClass: dcObject
+objectClass: organization
+dc: example
+o: Example, Inc
+
+dn: ou=users,$BASEDN
+objectClass: organizationalUnit
+ou: users
+
+dn: ou=local,ou=users,$BASEDN
+objectClass: organizationalUnit
+ou: local
+EOF
+
+echo "Populating provider1 database entries..."
+$LDAPADD -D "$MANAGERDN" -H $URI2 -w $PASSWD < $ENTRIES >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed to populate provider1 database entries ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Populating provider2 database entries..."
+$LDAPADD -D "$MANAGERDN" -H $URI3 -w $PASSWD < $ENTRIES >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed to populate provider2 database entries ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Starting refreshAndPersist search on provider1..."
+$LDAPRSEARCH -D $MANAGERDN -H $URI2 -w $PASSWD -MM -E sync=rp -b $BASEDN '*' + 2>&1 > $SYNC1OUT &
+PID=$!
+RC=32
+for i in 0 1 2 3 4 5; do
+ echo "Waiting for refreshDone message..."
+ sleep $SLEEP0
+ if grep '^# refresh done, switching to persist stage' $SYNC1OUT; then
+ awk '/^result:/{print; exit $2}' $SYNC1OUT
+ RC=$?
+ break
+ fi
+done
+if test $RC != 0 ; then
+ echo "refresh failed ($RC)!"
+ kill $PID
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapadd to add local entry on provider1..."
+$LDAPADD -D $MANAGERDN -H $URI2 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: cn=local_user,ou=local,ou=users,$BASEDN
+objectClass: person
+cn: local_user
+sn: local_user
+userPassword: $PASSWD
+description: add local_user
+EOF
+RC=32
+for i in 0 1 2 3 4 5; do
+ echo "Waiting for syncrepl to receive changes..."
+ sleep $SLEEP0
+ if grep -q '^dn: cn=local_user' $SYNC1OUT; then
+ RC=0
+ break
+ fi
+done
+if test $RC != 0 ; then
+ echo "syncrepl failed ($RC)!"
+ kill $PID
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapmodify to modify local entry on provider1..."
+$LDAPMODIFY -D $MANAGERDN -H $URI2 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: cn=local_user,ou=local,ou=users,$BASEDN
+changeType: modify
+replace: description
+description: modify local_user
+EOF
+RC=32
+for i in 0 1 2 3 4 5; do
+ echo "Waiting for syncrepl to receive changes..."
+ sleep $SLEEP0
+ if grep -q '^description: modify local_user' $SYNC1OUT; then
+ RC=0
+ break
+ fi
+done
+if test $RC != 0 ; then
+ echo "syncrepl failed ($RC)!"
+ kill $PID
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapmodrdn to rename local entry on provider1..."
+$LDAPMODRDN -D $MANAGERDN -H $URI2 -w $PASSWD -r <<EOF >> $TESTOUT 2>&1
+cn=local_user,ou=local,ou=users,$BASEDN
+cn=local_user1
+EOF
+RC=32
+for i in 0 1 2 3 4 5; do
+ echo "Waiting for syncrepl to receive changes..."
+ sleep $SLEEP0
+ if grep -q '^dn: cn=local_user1' $SYNC1OUT; then
+ RC=0
+ break
+ fi
+done
+kill $PID
+if test $RC != 0 ; then
+ echo "syncrepl failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Check that remote entries are NOT replicated..."
+if grep 'ou=remote,' $SYNC1OUT; then
+ echo "remote entries were unexpectedly replicated!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Starting refreshAndPersist search on provider2..."
+$LDAPRSEARCH -D $MANAGERDN -H $URI3 -w $PASSWD -MM -E sync=rp -b $BASEDN '*' + 2>&1 > $SYNC2OUT &
+PID=$!
+RC=32
+for i in 0 1 2 3 4 5; do
+ echo "Waiting for refreshDone message..."
+ sleep $SLEEP0
+ if grep '^# refresh done, switching to persist stage' $SYNC2OUT; then
+ awk '/^result:/{print; exit $2}' $SYNC2OUT
+ RC=$?
+ break
+ fi
+done
+if test $RC != 0 ; then
+ echo "refresh failed ($RC)!"
+ kill $PID
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapadd to add local entry on provider2..."
+$LDAPADD -D $MANAGERDN -H $URI3 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: cn=local_user,ou=local,ou=users,$BASEDN
+objectClass: person
+cn: local_user
+sn: local_user
+userPassword: $PASSWD
+description: add local_user
+EOF
+RC=32
+for i in 0 1 2 3 4 5; do
+ echo "Waiting for syncrepl to receive changes..."
+ sleep $SLEEP0
+ if grep -q '^dn: cn=local_user' $SYNC2OUT; then
+ RC=0
+ break
+ fi
+done
+if test $RC != 0 ; then
+ echo "syncrepl failed ($RC)!"
+ kill $PID
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapmodify to modify local entry on provider2..."
+$LDAPMODIFY -D $MANAGERDN -H $URI3 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: cn=local_user,ou=local,ou=users,$BASEDN
+changeType: modify
+replace: description
+description: modify local_user
+EOF
+RC=32
+for i in 0 1 2 3 4 5; do
+ echo "Waiting for syncrepl to receive changes..."
+ sleep $SLEEP0
+ if grep -q '^description: modify local_user' $SYNC2OUT; then
+ RC=0
+ break
+ fi
+done
+if test $RC != 0 ; then
+ echo "syncrepl failed ($RC)!"
+ kill $PID
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapmodrdn to rename local entry on provider2..."
+$LDAPMODRDN -D $MANAGERDN -H $URI3 -w $PASSWD -r <<EOF >> $TESTOUT 2>&1
+cn=local_user,ou=local,ou=users,$BASEDN
+cn=local_user1
+EOF
+RC=32
+for i in 0 1 2 3 4 5; do
+ echo "Waiting for syncrepl to receive changes..."
+ sleep $SLEEP0
+ if grep -q '^dn: cn=local_user1' $SYNC2OUT; then
+ RC=0
+ break
+ fi
+done
+if test $RC != 0 ; then
+ echo "syncrepl failed ($RC)!"
+ kill $PID
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapadd to add remote entry on provider2..."
+$LDAPADD -D $MANAGERDN -H $URI3 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: cn=remote_user,ou=remote,ou=users,$BASEDN
+objectClass: person
+cn: remote_user
+sn: remote_user
+userPassword: $PASSWD
+description: add remote_user
+EOF
+RC=32
+for i in 0 1 2 3 4 5; do
+ echo "Waiting for syncrepl to receive changes..."
+ sleep $SLEEP0
+ if grep -q '^dn: cn=remote_user' $SYNC2OUT; then
+ RC=0
+ break
+ fi
+done
+if test $RC != 0 ; then
+ echo "syncrepl failed ($RC)!"
+ kill $PID
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapmodify to modify remote entry on provider2..."
+$LDAPMODIFY -D $MANAGERDN -H $URI3 -w $PASSWD <<EOF >> $TESTOUT 2>&1
+dn: cn=remote_user,ou=remote,ou=users,$BASEDN
+changeType: modify
+replace: description
+description: modify remote_user
+EOF
+RC=32
+for i in 0 1 2 3 4 5; do
+ echo "Waiting for syncrepl to receive changes..."
+ sleep $SLEEP0
+ if grep -q '^description: modify remote_user' $SYNC2OUT; then
+ RC=0
+ break
+ fi
+done
+if test $RC != 0 ; then
+ echo "syncrepl failed ($RC)!"
+ kill $PID
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Using ldapmodrdn to rename remote entry on provider2..."
+$LDAPMODRDN -D $MANAGERDN -H $URI3 -w $PASSWD -r <<EOF >> $TESTOUT 2>&1
+cn=remote_user,ou=remote,ou=users,$BASEDN
+cn=remote_user1
+EOF
+RC=32
+for i in 0 1 2 3 4 5; do
+ echo "Waiting for syncrepl to receive changes..."
+ sleep $SLEEP0
+ if grep -q '^dn: cn=remote_user1' $SYNC2OUT; then
+ RC=0
+ break
+ fi
+done
+kill $PID
+if test $RC != 0 ; then
+ echo "syncrepl failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+exit 0