diff --git a/CHANGES b/CHANGES
index aa061f769a47e545d4406121f539a4cfb3d3b966..a5e993f0bf89674fe1e46e4757e4bb6d58976981 100644
--- a/CHANGES
+++ b/CHANGES
@@ -7,6 +7,7 @@ OpenLDAP 2.4.24 Engineering
 	Added libldap x500UniqueIdentifier handling (ITS#6741)
 	Added slapadd attribute value checking (ITS#6592)
 	Added slapcat continue mode for problematic DBs (ITS#6482)
+	Added slapd syncrepl suffixmassage support
 	Added slapd-meta paged results control fowarding (ITS#6664)
 	Added slapd-null back-config support (ITS#6624)
 	Added slapd-sql autocommit support (ITS#6612)
diff --git a/doc/man/man5/slapd-config.5 b/doc/man/man5/slapd-config.5
index 5ae1bb8c92716737350123e6b1e5ffc8411811a4..5c159794d58e2ce5f1a7e3116a1e45ccaece90db 100644
--- a/doc/man/man5/slapd-config.5
+++ b/doc/man/man5/slapd-config.5
@@ -1677,6 +1677,7 @@ FALSE, meaning the contextCSN is stored in the context entry.
 .B [tls_reqcert=never|allow|try|demand]
 .B [tls_ciphersuite=<ciphers>]
 .B [tls_crlcheck=none|peer|all]
+.B [suffixmassage=<real DN>]
 .B [logbase=<base DN>]
 .B [logfilter=<filter str>]
 .B [syncdata=default|accesslog|changelog]
@@ -1837,6 +1838,13 @@ fails. Otherwise the syncrepl session continues without TLS. The
 tls_reqcert setting defaults to "demand" and the other TLS settings
 default to the same as the main slapd TLS settings.
 
+The
+.B suffixmassage
+parameter allows the consumer to pull entries from a remote directory
+whose DN suffix differs from the local directory. The portion of the
+remote entries' DNs that matches the \fIsearchbase\fP will be replaced
+with the suffixmassage DN.
+
 Rather than replicating whole entries, the consumer can query logs of
 data modifications. This mode of operation is referred to as \fIdelta
 syncrepl\fP. In addition to the above parameters, the
diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5
index eb8396603418bef5efb331a56c29c7dacc80f03c..6e6800c4b44942ec158e021a7967b9b25668ae01 100644
--- a/doc/man/man5/slapd.conf.5
+++ b/doc/man/man5/slapd.conf.5
@@ -1656,6 +1656,7 @@ the contextCSN is stored in the context entry.
 .B [tls_reqcert=never|allow|try|demand]
 .B [tls_ciphersuite=<ciphers>]
 .B [tls_crlcheck=none|peer|all]
+.B [suffixmassage=<real DN>]
 .B [logbase=<base DN>]
 .B [logfilter=<filter str>]
 .B [syncdata=default|accesslog|changelog]
@@ -1835,6 +1836,13 @@ fails. Otherwise the syncrepl session continues without TLS. The
 tls_reqcert setting defaults to "demand" and the other TLS settings
 default to the same as the main slapd TLS settings.
 
+The
+.B suffixmassage
+parameter allows the consumer to pull entries from a remote directory
+whose DN suffix differs from the local directory. The portion of the
+remote entries' DNs that matches the \fIsearchbase\fP will be replaced
+with the suffixmassage DN.
+
 Rather than replicating whole entries, the consumer can query logs of
 data modifications. This mode of operation is referred to as \fIdelta
 syncrepl\fP. In addition to the above parameters, the
diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c
index aaa99a77a90947ab9415a0e4f9fea2001aeb69c8..ac2c34e8490b022fe9449863bc38236b1d074a60 100644
--- a/servers/slapd/syncrepl.c
+++ b/servers/slapd/syncrepl.c
@@ -31,6 +31,11 @@
 
 #include "ldap_rq.h"
 
+#ifdef ENABLE_REWRITE
+#include "rewrite.h"
+#define SUFFIXM_CTX	"<suffix massage>"
+#endif
+
 struct nonpresent_entry {
 	struct berval *npe_name;
 	struct berval *npe_nname;
@@ -111,6 +116,10 @@ typedef struct syncinfo_s {
 	LDAP			*si_ld;
 	Connection		*si_conn;
 	LDAP_LIST_HEAD(np, nonpresent_entry)	si_nonpresentlist;
+#ifdef ENABLE_REWRITE
+	struct rewrite_info *si_rewrite;
+	struct berval	si_suffixm;
+#endif
 	ldap_pvt_thread_mutex_t	si_mutex;
 } syncinfo_t;
 
@@ -1558,6 +1567,46 @@ deleted:
 	return NULL;
 }
 
+#ifdef ENABLE_REWRITE
+static int
+syncrepl_rewrite_dn(
+	syncinfo_t *si,
+	struct berval *dn,
+	struct berval *sdn )
+{
+	char nul;
+	int rc;
+
+	nul = dn->bv_val[dn->bv_len];
+	dn->bv_val[dn->bv_len] = 0;
+	rc = rewrite( si->si_rewrite, SUFFIXM_CTX, dn->bv_val, &sdn->bv_val );
+	dn->bv_val[dn->bv_len] = nul;
+
+	if ( sdn->bv_val == dn->bv_val )
+		sdn->bv_val = NULL;
+	else if ( rc == REWRITE_REGEXEC_OK && sdn->bv_val )
+		sdn->bv_len = strlen( sdn->bv_val );
+	return rc;
+}
+#define	REWRITE_VAL(si, ad, bv, bv2)	\
+	BER_BVZERO( &bv2 );	\
+	if ( si->si_rewrite && ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName) \
+		syncrepl_rewrite_dn( si, &bv, &bv2); \
+	if ( BER_BVISNULL( &bv2 ))  \
+		ber_dupbv( &bv2, &bv )
+#define REWRITE_DN(si, bv, bv2, dn, ndn) \
+	BER_BVZERO( &bv2 );	\
+	if (si->si_rewrite) \
+		syncrepl_rewrite_dn(si, &bv, &bv2); \
+	rc = dnPrettyNormal( NULL, bv2.bv_val ? &bv2 : &bv, &dn, &ndn, op->o_tmpmemctx ); \
+	ch_free(bv2.bv_val)
+#else
+#define REWRITE_VAL(si, ad, bv, bv2)	ber_dupbv(&bv2, &bv)
+#define REWRITE_DN(si, bv, bv2, dn, ndn) \
+	rc = dnPrettyNormal( NULL, &bv, &dn, &ndn, op->o_tmpmemctx )
+#endif
+
+
 static slap_verbmasks modops[] = {
 	{ BER_BVC("add"), LDAP_REQ_ADD },
 	{ BER_BVC("delete"), LDAP_REQ_DELETE },
@@ -1642,7 +1691,7 @@ syncrepl_accesslog_mods(
 		if ( colon[2] == ' ' ) {
 			bv.bv_val = colon + 3;
 			bv.bv_len = vals[i].bv_len - ( bv.bv_val - vals[i].bv_val );
-			ber_dupbv( &bv2, &bv );
+			REWRITE_VAL( si, ad, bv, bv2 );
 			ber_bvarray_add( &mod->sml_values, &bv2 );
 			mod->sml_numvals++;
 		}
@@ -1679,7 +1728,7 @@ syncrepl_message_to_op(
 	size_t textlen = sizeof txtbuf;
 
 	struct berval	bdn, dn = BER_BVNULL, ndn;
-	struct berval	bv, *bvals = NULL;
+	struct berval	bv, bv2, *bvals = NULL;
 	struct berval	rdn = BER_BVNULL, sup = BER_BVNULL,
 		prdn = BER_BVNULL, nrdn = BER_BVNULL,
 		psup = BER_BVNULL, nsup = BER_BVNULL;
@@ -1710,7 +1759,7 @@ syncrepl_message_to_op(
 	op->o_tag = LBER_DEFAULT;
 	op->o_bd = si->si_wbe;
 
-	if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) {
+	if ( BER_BVISEMPTY( &bdn )) {
 		Debug( LDAP_DEBUG_ANY,
 			"syncrepl_message_to_op: %s got empty dn",
 			si->si_ridtxt, 0, 0 );
@@ -1724,7 +1773,7 @@ syncrepl_message_to_op(
 
 		if ( !ber_bvstrcasecmp( &bv, &ls->ls_dn ) ) {
 			bdn = bvals[0];
-			rc = dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
+			REWRITE_DN( si, bdn, bv2, dn, ndn );
 			if ( rc != LDAP_SUCCESS ) {
 				Debug( LDAP_DEBUG_ANY,
 					"syncrepl_message_to_op: %s "
@@ -1841,9 +1890,9 @@ syncrepl_message_to_op(
 			goto done;
 		}
 		if ( !BER_BVISNULL( &sup ) ) {
-			if ( dnPrettyNormal( NULL, &sup, &psup, &nsup, NULL ) ) {
+			REWRITE_DN( si, sup, bv2, psup, nsup );
+			if ( rc )
 				goto done;
-			}
 			op->orr_newSup = &psup;
 			op->orr_nnewSup = &nsup;
 		} else {
@@ -1933,7 +1982,7 @@ syncrepl_message_to_entry(
 	char txtbuf[SLAP_TEXT_BUFLEN];
 	size_t textlen = sizeof txtbuf;
 
-	struct berval	bdn = BER_BVNULL, dn, ndn;
+	struct berval	bdn = BER_BVNULL, dn, ndn, bv2;
 	int		rc, is_ctx;
 
 	*modlist = NULL;
@@ -1973,7 +2022,7 @@ syncrepl_message_to_entry(
 		return -1;
 	}
 
-	rc = dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
+	REWRITE_DN( si, bdn, bv2, dn, ndn );
 	if ( rc != LDAP_SUCCESS ) {
 		/* One of the things that could happen is that the schema
 		 * is not lined-up; this could result in unknown attributes.
@@ -2026,6 +2075,26 @@ syncrepl_message_to_entry(
 		mod->sml_nvalues = NULL;
 		mod->sml_numvals = 0;	/* slap_mods_check will set this */
 
+#ifdef ENABLE_REWRITE
+		if (si->si_rewrite) {
+			AttributeDescription *ad = NULL;
+			slap_bv2ad( &tmp.sml_type, &ad, &text );
+			if ( ad ) {
+				mod->sml_desc = ad;
+				mod->sml_type = ad->ad_cname;
+				if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) {
+					int i;
+					for ( i = 0; tmp.sml_values[i].bv_val; i++ ) {
+						syncrepl_rewrite_dn( si, &tmp.sml_values[i], &bv2);
+						if ( !BER_BVISNULL( &bv2 )) {
+							ber_memfree( tmp.sml_values[i].bv_val );
+							tmp.sml_values[i] = bv2;
+						}
+					}
+				}
+			}
+		}
+#endif
 		*modtail = mod;
 		modtail = &mod->sml_next;
 	}
@@ -2240,8 +2309,16 @@ syncrepl_entry(
 	op->ors_deref = LDAP_DEREF_NEVER;
 
 	/* get the entry for this UUID */
-	op->o_req_dn = si->si_base;
-	op->o_req_ndn = si->si_base;
+#ifdef ENABLE_REWRITE
+	if ( si->si_rewrite ) {
+		op->o_req_dn = si->si_suffixm;
+		op->o_req_ndn = si->si_suffixm;
+	} else
+#endif
+	{
+		op->o_req_dn = si->si_base;
+		op->o_req_ndn = si->si_base;
+	}
 
 	op->o_time = slap_get_time();
 	op->ors_tlimit = SLAP_NO_LIMIT;
@@ -2717,8 +2794,16 @@ syncrepl_del_nonpresent(
 	struct berval pdn = BER_BVNULL;
 	struct berval csn;
 
-	op->o_req_dn = si->si_base;
-	op->o_req_ndn = si->si_base;
+#ifdef ENABLE_REWRITE
+	if ( si->si_rewrite ) {
+		op->o_req_dn = si->si_suffixm;
+		op->o_req_ndn = si->si_suffixm;
+	} else
+#endif
+	{
+		op->o_req_dn = si->si_base;
+		op->o_req_ndn = si->si_base;
+	}
 
 	cb.sc_response = nonpresent_callback;
 	cb.sc_private = si;
@@ -3924,12 +4009,54 @@ syncinfo_free( syncinfo_t *sie, int free_all )
 				ch_free( sie->si_cookieState );
 			}
 		}
+#ifdef ENABLE_REWRITE
+		if ( sie->si_rewrite )
+			rewrite_info_delete( &sie->si_rewrite );
+		if ( sie->si_suffixm.bv_val )
+			ch_free( sie->si_suffixm.bv_val );
+#endif
 		ch_free( sie );
 		sie = si_next;
 	} while ( free_all && si_next );
 }
 
+#ifdef ENABLE_REWRITE
+static int
+config_suffixm( ConfigArgs *c, syncinfo_t *si )
+{
+	char *argvEngine[] = { "rewriteEngine", "on", NULL };
+	char *argvContext[] = { "rewriteContext", SUFFIXM_CTX, NULL };
+	char *argvRule[] = { "rewriteRule", NULL, NULL, ":", NULL };
+	char *vnc, *rnc;
+	int rc;
 
+	if ( si->si_rewrite )
+		rewrite_info_delete( &si->si_rewrite );
+	si->si_rewrite = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
+
+	rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvEngine );
+	if ( rc != LDAP_SUCCESS )
+		return rc;
+
+	rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvContext );
+	if ( rc != LDAP_SUCCESS )
+		return rc;
+
+	vnc = ch_malloc( si->si_base.bv_len + 6 );
+	strcpy( vnc, "(.*)" );
+	lutil_strcopy( lutil_strcopy( vnc+4, si->si_base.bv_val ), "$" );
+	argvRule[1] = vnc;
+
+	rnc = ch_malloc( si->si_suffixm.bv_len + 3 );
+	strcpy( rnc, "%1" );
+	strcpy( rnc+2, si->si_suffixm.bv_val );
+	argvRule[2] = rnc;
+
+	rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 4, argvRule );
+	ch_free( vnc );
+	return rc;
+}
+#endif
 
 /* NOTE: used & documented in slapd.conf(5) */
 #define IDSTR			"rid"
@@ -3948,6 +4075,7 @@ syncinfo_free( syncinfo_t *sie, int free_all )
 #define SYNCDATASTR		"syncdata"
 #define LOGBASESTR		"logbase"
 #define LOGFILTERSTR	"logfilter"
+#define SUFFIXMSTR		"suffixmassage"
 
 /* FIXME: undocumented */
 #define EXATTRSSTR		"exattrs"
@@ -3974,6 +4102,7 @@ enum {
 	GOT_EXATTRS		= 0x00010000U,
 	GOT_MANAGEDSAIT		= 0x00020000U,
 	GOT_BINDCONF		= 0x00040000U,
+	GOT_SUFFIXM		= 0x00080000U,
 
 /* check */
 	GOT_REQUIRED		= (GOT_RID|GOT_PROVIDER|GOT_SEARCHBASE)
@@ -4171,16 +4300,38 @@ parse_syncrepl_line(
 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
 				return -1;
 			}
-			if ( !be_issubordinate( c->be, &si->si_base ) ) {
-				ch_free( si->si_base.bv_val );
-				BER_BVZERO( &si->si_base );
+			si->si_got |= GOT_SEARCHBASE;
+#ifdef ENABLE_REWRITE
+		} else if ( !strncasecmp( c->argv[ i ], SUFFIXMSTR "=",
+					STRLENOF( SUFFIXMSTR "=" ) ) )
+		{
+			struct berval	bv;
+			int		rc;
+
+			val = c->argv[ i ] + STRLENOF( SUFFIXMSTR "=" );
+			if ( si->si_suffixm.bv_val ) {
+				ch_free( si->si_suffixm.bv_val );
+			}
+			ber_str2bv( val, 0, 0, &bv );
+			rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_suffixm, NULL );
+			if ( rc != LDAP_SUCCESS ) {
 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
-					"Base DN \"%s\" is not within the database naming context",
+					"Invalid massage DN \"%s\": %d (%s)",
+					val, rc, ldap_err2string( rc ) );
+				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
+				return -1;
+			}
+			if ( !be_issubordinate( c->be, &si->si_suffixm )) {
+				ch_free( si->si_suffixm.bv_val );
+				BER_BVZERO( &si->si_suffixm );
+				snprintf( c->cr_msg, sizeof( c->cr_msg ),
+					"Massage DN \"%s\" is not within the database naming context",
 					val );
 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
 				return -1;
 			}
-			si->si_got |= GOT_SEARCHBASE;
+			si->si_got |= GOT_SUFFIXM;
+#endif
 		} else if ( !strncasecmp( c->argv[ i ], LOGBASESTR "=",
 					STRLENOF( LOGBASESTR "=" ) ) )
 		{
@@ -4443,6 +4594,29 @@ parse_syncrepl_line(
 		return -1;
 	}
 
+	if ( !be_issubordinate( c->be, &si->si_base ) && !( si->si_got & GOT_SUFFIXM )) {
+		ch_free( si->si_base.bv_val );
+		BER_BVZERO( &si->si_base );
+		snprintf( c->cr_msg, sizeof( c->cr_msg ),
+			"Base DN \"%s\" is not within the database naming context",
+			val );
+		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
+		return -1;
+	}
+
+#ifdef ENABLE_REWRITE
+	if ( si->si_got & GOT_SUFFIXM ) {
+		if (config_suffixm( c, si )) {
+			ch_free( si->si_suffixm.bv_val );
+			BER_BVZERO( &si->si_suffixm );
+			snprintf( c->cr_msg, sizeof( c->cr_msg ),
+				"Error configuring rewrite engine" );
+			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
+			return -1;
+		}
+	}
+#endif
+
 	if ( !( si->si_got & GOT_RETRY ) ) {
 		Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": no retry defined, using default\n", 
 			si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", 0 );
@@ -4669,6 +4843,14 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
 		ptr = lutil_strcopy( ptr, si->si_base.bv_val );
 		*ptr++ = '"';
 	}
+#ifdef ENABLE_REWRITE
+	if ( !BER_BVISNULL( &si->si_suffixm ) ) {
+		if ( WHATSLEFT <= STRLENOF( " " SUFFIXMSTR "=\"" "\"" ) + si->si_suffixm.bv_len ) return;
+		ptr = lutil_strcopy( ptr, " " SUFFIXMSTR "=\"" );
+		ptr = lutil_strcopy( ptr, si->si_suffixm.bv_val );
+		*ptr++ = '"';
+	}
+#endif
 	if ( !BER_BVISEMPTY( &si->si_logfilterstr ) ) {
 		if ( WHATSLEFT <= STRLENOF( " " LOGFILTERSTR "=\"" "\"" ) + si->si_logfilterstr.bv_len ) return;
 		ptr = lutil_strcopy( ptr, " " LOGFILTERSTR "=\"" );
diff --git a/tests/scripts/test059-slave-config b/tests/scripts/test059-slave-config
new file mode 100755
index 0000000000000000000000000000000000000000..bc2a9c77c3ba5ca2228f71aeffc6241dbd14abe6
--- /dev/null
+++ b/tests/scripts/test059-slave-config
@@ -0,0 +1,432 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2011 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 slave 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 $MONITORDB < $DYNAMICCONF > $CONFLDIF
+$SLAPADD -F $CFPRO -n 0 -l $CONFLDIF
+$SLAPD -F $CFPRO -h $URI1 -d $LVL $TIMING > $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
+
+# Slaves will not replicate the master's actual cn=config.
+# Instead, they will use an alternate DB so that they may be
+# configured differently from the master. This alternate DB
+# will also be a consumer for the real cn=schema,cn=config tree.
+# It has MirrorMode enabled so that it can be written directly
+# while being a slave of the main schema.
+echo "Configuring slave 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=slave
+olcRootDN: cn=config,cn=slave
+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=slave
+changetype: add
+objectClass: olcGlobal
+cn: slaveconfig
+
+dn: cn=schema,cn=config,cn=slave
+changetype: add
+objectClass: olcSchemaConfig
+cn: schema
+
+dn: olcDatabase={0}config,cn=config,cn=slave
+changetype: add
+objectClass: olcDatabaseConfig
+olcDatabase: {0}config
+olcRootPW: topsecret
+olcSyncrepl: {0}rid=001 provider=$URI1 binddn="cn=config,cn=slave"
+  bindmethod=simple credentials=repsecret searchbase="cn=config,cn=slave"
+  $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=slave"
+-
+add: olcMirrorMode
+olcMirrorMode: TRUE
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+	echo "ldapmodify failed for slave 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
+$SLAPD -F $CFCON -h $URI2 -d $LVL $TIMING > $LOG2 2>&1 &
+SLAVEPID=$!
+if test $WAIT != 0 ; then
+    echo SLAVEPID $SLAVEPID
+    read foo
+fi
+KILLPIDS="$KILLPIDS $SLAVEPID"
+
+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=slave"
+  bindmethod=simple credentials=repsecret searchbase="cn=config,cn=slave"
+  $SYNCTYPE retry="3 5 300 5" timeout=3
+  suffixmassage="cn=config"
+-
+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: ../servers/slapd/back-$BACKEND
+olcModuleLoad: back_$BACKEND.la
+
+dn: cn=module,cn=config,cn=slave
+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=slave
+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
+
+case $BACKEND in
+bdb | hdb)
+	$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
+	;;
+esac
+
+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=*' > $MASTEROUT 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=*' > $SLAVEOUT 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 < $MASTEROUT > $MASTERFLT
+echo "Filtering consumer results..."
+$LDIFFILTER < $SLAVEOUT > $SLAVEFLT
+
+echo "Comparing retrieved entries from provider and consumer..."
+$CMP $MASTERFLT $SLAVEFLT > $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