]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/syncrepl.c
fix previous commit (ITS#5819)
[openldap] / servers / slapd / syncrepl.c
index e5f732f446a2e58ae47d5819b2ffa5074b67ca60..a9f9cf66cc8ca86ff031b14efca36a15e7e59fd5 100644 (file)
@@ -96,6 +96,7 @@ typedef struct syncinfo_s {
        int                     si_refreshDone;
        int                     si_syncdata;
        int                     si_logstate;
+       ber_int_t       si_msgid;
        Avlnode                 *si_presentlist;
        LDAP                    *si_ld;
        Connection              *si_conn;
@@ -105,7 +106,7 @@ typedef struct syncinfo_s {
 
 static int syncuuid_cmp( const void *, const void * );
 static int avl_presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
-static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct berval * );
+static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
 static int syncrepl_message_to_op(
                                        syncinfo_t *, Operation *, LDAPMessage * );
 static int syncrepl_message_to_entry(
@@ -342,7 +343,6 @@ ldap_sync_search(
        BerElementBuffer berbuf;
        BerElement *ber = (BerElement *)&berbuf;
        LDAPControl c[2], *ctrls[3];
-       ber_int_t       msgid;
        int rc;
        int rhint;
        char *base;
@@ -407,7 +407,7 @@ ldap_sync_search(
                        abs(si->si_type), rhint );
        }
 
-       if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == LBER_ERROR ) {
+       if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
                ber_free_buf( ber );
                return rc;
        }
@@ -427,11 +427,117 @@ ldap_sync_search(
        }
 
        rc = ldap_search_ext( si->si_ld, base, scope, filter, attrs, attrsonly,
-               ctrls, NULL, NULL, si->si_slimit, &msgid );
+               ctrls, NULL, NULL, si->si_slimit, &si->si_msgid );
        ber_free_buf( ber );
        return rc;
 }
 
+static int
+check_syncprov(
+       Operation *op,
+       syncinfo_t *si )
+{
+       AttributeName at[2];
+       Attribute a = {0};
+       Entry e = {0};
+       SlapReply rs = {0};
+       int i, j, changed = 0;
+
+       /* Look for contextCSN from syncprov overlay. If
+        * there's no overlay, this will be a no-op. That means
+        * this is a pure consumer, so local changes will not be
+        * allowed, and all changes will already be reflected in
+        * the cookieState.
+        */
+       a.a_desc = slap_schema.si_ad_contextCSN;
+       e.e_attrs = &a;
+       e.e_name = op->o_bd->be_suffix[0];
+       e.e_nname = op->o_bd->be_nsuffix[0];
+       at[0].an_name = a.a_desc->ad_cname;
+       at[0].an_desc = a.a_desc;
+       BER_BVZERO( &at[1].an_name );
+       rs.sr_entry = &e;
+       rs.sr_flags = REP_ENTRY_MODIFIABLE;
+       rs.sr_attrs = at;
+       op->o_req_dn = e.e_name;
+       op->o_req_ndn = e.e_nname;
+
+       ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
+       i = backend_operational( op, &rs );
+       if ( i == LDAP_SUCCESS && a.a_nvals ) {
+               int num = a.a_numvals;
+               /* check for differences */
+               if ( num != si->si_cookieState->cs_num ) {
+                       changed = 1;
+               } else {
+                       for ( i=0; i<num; i++ ) {
+                               if ( ber_bvcmp( &a.a_nvals[i],
+                                       &si->si_cookieState->cs_vals[i] )) {
+                                       changed = 1;
+                                       break;
+                               }
+                       }
+               }
+               if ( changed ) {
+                       ber_bvarray_free( si->si_cookieState->cs_vals );
+                       ch_free( si->si_cookieState->cs_sids );
+                       si->si_cookieState->cs_num = num;
+                       si->si_cookieState->cs_vals = a.a_nvals;
+                       si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_nvals,
+                               num, NULL );
+                       si->si_cookieState->cs_age++;
+               } else {
+                       ber_bvarray_free( a.a_nvals );
+               }
+               ber_bvarray_free( a.a_vals );
+       }
+       /* See if the cookieState has changed due to anything outside
+        * this particular consumer. That includes other consumers in
+        * the same context, or local changes detected above.
+        */
+       if ( si->si_cookieState->cs_num > 0 && si->si_cookieAge !=
+               si->si_cookieState->cs_age ) {
+               if ( !si->si_syncCookie.numcsns ) {
+                       ber_bvarray_free( si->si_syncCookie.ctxcsn );
+                       ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
+                               si->si_cookieState->cs_vals, NULL );
+                       changed = 1;
+               } else {
+                       for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) {
+                               /* bogus, just dup everything */
+                               if ( si->si_syncCookie.sids[i] == -1 ) {
+                                       ber_bvarray_free( si->si_syncCookie.ctxcsn );
+                                       ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
+                                               si->si_cookieState->cs_vals, NULL );
+                                       changed = 1;
+                                       break;
+                               }
+                               for (j=0; j<si->si_cookieState->cs_num; j++) {
+                                       if ( si->si_syncCookie.sids[i] !=
+                                               si->si_cookieState->cs_sids[j] )
+                                               continue;
+                                       if ( bvmatch( &si->si_syncCookie.ctxcsn[i],
+                                               &si->si_cookieState->cs_vals[j] ))
+                                               break;
+                                       ber_bvreplace( &si->si_syncCookie.ctxcsn[i],
+                                               &si->si_cookieState->cs_vals[j] );
+                                       changed = 1;
+                                       break;
+                               }
+                       }
+               }
+       }
+       if ( changed ) {
+               si->si_cookieAge = si->si_cookieState->cs_age;
+               ch_free( si->si_syncCookie.octet_str.bv_val );
+               slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
+                       si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
+                       si->si_syncCookie.sid );
+       }
+       ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+       return changed;
+}
+
 static int
 do_syncrep1(
        Operation *op,
@@ -462,22 +568,32 @@ do_syncrep1(
                op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
        }
 #endif /* HAVE_TLS */
-       ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &op->o_sasl_ssf );
+       {
+               ber_len_t ssf; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought
+                                                 to use sasl_ssf_t but currently uses ber_len_t */
+               ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf );
+               op->o_sasl_ssf = ssf;
+       }
        op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
                ?  op->o_sasl_ssf : op->o_tls_ssf;
 
        ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );
 
+       rc = LDAP_DEREF_NEVER;  /* actually could allow DEREF_FINDING */
+       ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc );
+
+       si->si_syncCookie.rid = si->si_rid;
+
+       /* whenever there are multiple data sources possible, advertise sid */
+       si->si_syncCookie.sid = ( SLAP_MULTIMASTER( si->si_be ) || si->si_be != si->si_wbe ) ?
+               slap_serverID : -1;
+
        /* We've just started up, or the remote server hasn't sent us
         * any meaningful state.
         */
        if ( BER_BVISNULL( &si->si_syncCookie.octet_str ) ) {
                int i;
 
-               si->si_syncCookie.rid = si->si_rid;
-               si->si_syncCookie.sid = SLAP_SINGLE_SHADOW( si->si_be ) ? -1 :
-                       slap_serverID;
-
                LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) {
                        if ( si->si_rid == sc->rid ) {
                                cmdline_cookie_found = 1;
@@ -538,96 +654,8 @@ do_syncrep1(
                        si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
                        si->si_syncCookie.sid );
        } else {
-               AttributeName at[2];
-               Attribute a = {0};
-               Entry e = {0};
-               SlapReply rs = {0};
-               int i, j, changed = 0;
-
-               /* Look for contextCSN from syncprov overlay. If
-                * there's no overlay, this will be a no-op. That means
-                * this is a pure consumer, so local changes will not be
-                * allowed, and all changes will already be reflected in
-                * the cookieState.
-                */
-               a.a_desc = slap_schema.si_ad_contextCSN;
-               e.e_attrs = &a;
-               e.e_name = si->si_wbe->be_suffix[0];
-               e.e_nname = si->si_wbe->be_nsuffix[0];
-               rs.sr_entry = &e;
-               rs.sr_flags = REP_ENTRY_MODIFIABLE;
-               at[0].an_name = a.a_desc->ad_cname;
-               at[0].an_desc = a.a_desc;
-               BER_BVZERO( &at[1].an_name );
-               op->o_req_dn = e.e_name;
-               op->o_req_ndn = e.e_nname;
-
-               ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
-               rc = backend_operational( op, &rs );
-               if ( rc == LDAP_SUCCESS && a.a_vals ) {
-                       int num = a.a_numvals;
-                       /* check for differences */
-                       if ( num != si->si_cookieState->cs_num ) {
-                               changed = 1;
-                       } else {
-                               for ( i=0; i<num; i++ ) {
-                                       if ( ber_bvcmp( &a.a_vals[i],
-                                               &si->si_cookieState->cs_vals[i] )) {
-                                               changed =1;
-                                               break;
-                                       }
-                               }
-                       }
-                       if ( changed ) {
-                               ber_bvarray_free( si->si_cookieState->cs_vals );
-                               ch_free( si->si_cookieState->cs_sids );
-                               si->si_cookieState->cs_num = num;
-                               si->si_cookieState->cs_vals = a.a_vals;
-                               si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_vals,
-                                       num, NULL );
-                               si->si_cookieState->cs_age++;
-                       } else {
-                               ber_bvarray_free( a.a_vals );
-                       }
-                       changed = 0;
-               }
-               /* See if the cookieState has changed due to anything outside
-                * this particular consumer. That includes other consumers in
-                * the same context, or local changes detected above.
-                */
-               if ( si->si_cookieState->cs_num > 1 && si->si_cookieAge !=
-                       si->si_cookieState->cs_age ) {
-
-                       for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) {
-                               /* bogus, just dup everything */
-                               if ( si->si_syncCookie.sids[i] == -1 ) {
-                                       ber_bvarray_free( si->si_syncCookie.ctxcsn );
-                                       ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
-                                               si->si_cookieState->cs_vals, NULL );
-                                       changed = 1;
-                                       break;
-                               }
-                               for (j=0; j<si->si_cookieState->cs_num; j++) {
-                                       if ( si->si_syncCookie.sids[i] !=
-                                               si->si_cookieState->cs_sids[j] )
-                                               continue;
-                                       if ( bvmatch( &si->si_syncCookie.ctxcsn[i],
-                                               &si->si_cookieState->cs_vals[j] ))
-                                               break;
-                                       ber_bvreplace( &si->si_syncCookie.ctxcsn[i],
-                                               &si->si_cookieState->cs_vals[j] );
-                                       changed = 1;
-                                       break;
-                               }
-                       }
-                       if ( changed ) {
-                               ch_free( si->si_syncCookie.octet_str.bv_val );
-                               slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
-                                       si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
-                                       SLAP_SINGLE_SHADOW( si->si_be ) ? -1 : slap_serverID );
-                       }
-               }
-               ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+               /* Look for contextCSN from syncprov overlay. */
+               check_syncprov( op, si );
        }
 
        si->si_refreshDone = 0;
@@ -664,24 +692,31 @@ compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
                return -1;
        }
 
-       for (i=0; !BER_BVISNULL( &sc1->ctxcsn[i] ); i++) {
-               for (j=0; !BER_BVISNULL( &sc2->ctxcsn[j] ); j++) {
+       for (j=0; j<sc2->numcsns; j++) {
+               for (i=0; i<sc1->numcsns; i++) {
                        if ( sc1->sids[i] != sc2->sids[j] )
                                continue;
                        value_match( &match, slap_schema.si_ad_entryCSN,
                                slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
                                SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
-                               &sc1->ctxcsn[i], &sc2->ctxcsn[i], &text );
+                               &sc1->ctxcsn[i], &sc2->ctxcsn[j], &text );
                        if ( match < 0 ) {
                                *which = j;
                                return match;
                        }
                        break;
                }
+               if ( i == sc1->numcsns ) {
+                       /* sc2 has a sid sc1 lacks */
+                       *which = j;
+                       return -1;
+               }
        }
        return match;
 }
 
+#define        SYNC_PAUSED     -3
+
 static int
 do_syncrep2(
        Operation *op,
@@ -693,7 +728,6 @@ do_syncrep2(
        BerElementBuffer berbuf;
        BerElement      *ber = (BerElement *)&berbuf;
 
-       LDAPMessage     *res = NULL;
        LDAPMessage     *msg = NULL;
 
        char            *retoid = NULL;
@@ -743,146 +777,286 @@ do_syncrep2(
                tout_p = NULL;
        }
 
-       while ( ( rc = ldap_result( si->si_ld, LDAP_RES_ANY, LDAP_MSG_ONE,
-               tout_p, &res ) ) > 0 )
+       while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
+               tout_p, &msg ) ) > 0 )
        {
                if ( slapd_shutdown ) {
                        rc = -2;
                        goto done;
                }
-               for( msg = ldap_first_message( si->si_ld, res );
-                       msg != NULL;
-                       msg = ldap_next_message( si->si_ld, msg ) )
-               {
-                       if ( slapd_shutdown ) {
-                               rc = -2;
-                               goto done;
-                       }
-                       switch( ldap_msgtype( msg ) ) {
-                       case LDAP_RES_SEARCH_ENTRY:
-                               ldap_get_entry_controls( si->si_ld, msg, &rctrls );
-                               /* we can't work without the control */
-                               rctrlp = NULL;
-                               if ( rctrls ) {
-                                       LDAPControl **next;
-                                       /* NOTE: make sure we use the right one;
-                                        * a better approach would be to run thru
-                                        * the whole list and take care of all */
-                                       rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_STATE, rctrls, &next );
-                                       if ( next && ldap_control_find( LDAP_CONTROL_SYNC_STATE, next, NULL ) )
-                                       {
-                                               Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
-                                                       "got search entry with multiple "
-                                                       "Sync State control\n", si->si_ridtxt, 0, 0 );
-                                               rc = -1;
-                                               goto done;
-                                       }
-                               }
-                               if ( rctrlp == NULL ) {
+               switch( ldap_msgtype( msg ) ) {
+               case LDAP_RES_SEARCH_ENTRY:
+                       ldap_get_entry_controls( si->si_ld, msg, &rctrls );
+                       /* we can't work without the control */
+                       rctrlp = NULL;
+                       if ( rctrls ) {
+                               LDAPControl **next;
+                               /* NOTE: make sure we use the right one;
+                                * a better approach would be to run thru
+                                * the whole list and take care of all */
+                               rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_STATE, rctrls, &next );
+                               if ( next && ldap_control_find( LDAP_CONTROL_SYNC_STATE, next, NULL ) )
+                               {
                                        Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
-                                               "got search entry without "
+                                               "got search entry with multiple "
                                                "Sync State control\n", si->si_ridtxt, 0, 0 );
                                        rc = -1;
                                        goto done;
                                }
-                               ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
-                               ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID );
-                               /* FIXME: what if syncUUID is NULL or empty?
-                                * (happens with back-sql...) */
-                               if ( BER_BVISEMPTY( &syncUUID ) ) {
-                                       Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
-                                               "got empty syncUUID with LDAP_SYNC_%s\n",
-                                               si->si_ridtxt,
-                                               syncrepl_state2str( syncstate ), 0 );
-                                       ldap_controls_free( rctrls );
-                                       rc = -1;
-                                       goto done;
+                       }
+                       if ( rctrlp == NULL ) {
+                               Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
+                                       "got search entry without "
+                                       "Sync State control\n", si->si_ridtxt, 0, 0 );
+                               rc = -1;
+                               goto done;
+                       }
+                       ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
+                       ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID );
+                       /* FIXME: what if syncUUID is NULL or empty?
+                        * (happens with back-sql...) */
+                       if ( BER_BVISEMPTY( &syncUUID ) ) {
+                               Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
+                                       "got empty syncUUID with LDAP_SYNC_%s\n",
+                                       si->si_ridtxt,
+                                       syncrepl_state2str( syncstate ), 0 );
+                               ldap_controls_free( rctrls );
+                               rc = -1;
+                               goto done;
+                       }
+                       if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
+                               ber_scanf( ber, /*"{"*/ "m}", &cookie );
+
+                               Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
+                                       BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+
+                               if ( !BER_BVISNULL( &cookie ) ) {
+                                       ch_free( syncCookie.octet_str.bv_val );
+                                       ber_dupbv( &syncCookie.octet_str, &cookie );
+                               }
+                               if ( !BER_BVISNULL( &syncCookie.octet_str ) )
+                               {
+                                       slap_parse_sync_cookie( &syncCookie, NULL );
+                                       if ( syncCookie.ctxcsn ) {
+                                               int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
+                                               for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
+                                                       if ( si->si_cookieState->cs_sids[i] == sid && 
+                                                               ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
+                                                               Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s\n",
+                                                                       si->si_ridtxt, syncCookie.ctxcsn->bv_val, 0 );
+                                                               ldap_controls_free( rctrls );
+                                                               rc = 0;
+                                                               goto done;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       rc = 0;
+                       if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
+                               modlist = NULL;
+                               if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
+                                       syncCookie.ctxcsn )
+                               {
+                                       rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
+                               } else switch ( rc ) {
+                                       case LDAP_ALREADY_EXISTS:
+                                       case LDAP_NO_SUCH_OBJECT:
+                                       case LDAP_NO_SUCH_ATTRIBUTE:
+                                       case LDAP_TYPE_OR_VALUE_EXISTS:
+                                               rc = LDAP_SYNC_REFRESH_REQUIRED;
+                                               si->si_logstate = SYNCLOG_FALLBACK;
+                                               ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       } else if ( ( rc = syncrepl_message_to_entry( si, op, msg,
+                               &modlist, &entry, syncstate ) ) == LDAP_SUCCESS )
+                       {
+                               if ( ( rc = syncrepl_entry( si, op, entry, &modlist,
+                                       syncstate, &syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
+                                       syncCookie.ctxcsn )
+                               {
+                                       rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
                                }
+                       }
+                       ldap_controls_free( rctrls );
+                       if ( modlist ) {
+                               slap_mods_free( modlist, 1 );
+                       }
+                       if ( rc )
+                               goto done;
+                       break;
+
+               case LDAP_RES_SEARCH_REFERENCE:
+                       Debug( LDAP_DEBUG_ANY,
+                               "do_syncrep2: %s reference received error\n",
+                               si->si_ridtxt, 0, 0 );
+                       break;
+
+               case LDAP_RES_SEARCH_RESULT:
+                       Debug( LDAP_DEBUG_SYNC,
+                               "do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
+                               si->si_ridtxt, 0, 0 );
+                       ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
+                               &rctrls, 0 );
+#ifdef LDAP_X_SYNC_REFRESH_REQUIRED
+                       if ( err == LDAP_X_SYNC_REFRESH_REQUIRED ) {
+                               /* map old result code to registered code */
+                               err = LDAP_SYNC_REFRESH_REQUIRED;
+                       }
+#endif
+                       if ( err == LDAP_SYNC_REFRESH_REQUIRED ) {
+                               if ( si->si_logstate == SYNCLOG_LOGGING ) {
+                                       si->si_logstate = SYNCLOG_FALLBACK;
+                               }
+                               rc = err;
+                               goto done;
+                       }
+                       if ( err ) {
+                               Debug( LDAP_DEBUG_ANY,
+                                       "do_syncrep2: %s LDAP_RES_SEARCH_RESULT (%d) %s\n",
+                                       si->si_ridtxt, err, ldap_err2string( err ) );
+                       }
+                       if ( rctrls ) {
+                               rctrlp = *rctrls;
+                               ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
+
+                               ber_scanf( ber, "{" /*"}"*/);
                                if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
-                                       ber_scanf( ber, /*"{"*/ "m}", &cookie );
+                                       ber_scanf( ber, "m", &cookie );
 
                                        Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
                                                BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
 
                                        if ( !BER_BVISNULL( &cookie ) ) {
                                                ch_free( syncCookie.octet_str.bv_val );
-                                               ber_dupbv( &syncCookie.octet_str, &cookie );
+                                               ber_dupbv( &syncCookie.octet_str, &cookie);
                                        }
                                        if ( !BER_BVISNULL( &syncCookie.octet_str ) )
                                        {
                                                slap_parse_sync_cookie( &syncCookie, NULL );
-                                               if ( syncCookie.ctxcsn ) {
-                                                       int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
-                                                       for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
-                                                               if ( si->si_cookieState->cs_sids[i] == sid && 
-                                                                       ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
-                                                                       Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s\n",
-                                                                               si->si_ridtxt, syncCookie.ctxcsn->bv_val, 0 );
-                                                                       ldap_controls_free( rctrls );
-                                                                       rc = 0;
-                                                                       goto done;
-                                                               }
-                                                       }
-                                               }
                                        }
                                }
-                               rc = 0;
-                               if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
-                                       modlist = NULL;
-                                       if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
-                                               syncCookie.ctxcsn )
-                                       {
-                                               rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
-                                       }
-                               } else if ( ( rc = syncrepl_message_to_entry( si, op, msg,
-                                       &modlist, &entry, syncstate ) ) == LDAP_SUCCESS )
+                               if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
                                {
-                                       if ( ( rc = syncrepl_entry( si, op, entry, &modlist,
-                                               syncstate, &syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
-                                               syncCookie.ctxcsn )
-                                       {
-                                               rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
-                                       }
+                                       ber_scanf( ber, "b", &refreshDeletes );
                                }
+                               ber_scanf( ber, /*"{"*/ "}" );
+                       }
+                       if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
+                               slap_sync_cookie_free( &syncCookie_req, 0 );
+                               slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
+                       }
+                       if ( !syncCookie.ctxcsn ) {
+                               match = 1;
+                       } else if ( !syncCookie_req.ctxcsn ) {
+                               match = -1;
+                               m = 0;
+                       } else {
+                               match = compare_csns( &syncCookie_req, &syncCookie, &m );
+                       }
+                       if ( rctrls ) {
                                ldap_controls_free( rctrls );
-                               if ( modlist ) {
-                                       slap_mods_free( modlist, 1 );
+                       }
+                       if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
+                               /* FIXME : different error behaviors according to
+                                *      1) err code : LDAP_BUSY ...
+                                *      2) on err policy : stop service, stop sync, retry
+                                */
+                               if ( refreshDeletes == 0 && match < 0 &&
+                                       err == LDAP_SUCCESS &&
+                                       syncCookie_req.numcsns == syncCookie.numcsns )
+                               {
+                                       syncrepl_del_nonpresent( op, si, NULL,
+                                               &syncCookie, m );
+                               } else {
+                                       avl_free( si->si_presentlist, ch_free );
+                                       si->si_presentlist = NULL;
                                }
-                               if ( rc )
-                                       goto done;
-                               break;
-
-                       case LDAP_RES_SEARCH_REFERENCE:
-                               Debug( LDAP_DEBUG_ANY,
-                                       "do_syncrep2: %s reference received error\n",
-                                       si->si_ridtxt, 0, 0 );
-                               break;
+                       }
+                       if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
+                       {
+                               rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
+                       }
+                       if ( err == LDAP_SUCCESS
+                               && si->si_logstate == SYNCLOG_FALLBACK ) {
+                               si->si_logstate = SYNCLOG_LOGGING;
+                               rc = LDAP_SYNC_REFRESH_REQUIRED;
+                       } else {
+                               rc = -2;
+                       }
+                       goto done;
+                       break;
 
-                       case LDAP_RES_SEARCH_RESULT:
-                               Debug( LDAP_DEBUG_SYNC,
-                                       "do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
-                                       si->si_ridtxt, 0, 0 );
-                               ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
-                                       &rctrls, 0 );
-#ifdef LDAP_X_SYNC_REFRESH_REQUIRED
-                               if ( err == LDAP_X_SYNC_REFRESH_REQUIRED ) {
-                                       /* map old result code to registered code */
-                                       err = LDAP_SYNC_REFRESH_REQUIRED;
-                               }
-#endif
-                               if ( err == LDAP_SYNC_REFRESH_REQUIRED ) {
-                                       if ( si->si_logstate == SYNCLOG_LOGGING ) {
-                                               si->si_logstate = SYNCLOG_FALLBACK;
+               case LDAP_RES_INTERMEDIATE:
+                       rc = ldap_parse_intermediate( si->si_ld, msg,
+                               &retoid, &retdata, NULL, 0 );
+                       if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
+                               ber_init2( ber, retdata, LBER_USE_DER );
+
+                               switch ( si_tag = ber_peek_tag( ber, &len ) ) {
+                               ber_tag_t tag;
+                               case LDAP_TAG_SYNC_NEW_COOKIE:
+                                       Debug( LDAP_DEBUG_SYNC,
+                                               "do_syncrep2: %s %s - %s\n", 
+                                               si->si_ridtxt,
+                                               "LDAP_RES_INTERMEDIATE", 
+                                               "NEW_COOKIE" );
+                                       ber_scanf( ber, "tm", &tag, &cookie );
+                                       break;
+                               case LDAP_TAG_SYNC_REFRESH_DELETE:
+                               case LDAP_TAG_SYNC_REFRESH_PRESENT:
+                                       Debug( LDAP_DEBUG_SYNC,
+                                               "do_syncrep2: %s %s - %s\n", 
+                                               si->si_ridtxt,
+                                               "LDAP_RES_INTERMEDIATE", 
+                                               si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ?
+                                               "REFRESH_PRESENT" : "REFRESH_DELETE" );
+                                       if ( si_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
+                                               si->si_refreshDelete = 1;
+                                       } else {
+                                               si->si_refreshPresent = 1;
                                        }
-                                       rc = err;
-                                       goto done;
-                               }
-                               if ( rctrls ) {
-                                       rctrlp = *rctrls;
-                                       ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
+                                       ber_scanf( ber, "t{" /*"}"*/, &tag );
+                                       if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
+                                       {
+                                               ber_scanf( ber, "m", &cookie );
+
+                                               Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
+                                                       BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
 
-                                       ber_scanf( ber, "{" /*"}"*/);
-                                       if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
+                                               if ( !BER_BVISNULL( &cookie ) ) {
+                                                       ch_free( syncCookie.octet_str.bv_val );
+                                                       ber_dupbv( &syncCookie.octet_str, &cookie );
+                                               }
+                                               if ( !BER_BVISNULL( &syncCookie.octet_str ) )
+                                               {
+                                                       slap_parse_sync_cookie( &syncCookie, NULL );
+                                               }
+                                       }
+                                       /* Defaults to TRUE */
+                                       if ( ber_peek_tag( ber, &len ) ==
+                                               LDAP_TAG_REFRESHDONE )
+                                       {
+                                               ber_scanf( ber, "b", &si->si_refreshDone );
+                                       } else
+                                       {
+                                               si->si_refreshDone = 1;
+                                       }
+                                       ber_scanf( ber, /*"{"*/ "}" );
+                                       break;
+                               case LDAP_TAG_SYNC_ID_SET:
+                                       Debug( LDAP_DEBUG_SYNC,
+                                               "do_syncrep2: %s %s - %s\n", 
+                                               si->si_ridtxt,
+                                               "LDAP_RES_INTERMEDIATE", 
+                                               "SYNC_ID_SET" );
+                                       ber_scanf( ber, "t{" /*"}"*/, &tag );
+                                       if ( ber_peek_tag( ber, &len ) ==
+                                               LDAP_TAG_SYNC_COOKIE )
+                                       {
                                                ber_scanf( ber, "m", &cookie );
 
                                                Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
@@ -890,18 +1064,47 @@ do_syncrep2(
 
                                                if ( !BER_BVISNULL( &cookie ) ) {
                                                        ch_free( syncCookie.octet_str.bv_val );
-                                                       ber_dupbv( &syncCookie.octet_str, &cookie);
+                                                       ber_dupbv( &syncCookie.octet_str, &cookie );
                                                }
                                                if ( !BER_BVISNULL( &syncCookie.octet_str ) )
                                                {
                                                        slap_parse_sync_cookie( &syncCookie, NULL );
+                                                       compare_csns( &syncCookie_req, &syncCookie, &m );
                                                }
                                        }
-                                       if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
+                                       if ( ber_peek_tag( ber, &len ) ==
+                                               LDAP_TAG_REFRESHDELETES )
                                        {
                                                ber_scanf( ber, "b", &refreshDeletes );
                                        }
+                                       ber_scanf( ber, "[W]", &syncUUIDs );
                                        ber_scanf( ber, /*"{"*/ "}" );
+                                       if ( refreshDeletes ) {
+                                               syncrepl_del_nonpresent( op, si, syncUUIDs,
+                                                       &syncCookie, m );
+                                               ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
+                                       } else {
+                                               int i;
+                                               for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
+                                                       (void)avl_presentlist_insert( si, &syncUUIDs[i] );
+                                                       slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx );
+                                               }
+                                               slap_sl_free( syncUUIDs, op->o_tmpmemctx );
+                                       }
+                                       slap_sync_cookie_free( &syncCookie, 0 );
+                                       break;
+                               default:
+                                       Debug( LDAP_DEBUG_ANY,
+                                               "do_syncrep2: %s unknown syncinfo tag (%ld)\n",
+                                               si->si_ridtxt, (long) si_tag, 0 );
+                                       ldap_memfree( retoid );
+                                       ber_bvfree( retdata );
+                                       continue;
+                               }
+
+                               if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
+                                       slap_sync_cookie_free( &syncCookie_req, 0 );
+                                       slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
                                }
                                if ( !syncCookie.ctxcsn ) {
                                        match = 1;
@@ -911,201 +1114,54 @@ do_syncrep2(
                                } else {
                                        match = compare_csns( &syncCookie_req, &syncCookie, &m );
                                }
-                               if ( rctrls ) {
-                                       ldap_controls_free( rctrls );
-                               }
-                               if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
-                                       /* FIXME : different error behaviors according to
-                                        *      1) err code : LDAP_BUSY ...
-                                        *      2) on err policy : stop service, stop sync, retry
-                                        */
-                                       if ( refreshDeletes == 0 && match < 0 &&
-                                               err == LDAP_SUCCESS )
-                                       {
-                                               syncrepl_del_nonpresent( op, si, NULL,
-                                                       &syncCookie.ctxcsn[m] );
-                                       } else {
-                                               avl_free( si->si_presentlist, ch_free );
-                                               si->si_presentlist = NULL;
-                                       }
-                               }
-                               if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
-                               {
-                                       rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
-                               }
-                               if ( err == LDAP_SUCCESS
-                                       && si->si_logstate == SYNCLOG_FALLBACK ) {
-                                       si->si_logstate = SYNCLOG_LOGGING;
-                                       rc = LDAP_SYNC_REFRESH_REQUIRED;
-                               } else {
-                                       rc = -2;
-                               }
-                               goto done;
-                               break;
-
-                       case LDAP_RES_INTERMEDIATE:
-                               rc = ldap_parse_intermediate( si->si_ld, msg,
-                                       &retoid, &retdata, NULL, 0 );
-                               if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
-                                       ber_init2( ber, retdata, LBER_USE_DER );
-
-                                       switch ( si_tag = ber_peek_tag( ber, &len ) ) {
-                                       ber_tag_t tag;
-                                       case LDAP_TAG_SYNC_NEW_COOKIE:
-                                               Debug( LDAP_DEBUG_SYNC,
-                                                       "do_syncrep2: %s %s - %s\n", 
-                                                       si->si_ridtxt,
-                                                       "LDAP_RES_INTERMEDIATE", 
-                                                       "NEW_COOKIE" );
-                                               ber_scanf( ber, "tm", &tag, &cookie );
-                                               break;
-                                       case LDAP_TAG_SYNC_REFRESH_DELETE:
-                                       case LDAP_TAG_SYNC_REFRESH_PRESENT:
-                                               Debug( LDAP_DEBUG_SYNC,
-                                                       "do_syncrep2: %s %s - %s\n", 
-                                                       si->si_ridtxt,
-                                                       "LDAP_RES_INTERMEDIATE", 
-                                                       si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ?
-                                                       "REFRESH_PRESENT" : "REFRESH_DELETE" );
-                                               if ( si_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
-                                                       si->si_refreshDelete = 1;
-                                               } else {
-                                                       si->si_refreshPresent = 1;
-                                               }
-                                               ber_scanf( ber, "t{" /*"}"*/, &tag );
-                                               if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
-                                               {
-                                                       ber_scanf( ber, "m", &cookie );
-
-                                                       Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
-                                                               BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
 
-                                                       if ( !BER_BVISNULL( &cookie ) ) {
-                                                               ch_free( syncCookie.octet_str.bv_val );
-                                                               ber_dupbv( &syncCookie.octet_str, &cookie );
-                                                       }
-                                                       if ( !BER_BVISNULL( &syncCookie.octet_str ) )
-                                                       {
-                                                               slap_parse_sync_cookie( &syncCookie, NULL );
-                                                       }
-                                               }
-                                               /* Defaults to TRUE */
-                                               if ( ber_peek_tag( ber, &len ) ==
-                                                       LDAP_TAG_REFRESHDONE )
-                                               {
-                                                       ber_scanf( ber, "b", &si->si_refreshDone );
-                                               } else
-                                               {
-                                                       si->si_refreshDone = 1;
-                                               }
-                                               ber_scanf( ber, /*"{"*/ "}" );
-                                               break;
-                                       case LDAP_TAG_SYNC_ID_SET:
-                                               Debug( LDAP_DEBUG_SYNC,
-                                                       "do_syncrep2: %s %s - %s\n", 
-                                                       si->si_ridtxt,
-                                                       "LDAP_RES_INTERMEDIATE", 
-                                                       "SYNC_ID_SET" );
-                                               ber_scanf( ber, "t{" /*"}"*/, &tag );
-                                               if ( ber_peek_tag( ber, &len ) ==
-                                                       LDAP_TAG_SYNC_COOKIE )
-                                               {
-                                                       ber_scanf( ber, "m", &cookie );
-
-                                                       Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
-                                                               BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
-
-                                                       if ( !BER_BVISNULL( &cookie ) ) {
-                                                               ch_free( syncCookie.octet_str.bv_val );
-                                                               ber_dupbv( &syncCookie.octet_str, &cookie );
-                                                       }
-                                                       if ( !BER_BVISNULL( &syncCookie.octet_str ) )
-                                                       {
-                                                               slap_parse_sync_cookie( &syncCookie, NULL );
-                                                               compare_csns( &syncCookie_req, &syncCookie, &m );
-                                                       }
-                                               }
-                                               if ( ber_peek_tag( ber, &len ) ==
-                                                       LDAP_TAG_REFRESHDELETES )
-                                               {
-                                                       ber_scanf( ber, "b", &refreshDeletes );
-                                               }
-                                               ber_scanf( ber, "[W]", &syncUUIDs );
-                                               ber_scanf( ber, /*"{"*/ "}" );
-                                               if ( refreshDeletes ) {
-                                                       syncrepl_del_nonpresent( op, si, syncUUIDs,
-                                                               &syncCookie.ctxcsn[m] );
-                                                       ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
-                                               } else {
-                                                       int i;
-                                                       for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
-                                                               (void)avl_presentlist_insert( si, &syncUUIDs[i] );
-                                                               slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx );
-                                                       }
-                                                       slap_sl_free( syncUUIDs, op->o_tmpmemctx );
-                                               }
-                                               slap_sync_cookie_free( &syncCookie, 0 );
-                                               break;
-                                       default:
-                                               Debug( LDAP_DEBUG_ANY,
-                                                       "do_syncrep2: %s unknown syncinfo tag (%ld)\n",
-                                                       si->si_ridtxt, (long) si_tag, 0 );
-                                               ldap_memfree( retoid );
-                                               ber_bvfree( retdata );
-                                               continue;
+                               if ( match < 0 ) {
+                                       if ( si->si_refreshPresent == 1 &&
+                                               syncCookie_req.numcsns == syncCookie.numcsns ) {
+                                               syncrepl_del_nonpresent( op, si, NULL,
+                                                       &syncCookie, m );
                                        }
 
-                                       if ( !syncCookie.ctxcsn ) {
-                                               match = 1;
-                                       } else if ( !syncCookie_req.ctxcsn ) {
-                                               match = -1;
-                                               m = 0;
-                                       } else {
-                                               match = compare_csns( &syncCookie_req, &syncCookie, &m );
+                                       if ( syncCookie.ctxcsn )
+                                       {
+                                               rc = syncrepl_updateCookie( si, op, psub, &syncCookie);
                                        }
+                               } 
 
-                                       if ( match < 0 ) {
-                                               if ( si->si_refreshPresent == 1 ) {
-                                                       syncrepl_del_nonpresent( op, si, NULL,
-                                                               &syncCookie.ctxcsn[m] );
-                                               }
-
-                                               if ( syncCookie.ctxcsn )
-                                               {
-                                                       rc = syncrepl_updateCookie( si, op, psub, &syncCookie);
-                                               }
-                                       } 
-
-                                       ldap_memfree( retoid );
-                                       ber_bvfree( retdata );
-                                       break;
-
-                               } else {
-                                       Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
-                                               "unknown intermediate response (%d)\n",
-                                               si->si_ridtxt, rc, 0 );
-                                       ldap_memfree( retoid );
-                                       ber_bvfree( retdata );
-                                       break;
-                               }
+                               ldap_memfree( retoid );
+                               ber_bvfree( retdata );
                                break;
 
-                       default:
+                       } else {
                                Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
-                                       "unknown message (0x%02lx)\n",
-                                       si->si_ridtxt,
-                                       (unsigned long)ldap_msgtype( msg ), 0 );
+                                       "unknown intermediate response (%d)\n",
+                                       si->si_ridtxt, rc, 0 );
+                               ldap_memfree( retoid );
+                               ber_bvfree( retdata );
                                break;
-
-                       }
-                       if ( !BER_BVISNULL( &syncCookie.octet_str ) ) {
-                               slap_sync_cookie_free( &syncCookie_req, 0 );
-                               slap_dup_sync_cookie( &syncCookie_req, &syncCookie );
-                               slap_sync_cookie_free( &syncCookie, 0 );
                        }
+                       break;
+
+               default:
+                       Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
+                               "unknown message (0x%02lx)\n",
+                               si->si_ridtxt,
+                               (unsigned long)ldap_msgtype( msg ), 0 );
+                       break;
+
+               }
+               if ( !BER_BVISNULL( &syncCookie.octet_str ) ) {
+                       slap_sync_cookie_free( &syncCookie_req, 0 );
+                       slap_dup_sync_cookie( &syncCookie_req, &syncCookie );
+                       slap_sync_cookie_free( &syncCookie, 0 );
+               }
+               ldap_msgfree( msg );
+               msg = NULL;
+               if ( ldap_pvt_thread_pool_pausing( &connection_pool )) {
+                       slap_sync_cookie_free( &syncCookie, 0 );
+                       slap_sync_cookie_free( &syncCookie_req, 0 );
+                       return SYNC_PAUSED;
                }
-               ldap_msgfree( res );
-               res = NULL;
        }
 
        if ( rc == -1 ) {
@@ -1123,7 +1179,7 @@ done:
        slap_sync_cookie_free( &syncCookie, 0 );
        slap_sync_cookie_free( &syncCookie_req, 0 );
 
-       if ( res ) ldap_msgfree( res );
+       if ( msg ) ldap_msgfree( msg );
 
        if ( rc && rc != LDAP_SYNC_REFRESH_REQUIRED && si->si_ld ) {
                if ( si->si_conn ) {
@@ -1158,6 +1214,7 @@ do_syncrepl(
        if ( si == NULL )
                return NULL;
 
+       /* There will never be more than one instance active */
        ldap_pvt_thread_mutex_lock( &si->si_mutex );
 
        switch( abs( si->si_type ) ) {
@@ -1190,25 +1247,45 @@ do_syncrepl(
        op->o_tmpmfuncs = &ch_mfuncs;
 
        op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
-       op->o_bd = be = si->si_be;
-       op->o_dn = op->o_bd->be_rootdn;
-       op->o_ndn = op->o_bd->be_rootndn;
-       if ( !si->si_schemachecking )
-               op->o_no_schema_check = 1;
-
-       /* If we're glued, send writes through the glue parent */
+       be = si->si_be;
+
+       /* Coordinate contextCSN updates with any syncprov overlays
+        * in use. This may be complicated by the use of the glue
+        * overlay.
+        *
+        * Typically there is a single syncprov mastering the entire
+        * glued tree. In that case, our contextCSN updates should
+        * go to the master DB. But if there is no syncprov on the
+        * master DB, then nothing special is needed here.
+        *
+        * Alternatively, there may be individual syncprov overlays
+        * on each glued branch. In that case, each syncprov only
+        * knows about changes within its own branch. And so our
+        * contextCSN updates should only go to the local DB.
+        */
        if ( !si->si_wbe ) {
-               if ( SLAP_GLUE_SUBORDINATE( be )) {
-                       si->si_wbe = select_backend( &be->be_nsuffix[0], 1 );
+               if ( SLAP_GLUE_SUBORDINATE( be ) && !overlay_is_inst( be, "syncprov" )) {
+                       BackendDB * top_be = select_backend( &be->be_nsuffix[0], 1 );
+                       if ( overlay_is_inst( top_be, "syncprov" ))
+                               si->si_wbe = select_backend( &be->be_nsuffix[0], 1 );
+                       else
+                               si->si_wbe = be;
                } else {
                        si->si_wbe = be;
                }
        }
+       if ( !si->si_schemachecking )
+               op->o_no_schema_check = 1;
 
        /* Establish session, do search */
        if ( !si->si_ld ) {
                si->si_refreshDelete = 0;
                si->si_refreshPresent = 0;
+
+               /* use main DB when retrieving contextCSN */
+               op->o_bd = si->si_wbe;
+               op->o_dn = op->o_bd->be_rootdn;
+               op->o_ndn = op->o_bd->be_rootndn;
                rc = do_syncrep1( op, si );
        }
 
@@ -1217,6 +1294,10 @@ reload:
        if ( rc == LDAP_SUCCESS ) {
                ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
 
+               /* use current DB */
+               op->o_bd = be;
+               op->o_dn = op->o_bd->be_rootdn;
+               op->o_ndn = op->o_bd->be_rootndn;
                rc = do_syncrep2( op, si );
                if ( rc == LDAP_SYNC_REFRESH_REQUIRED ) {
                        rc = ldap_sync_search( si, op->o_tmpmemctx );
@@ -1230,29 +1311,32 @@ reload:
                        rc = -1;
                }
 
-               if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
-                       /* If we succeeded, enable the connection for further listening.
-                        * If we failed, tear down the connection and reschedule.
-                        */
-                       if ( rc == LDAP_SUCCESS ) {
-                               if ( si->si_conn ) {
-                                       connection_client_enable( si->si_conn );
-                               } else {
-                                       si->si_conn = connection_client_setup( s, do_syncrepl, arg );
-                               } 
-                       } else if ( si->si_conn ) {
-                               dostop = 1;
+               if ( rc != SYNC_PAUSED ) {
+                       if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
+                               /* If we succeeded, enable the connection for further listening.
+                                * If we failed, tear down the connection and reschedule.
+                                */
+                               if ( rc == LDAP_SUCCESS ) {
+                                       if ( si->si_conn ) {
+                                               connection_client_enable( si->si_conn );
+                                       } else {
+                                               si->si_conn = connection_client_setup( s, do_syncrepl, arg );
+                                       } 
+                               } else if ( si->si_conn ) {
+                                       dostop = 1;
+                               }
+                       } else {
+                               if ( rc == -2 ) rc = 0;
                        }
-               } else {
-                       if ( rc == -2 ) rc = 0;
                }
        }
 
-       /* At this point, we have 4 cases:
+       /* At this point, we have 5 cases:
         * 1) for any hard failure, give up and remove this task
-        * 2) for ServerDown, reschedule this task to run
-        * 3) for Refresh and Success, reschedule to run
-        * 4) for Persist and Success, reschedule to defer
+        * 2) for ServerDown, reschedule this task to run later
+        * 3) for threadpool pause, reschedule to run immediately
+        * 4) for Refresh and Success, reschedule to run
+        * 5) for Persist and Success, reschedule to defer
         */
        ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
 
@@ -1265,7 +1349,12 @@ reload:
                si->si_conn = NULL;
        }
 
-       if ( rc == LDAP_SUCCESS ) {
+       if ( rc == SYNC_PAUSED ) {
+               rtask->interval.tv_sec = 0;
+               ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
+               rtask->interval.tv_sec = si->si_interval;
+               rc = 0;
+       } else if ( rc == LDAP_SUCCESS ) {
                if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
                        defer = 0;
                }
@@ -1843,7 +1932,6 @@ typedef struct dninfo {
        struct berval dn;
        struct berval ndn;
        int renamed;    /* Was an existing entry renamed? */
-       int delOldRDN;  /* Was old RDN deleted? */
        Modifications **modlist;        /* the modlist we received */
        Modifications *mods;    /* the modlist we compared */
 } dninfo;
@@ -2128,7 +2216,8 @@ retry_add:;
                                op->orr_newSup = NULL;
                                op->orr_nnewSup = NULL;
                        }
-                       op->orr_deleteoldrdn = dni.delOldRDN;
+                       /* Let the modify handler take care of deleting old RDNs */
+                       op->orr_deleteoldrdn = 0;
                        op->orr_modlist = NULL;
                        if ( ( rc = slap_modrdn2mods( op, &rs_modify ) ) ) {
                                goto done;
@@ -2140,39 +2229,9 @@ retry_add:;
                        noldp = op->orr_nnewrdn;
                        ber_dupbv_x( &op->orr_nnewrdn, &noldp, op->o_tmpmemctx );
 
-                       /* Setup opattrs too */
-                       {
-                               static AttributeDescription *nullattr = NULL;
-                               static AttributeDescription **const opattrs[] = {
-                                       &slap_schema.si_ad_entryCSN,
-                                       &slap_schema.si_ad_modifiersName,
-                                       &slap_schema.si_ad_modifyTimestamp,
-                                       &nullattr
-                               };
-                               AttributeDescription *opattr;
-                               Modifications *mod, **modtail, **ml;
-                               int i;
-
-                               for ( mod = op->orr_modlist;
-                                       mod->sml_next;
-                                       mod = mod->sml_next )
-                                       ;
-                               modtail = &mod->sml_next;
-
-                               /* pull mod off incoming modlist, append to orr_modlist */
-                               for ( i = 0; (opattr = *opattrs[i]) != NULL; i++ ) {
-                                       for ( ml = modlist; *ml; ml = &(*ml)->sml_next )
-                                       {
-                                               if ( (*ml)->sml_desc == opattr ) {
-                                                       mod = *ml;
-                                                       *ml = mod->sml_next;
-                                                       mod->sml_next = NULL;
-                                                       *modtail = mod;
-                                                       modtail = &mod->sml_next;
-                                                       break;
-                                               }
-                                       }
-                               }
+                       /* Remove the CSN for now, only propagate the Modify */
+                       if ( syncCSN ) {
+                               slap_graduate_commit_csn( op );
                        }
                        op->o_bd = si->si_wbe;
                        rc = op->o_bd->be_modrdn( op, &rs_modify );
@@ -2184,7 +2243,12 @@ retry_add:;
                                        "syncrepl_entry: %s be_modrdn (%d)\n", 
                                        si->si_ridtxt, rc, 0 );
                        op->o_bd = be;
-                       goto done;
+                       /* Renamed entries still have other mods so just fallthru */
+                       op->o_req_dn = entry->e_name;
+                       op->o_req_ndn = entry->e_nname;
+                       if ( syncCSN ) {
+                               slap_queue_csn( op, syncCSN );
+                       }
                }
                if ( dni.mods ) {
                        op->o_tag = LDAP_REQ_MODIFY;
@@ -2283,7 +2347,8 @@ syncrepl_del_nonpresent(
        Operation *op,
        syncinfo_t *si,
        BerVarray uuids,
-       struct berval *cookiecsn )
+       struct sync_cookie *sc,
+       int m )
 {
        Backend* be = op->o_bd;
        slap_callback   cb = { NULL };
@@ -2336,6 +2401,8 @@ syncrepl_del_nonpresent(
                }
                si->si_refreshDelete ^= NP_DELETE_ONE;
        } else {
+               Filter *cf, *of;
+
                memset( &an[0], 0, 2 * sizeof( AttributeName ) );
                an[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
                an[0].an_desc = slap_schema.si_ad_entryUUID;
@@ -2343,21 +2410,56 @@ syncrepl_del_nonpresent(
                op->ors_slimit = SLAP_NO_LIMIT;
                op->ors_attrsonly = 0;
                op->ors_filter = str2filter_x( op, si->si_filterstr.bv_val );
-               op->ors_filterstr = si->si_filterstr;
+               /* In multimaster, updates can continue to arrive while
+                * we're searching. Limit the search result to entries
+                * older than all of our cookie CSNs.
+                */
+               if ( SLAP_MULTIMASTER( op->o_bd )) {
+                       Filter *f;
+                       int i;
+                       cf = op->o_tmpalloc( (sc->numcsns+1) * sizeof(Filter) +
+                               sc->numcsns * sizeof(AttributeAssertion), op->o_tmpmemctx );
+                       f = cf;
+                       f->f_choice = LDAP_FILTER_AND;
+                       f->f_next = NULL;
+                       f->f_and = f+1;
+                       of = f->f_and;
+                       for ( i=0; i<sc->numcsns; i++ ) {
+                               f = of;
+                               f->f_choice = LDAP_FILTER_LE;
+                               f->f_ava = (AttributeAssertion *)(f+1);
+                               f->f_av_desc = slap_schema.si_ad_entryCSN;
+                               f->f_av_value = sc->ctxcsn[i];
+                               f->f_next = (Filter *)(f->f_ava+1);
+                               of = f->f_next;
+                       }
+                       f->f_next = op->ors_filter;
+                       of = op->ors_filter;
+                       op->ors_filter = cf;
+                       filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
+               } else {
+                       cf = NULL;
+                       op->ors_filterstr = si->si_filterstr;
+               }
                op->o_nocaching = 1;
 
                if ( limits_check( op, &rs_search ) == 0 ) {
                        rc = be->be_search( op, &rs_search );
                }
-               if ( op->ors_filter ) filter_free_x( op, op->ors_filter );
+               if ( SLAP_MULTIMASTER( op->o_bd )) {
+                       op->o_tmpfree( cf, op->o_tmpmemctx );
+                       op->ors_filter = of;
+               }
+               if ( op->ors_filter ) filter_free_x( op, op->ors_filter, 1 );
+
        }
 
        op->o_nocaching = 0;
 
        if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
 
-               if ( cookiecsn && !BER_BVISNULL( cookiecsn ) ) {
-                       csn = *cookiecsn;
+               if ( sc->ctxcsn && !BER_BVISNULL( &sc->ctxcsn[m] ) ) {
+                       csn = sc->ctxcsn[m];
                } else {
                        csn = si->si_syncCookie.ctxcsn[0];
                }
@@ -2603,32 +2705,32 @@ syncrepl_updateCookie(
        struct sync_cookie *syncCookie )
 {
        Backend *be = op->o_bd;
-       Modifications mod[2];
+       Modifications mod;
        struct berval first = BER_BVNULL;
 
-       int rc, i, j, len;
+       int rc, i, j;
+       ber_len_t len;
 
        slap_callback cb = { NULL };
        SlapReply       rs_modify = {REP_RESULT};
 
-       mod[0].sml_op = LDAP_MOD_DELETE;
-       mod[0].sml_desc = slap_schema.si_ad_contextCSN;
-       mod[0].sml_type = mod[0].sml_desc->ad_cname;
-       mod[0].sml_values = NULL;
-       mod[0].sml_nvalues = NULL;
-       mod[0].sml_numvals = 0;
-       mod[0].sml_next = &mod[1];
-
-       mod[1].sml_op = LDAP_MOD_ADD;
-       mod[1].sml_desc = slap_schema.si_ad_contextCSN;
-       mod[1].sml_type = mod[0].sml_desc->ad_cname;
-       mod[1].sml_values = NULL;
-       mod[1].sml_nvalues = NULL;
-       mod[1].sml_numvals = 0;
-       mod[1].sml_next = NULL;
+       mod.sml_op = LDAP_MOD_REPLACE;
+       mod.sml_desc = slap_schema.si_ad_contextCSN;
+       mod.sml_type = mod.sml_desc->ad_cname;
+       mod.sml_flags = SLAP_MOD_INTERNAL;
+       mod.sml_nvalues = NULL;
+       mod.sml_next = NULL;
 
        ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
 
+       /* clone the cookieState CSNs so we can Replace the whole thing */
+       mod.sml_numvals = si->si_cookieState->cs_num;
+       mod.sml_values = op->o_tmpalloc(( mod.sml_numvals+1 )*sizeof(struct berval), op->o_tmpmemctx );
+       for ( i=0; i<mod.sml_numvals; i++ )
+               mod.sml_values[i] = si->si_cookieState->cs_vals[i];
+       BER_BVZERO( &mod.sml_values[i] );
+
+       /* find any CSNs in the syncCookie that are newer than the cookieState */
        for ( i=0; i<syncCookie->numcsns; i++ ) {
                for ( j=0; j<si->si_cookieState->cs_num; j++ ) {
                        if ( syncCookie->sids[i] != si->si_cookieState->cs_sids[j] )
@@ -2638,29 +2740,35 @@ syncrepl_updateCookie(
                                len = si->si_cookieState->cs_vals[j].bv_len;
                        if ( memcmp( syncCookie->ctxcsn[i].bv_val,
                                si->si_cookieState->cs_vals[j].bv_val, len ) > 0 ) {
-                               ber_bvarray_add_x( &mod[0].sml_values,
-                                       &si->si_cookieState->cs_vals[j], op->o_tmpmemctx );
-                               mod[0].sml_numvals++;
-                               ber_bvarray_add_x( &mod[1].sml_values,
-                                       &syncCookie->ctxcsn[i], op->o_tmpmemctx );
-                               mod[1].sml_numvals++;
-                               if ( BER_BVISNULL( &first ))
+                               mod.sml_values[j] = syncCookie->ctxcsn[i];
+                               if ( BER_BVISNULL( &first ) ) {
+                                       first = syncCookie->ctxcsn[i];
+
+                               } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
+                               {
                                        first = syncCookie->ctxcsn[i];
+                               }
                        }
                        break;
                }
                /* there was no match for this SID, it's a new CSN */
                if ( j == si->si_cookieState->cs_num ) {
-                       ber_bvarray_add_x( &mod[1].sml_values,
-                               &syncCookie->ctxcsn[i], op->o_tmpmemctx );
-                       mod[1].sml_numvals++;
-                       if ( BER_BVISNULL( &first ))
+                       mod.sml_values = op->o_tmprealloc( mod.sml_values,
+                               ( mod.sml_numvals+2 )*sizeof(struct berval), op->o_tmpmemctx );
+                       mod.sml_values[mod.sml_numvals++] = syncCookie->ctxcsn[i];
+                       BER_BVZERO( &mod.sml_values[mod.sml_numvals] );
+                       if ( BER_BVISNULL( &first ) ) {
                                first = syncCookie->ctxcsn[i];
+                       } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
+                       {
+                               first = syncCookie->ctxcsn[i];
+                       }
                }
        }
        /* Should never happen, ITS#5065 */
        if ( BER_BVISNULL( &first )) {
                ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+               op->o_tmpfree( mod.sml_values, op->o_tmpmemctx );
                return 0;
        }
        op->o_bd = si->si_wbe;
@@ -2676,37 +2784,27 @@ syncrepl_updateCookie(
        op->o_req_ndn = op->o_bd->be_nsuffix[0];
 
        /* update contextCSN */
-       op->o_msgid = SLAP_SYNC_UPDATE_MSGID;
-
-       if ( mod[0].sml_values )
-               op->orm_modlist = mod;
-       else
-               op->orm_modlist = &mod[1];
+       op->o_dont_replicate = 1;
 
+       op->orm_modlist = &mod;
        op->orm_no_opattrs = 1;
        rc = op->o_bd->be_modify( op, &rs_modify );
        op->orm_no_opattrs = 0;
-       op->o_msgid = 0;
+       op->o_dont_replicate = 0;
 
        if ( rs_modify.sr_err == LDAP_SUCCESS ) {
                slap_sync_cookie_free( &si->si_syncCookie, 0 );
                slap_dup_sync_cookie( &si->si_syncCookie, syncCookie );
                /* If we replaced any old values */
-               if ( mod[0].sml_values ) {
-                       for ( i=0; !BER_BVISNULL( &mod[0].sml_values[i] ); i++ ) {
-                               for ( j=0; j<si->si_cookieState->cs_num; j++ ) {
-                                       if ( mod[0].sml_values[i].bv_val !=
-                                               si->si_cookieState->cs_vals[j].bv_val )
-                                               continue;
-                                       ber_bvreplace( &si->si_cookieState->cs_vals[j],
-                                               &mod[1].sml_values[i] );
-                                       break;
-                               }
-                       }
-               } else {
-                       /* Else we just added */
-                       si->si_cookieState->cs_num += syncCookie->numcsns;
-                       value_add( &si->si_cookieState->cs_vals, syncCookie->ctxcsn );
+               for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
+                       if ( mod.sml_values[i].bv_val != si->si_cookieState->cs_vals[i].bv_val )
+                                       ber_bvreplace( &si->si_cookieState->cs_vals[i],
+                                               &mod.sml_values[i] );
+               }
+               /* Handle any added values */
+               if ( i < mod.sml_numvals ) {
+                       si->si_cookieState->cs_num = mod.sml_numvals;
+                       value_add( &si->si_cookieState->cs_vals, &mod.sml_values[i] );
                        free( si->si_cookieState->cs_sids );
                        si->si_cookieState->cs_sids = slap_parse_csn_sids(
                                si->si_cookieState->cs_vals, si->si_cookieState->cs_num, NULL );
@@ -2724,9 +2822,8 @@ syncrepl_updateCookie(
        op->o_bd = be;
        op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
        BER_BVZERO( &op->o_csn );
-       if ( mod[1].sml_next ) slap_mods_free( mod[1].sml_next, 1 );
-       op->o_tmpfree( mod[1].sml_values, op->o_tmpmemctx );
-       op->o_tmpfree( mod[0].sml_values, op->o_tmpmemctx );
+       if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
+       op->o_tmpfree( mod.sml_values, op->o_tmpmemctx );
 
        return rc;
 }
@@ -2774,6 +2871,19 @@ attr_cmp( Operation *op, Attribute *old, Attribute *new,
                        }
                }
 
+               /* Don't delete/add an objectClass, always use the replace op.
+                * Modify would fail if provider has replaced entry with a new,
+                * and the new explicitly includes a superior of a class that was
+                * only included implicitly in the old entry.  Ref ITS#5517.
+                *
+                * Also use replace op if attr has no equality matching rule.
+                * (ITS#5781)
+                */
+               if ( nn && no < o &&
+                       ( old->a_desc == slap_schema.si_ad_objectClass ||
+                        !old->a_desc->ad_type->sat_equality ))
+                       no = o;
+
                i = j;
                /* all old values were deleted, just use the replace op */
                if ( no == o ) {
@@ -2883,39 +2993,32 @@ dn_callback(
                        if ( dni->new_entry ) {
                                Modifications **modtail, **ml;
                                Attribute *old, *new;
+                               struct berval old_rdn, new_rdn;
+                               struct berval old_p, new_p;
                                int is_ctx;
 
                                is_ctx = dn_match( &rs->sr_entry->e_nname,
                                        &op->o_bd->be_nsuffix[0] );
 
                                /* Did the DN change?
+                                * case changes in the parent are ignored,
+                                * we only want to know if the RDN was
+                                * actually changed.
                                 */
-                               if ( !dn_match( &rs->sr_entry->e_name,
-                                               &dni->new_entry->e_name ) )
-                               {
-                                       struct berval oldRDN, oldVal;
-                                       AttributeDescription *ad = NULL;
-                                       Attribute *a;
+                               dnRdn( &rs->sr_entry->e_name, &old_rdn );
+                               dnRdn( &dni->new_entry->e_name, &new_rdn );
+                               dnParent( &rs->sr_entry->e_nname, &old_p );
+                               dnParent( &dni->new_entry->e_nname, &new_p );
 
+                               if ( !dn_match( &old_rdn, &new_rdn ) ||
+                                       ber_bvstrcasecmp( &old_p, &new_p ))
+                               {
                                        dni->renamed = 1;
-                                       /* See if the oldRDN was deleted */
-                                       dnRdn( &rs->sr_entry->e_nname, &oldRDN );
-                                       oldVal.bv_val = strchr(oldRDN.bv_val, '=') + 1;
-                                       oldVal.bv_len = oldRDN.bv_len - ( oldVal.bv_val -
-                                               oldRDN.bv_val );
-                                       oldRDN.bv_len -= oldVal.bv_len + 2;
-                                       slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
-                                       a = attr_find( dni->new_entry->e_attrs, ad );
-                                       if ( !a || attr_valfind( a,
-                                               SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
-                                               SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
-                                               SLAP_MR_VALUE_OF_SYNTAX,
-                                               &oldVal, NULL, op->o_tmpmemctx ) != LDAP_SUCCESS )
-                                       {
-                                               dni->delOldRDN = 1;
-                                       }
-                                       /* OK, this was just a modDN, we're done */
-                                       return LDAP_SUCCESS;
+
+                                       /* A ModDN has happened, but other changes may have
+                                        * occurred before we picked it up. So fallthru to
+                                        * regular Modify processing.
+                                        */
                                }
 
                                modtail = &dni->mods;
@@ -2927,7 +3030,8 @@ dn_callback(
                                new = attr_find( dni->new_entry->e_attrs,
                                        slap_schema.si_ad_entryCSN );
                                if ( new && old ) {
-                                       int rc, len = old->a_vals[0].bv_len;
+                                       int rc;
+                                       ber_len_t len = old->a_vals[0].bv_len;
                                        if ( len > new->a_vals[0].bv_len )
                                                len = new->a_vals[0].bv_len;
                                        rc = memcmp( old->a_vals[0].bv_val,
@@ -3057,12 +3161,12 @@ nonpresent_callback(
                        }
 
                        if ( LogTest( LDAP_DEBUG_SYNC ) ) {
-                               char buf[sizeof("rid=999 not")];
+                               char buf[sizeof("rid=999 non")];
 
                                snprintf( buf, sizeof(buf), "%s %s", si->si_ridtxt,
-                                       present_uuid ? "got" : "not" );
+                                       present_uuid ? "" : "non" );
 
-                               Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %s UUID %s, dn %s\n",
+                               Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %spresent UUID %s, dn %s\n",
                                        buf, a ? a->a_vals[0].bv_val : "<missing>", rs->sr_entry->e_name.bv_val );
                        }
 
@@ -3239,6 +3343,7 @@ syncinfo_free( syncinfo_t *sie, int free_all )
                }
        
                /* re-fetch it, in case it was already removed */
+               ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
                sie->si_re = ldap_pvt_runqueue_find( &slapd_rq, do_syncrepl, sie );
                if ( sie->si_re ) {
                        if ( ldap_pvt_runqueue_isrunning( &slapd_rq, sie->si_re ) )
@@ -3246,6 +3351,7 @@ syncinfo_free( syncinfo_t *sie, int free_all )
                        ldap_pvt_runqueue_remove( &slapd_rq, sie->si_re );
                }
        
+               ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
                ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
        
                bindconf_free( &sie->si_bindconf );
@@ -3896,9 +4002,11 @@ add_syncrepl(
 
                        if ( !isMe ) {
                                init_syncrepl( si );
+                               ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
                                si->si_re = ldap_pvt_runqueue_insert( &slapd_rq,
                                        si->si_interval, do_syncrepl, si, "do_syncrepl",
                                        si->si_ridtxt );
+                               ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
                                if ( si->si_re )
                                        rc = config_sync_shadow( c ) ? -1 : 0;
                                else
@@ -3923,9 +4031,6 @@ add_syncrepl(
                        "Config: ** successfully added syncrepl \"%s\"\n",
                        BER_BVISNULL( &si->si_bindconf.sb_uri ) ?
                        "(null)" : si->si_bindconf.sb_uri.bv_val, 0, 0 );
-               if ( !si->si_schemachecking ) {
-                       SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK;
-               }
                if ( c->be->be_syncinfo ) {
                        si->si_cookieState = c->be->be_syncinfo->si_cookieState;
                } else {
@@ -3943,9 +4048,9 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
 {
        struct berval bc, uri;
        char buf[BUFSIZ*2], *ptr;
+       ber_len_t len;
        int i;
-
-#define WHATSLEFT      ( sizeof( buf ) - ( ptr - buf ) )
+#      define WHATSLEFT        ((ber_len_t) (&buf[sizeof( buf )] - ptr))
 
        BER_BVZERO( bv );
 
@@ -3959,9 +4064,10 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
 
        ptr = buf;
        assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_SID_MAX );
-       ptr += snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
+       len = snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
                si->si_rid, si->si_bindconf.sb_uri.bv_val );
-       if ( ptr - buf >= sizeof( buf ) ) return;
+       if ( len >= sizeof( buf ) ) return;
+       ptr += len;
        if ( !BER_BVISNULL( &bc ) ) {
                if ( WHATSLEFT <= bc.bv_len ) {
                        free( bc.bv_val );
@@ -4019,8 +4125,8 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
                if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
                ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" );
                old = ptr;
-               /* FIXME: add check for overflow */
                ptr = anlist_unparse( si->si_anlist, ptr, WHATSLEFT );
+               if ( ptr == NULL ) return;
                if ( si->si_allattrs ) {
                        if ( WHATSLEFT <= STRLENOF( ",*\"" ) ) return;
                        if ( old != ptr ) *ptr++ = ',';
@@ -4036,8 +4142,8 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
        if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) {
                if ( WHATSLEFT <= STRLENOF( " " EXATTRSSTR "=" ) ) return;
                ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" );
-               /* FIXME: add check for overflow */
                ptr = anlist_unparse( si->si_exanlist, ptr, WHATSLEFT );
+               if ( ptr == NULL ) return;
        }
        if ( WHATSLEFT <= STRLENOF( " " SCHEMASTR "=" ) + STRLENOF( "off" ) ) return;
        ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" );
@@ -4058,36 +4164,42 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
                dd /= 60;
                hh = dd % 24;
                dd /= 24;
-               ptr = lutil_strcopy( ptr, " " INTERVALSTR "=" );
-               ptr += snprintf( ptr, WHATSLEFT, "%02d:%02d:%02d:%02d", dd, hh, mm, ss );
-               if ( ptr - buf >= sizeof( buf ) ) return;
+               len = snprintf( ptr, WHATSLEFT, " %s=%02d:%02d:%02d:%02d",
+                       INTERVALSTR, dd, hh, mm, ss );
+               if ( len >= WHATSLEFT ) return;
+               ptr += len;
        } else if ( si->si_retryinterval ) {
-               int space=0;
+               const char *space = "";
                if ( WHATSLEFT <= STRLENOF( " " RETRYSTR "=\"" "\"" ) ) return;
                ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" );
                for (i=0; si->si_retryinterval[i]; i++) {
-                       if ( space ) *ptr++ = ' ';
-                       space = 1;
-                       ptr += snprintf( ptr, WHATSLEFT, "%ld ", (long) si->si_retryinterval[i] );
+                       len = snprintf( ptr, WHATSLEFT, "%s%ld ", space,
+                               (long) si->si_retryinterval[i] );
+                       space = " ";
+                       if ( WHATSLEFT - 1 <= len ) return;
+                       ptr += len;
                        if ( si->si_retrynum_init[i] == RETRYNUM_FOREVER )
                                *ptr++ = '+';
-                       else
-                               ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] );
+                       else {
+                               len = snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] );
+                               if ( WHATSLEFT <= len ) return;
+                               ptr += len;
+                       }
                }
                if ( WHATSLEFT <= STRLENOF( "\"" ) ) return;
                *ptr++ = '"';
        }
 
        if ( si->si_slimit ) {
-               if ( WHATSLEFT <= STRLENOF( " " SLIMITSTR "=" ) ) return;
-               ptr = lutil_strcopy( ptr, " " SLIMITSTR "=" );
-               ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_slimit );
+               len = snprintf( ptr, WHATSLEFT, " " SLIMITSTR "=%d", si->si_slimit );
+               if ( WHATSLEFT <= len ) return;
+               ptr += len;
        }
 
        if ( si->si_tlimit ) {
-               if ( WHATSLEFT <= STRLENOF( " " TLIMITSTR "=" ) ) return;
-               ptr = lutil_strcopy( ptr, " " TLIMITSTR "=" );
-               ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_tlimit );
+               len = snprintf( ptr, WHATSLEFT, " " TLIMITSTR "=%d", si->si_tlimit );
+               if ( WHATSLEFT <= len ) return;
+               ptr += len;
        }
 
        if ( si->si_syncdata ) {
@@ -4127,13 +4239,18 @@ syncrepl_config( ConfigArgs *c )
                        for ( sip = &c->be->be_syncinfo, i=0; *sip; i++ ) {
                                si = *sip;
                                if ( c->valx == -1 || i == c->valx ) {
+                                       int isrunning = 0;
                                        *sip = si->si_next;
                                        /* If the task is currently active, we have to leave
                                         * it running. It will exit on its own. This will only
                                         * happen when running on the cn=config DB.
                                         */
-                                       if ( si->si_re &&
-                                               ldap_pvt_runqueue_isrunning( &slapd_rq, si->si_re ) ) {
+                                       if ( si->si_re ) {
+                                               ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+                                               isrunning = ldap_pvt_runqueue_isrunning( &slapd_rq, si->si_re );
+                                               ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+                                       }
+                                       if ( si->si_re && isrunning ) {
                                                si->si_ctype = 0;
                                        } else {
                                                syncinfo_free( si, 0 );