]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/syncrepl.c
Build without HAVE_TLS
[openldap] / servers / slapd / syncrepl.c
index e8e3017fc76173073738ac863e649c497be541c4..b12ecd2cb6ff869b8fa77b20558b3ef373ea903b 100644 (file)
 
 #ifdef LDAP_SYNCREPL
 
+#include "ldap_rq.h"
+
 static Entry*
-syncrepl_message_to_entry ( LDAP *, Operation *, LDAPMessage *, Modifications *,
-                           int*, struct berval *, struct berval * );
+syncrepl_message_to_entry ( LDAP *, Operation *, LDAPMessage *,
+               Modifications **, int*, struct berval *, struct berval * );
 
 static int
 syncrepl_entry( LDAP *, Operation*, Entry*, Modifications*,
@@ -59,7 +61,7 @@ slap_mods_check_syncrepl( Operation *, Modifications **,
 
 static int
 slap_mods_opattrs_syncrepl( Operation *, Modifications *, Modifications **,
-                           const char **, char *, size_t );
+                               const char **, char *, size_t );
 
 static int
 slap_mods2entry_syncrepl( Modifications *, Entry **, int,
@@ -67,6 +69,7 @@ slap_mods2entry_syncrepl( Modifications *, Entry **, int,
 
 /* callback functions */
 static int cookie_callback( struct slap_op *, struct slap_rep * );
+static int dn_callback( struct slap_op *, struct slap_rep * );
 static int nonpresent_callback( struct slap_op *, struct slap_rep * );
 static int null_callback( struct slap_op *, struct slap_rep * );
 
@@ -75,6 +78,8 @@ static AttributeDescription **add_descs_lastmod;
 static AttributeDescription **del_descs;
 static AttributeDescription **del_descs_lastmod;
 
+struct runqueue_s syncrepl_rq;
+
 void
 init_syncrepl()
 {
@@ -114,20 +119,25 @@ do_syncrepl(
        void    *ctx,
        void    *arg )
 {
-       Backend *be = arg;
+       struct re_s* rtask = arg;
+       Backend *be = rtask->arg;
        syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
 
        SlapReply       rs = {REP_RESULT};
 
-       LDAPControl     c[2], **sctrls = NULL, **rctrls = NULL, *rctrlp;
-       BerElement      *sync_ber;
-       struct berval   *sync_bvalp;
+       LDAPControl     c[2];
+       LDAPControl     **sctrls = NULL;
+       LDAPControl     **rctrls = NULL;
+       LDAPControl     *rctrlp = NULL;
+       BerElement      *sync_ber = NULL;
+       struct berval   *sync_bvalp = NULL;
 
-       BerElement      *ctrl_ber;
-       BerElement      *res_ber;
+       BerElement      *ctrl_ber = NULL;
+       BerElement      *res_ber = NULL;
 
        LDAP    *ld = NULL;
-       LDAPMessage     *res = NULL, *msg;
+       LDAPMessage     *res = NULL;
+       LDAPMessage     *msg = NULL;
 
        ber_int_t       msgid;
 
@@ -139,11 +149,11 @@ do_syncrepl(
        struct berval   *retdata = NULL;
 
        int             sync_info_arrived = 0;
-       Entry           *entry;
+       Entry           *entry = NULL;
 
        int             syncstate;
-       struct berval   syncUUID;
-       struct berval   syncCookie;
+       struct berval   syncUUID = { 0, NULL };
+       struct berval   syncCookie = { 0, NULL };
 
        int     rc;
        int     err;
@@ -151,17 +161,18 @@ do_syncrepl(
        int     syncinfo_arrived = 0;
        int     cancel_response = 0;
 
-       char **tmp;
-       AttributeDescription** descs;
+       char **tmp = NULL;
+       AttributeDescription** descs = NULL;
 
        Connection conn;
        Operation op = {0};
        slap_callback   cb;
 
-       void *memctx;
+       void *memctx = NULL;
        ber_len_t memsiz;
        
        int i, j, k, n;
+       int rc_efree;
 
        struct berval base_bv = { 0, NULL };
        struct berval pbase = { 0, NULL };
@@ -172,10 +183,9 @@ do_syncrepl(
        struct berval psub = { 0, NULL };
        struct berval nsub = { 0, NULL };
        char substr[64];
-       Modifications   *modlist;
-
-       char *def_filter_str;
-       struct berval def_filter_bv = { 0, NULL };
+       Modifications   *modlist = NULL;
+       Modifications   *ml, *mlnext;
+       char *def_filter_str = NULL;
 
 #ifdef NEW_LOGGING
        LDAP_LOG ( OPERATION, DETAIL1, "do_syncrepl\n", 0, 0, 0 );
@@ -314,6 +324,27 @@ do_syncrepl(
 
        si->ctx = ctx;
 
+       op.o_tmpmemctx = NULL; /* FIXME : to use per-thread mem context */
+       op.o_tag = LDAP_REQ_SEARCH;
+       op.o_dn = si->updatedn;
+       op.o_ndn = si->updatedn;
+       op.o_callback = &cb;
+       op.o_time = slap_get_time();
+       op.o_managedsait = 1;
+       op.o_threadctx = si->ctx;
+       op.o_bd = be;
+       op.o_conn = &conn;
+       op.o_connid = op.o_conn->c_connid;
+       op.ors_scope = LDAP_SCOPE_BASE;
+       op.ors_deref = LDAP_DEREF_NEVER;
+       op.ors_slimit = -1;
+       op.ors_tlimit = -1;
+       op.ors_attrsonly = 0;
+       op.ors_attrs = NULL;
+       op.ors_filter = str2filter( def_filter_str = "(objectClass=*)" );
+       ber_str2bv( def_filter_str, strlen( def_filter_str ), 1,
+                               &op.ors_filterstr );
+
        si->conn = &conn;
        conn.c_send_ldap_result = slap_send_ldap_result;
        conn.c_send_search_entry = slap_send_search_entry;
@@ -330,13 +361,12 @@ do_syncrepl(
        build_new_dn( &op.o_req_dn, &pbase, &psubrdn );
        build_new_dn( &op.o_req_ndn, &nbase, &nsubrdn );
 
-       op.o_tag = LDAP_REQ_SEARCH;
-       op.o_ndn = be->be_rootndn;
-       psub = be->be_nsuffix[0];
-       op.o_callback = &cb;
-       op.o_time = slap_get_time();
-       op.o_managedsait = 1;
-       op.o_threadctx = si->ctx;
+       ch_free( base_bv.bv_val );
+       ch_free( pbase.bv_val );
+       ch_free( nbase.bv_val );
+       ch_free( sub_bv.bv_val );
+       ch_free( psubrdn.bv_val );
+       ch_free( nsubrdn.bv_val );
 
        /* set callback function */
        cb.sc_response = cookie_callback;
@@ -344,24 +374,18 @@ do_syncrepl(
 
        /* search subentry to retrieve cookie */
        si->syncCookie = NULL;
+       be->be_search( &op, &rs );
 
-       op.o_bd = be;
-       op.o_conn = &conn;
-       op.o_connid = op.o_conn->c_connid;
-       op.ors_scope = LDAP_SCOPE_BASE;
-       op.ors_deref = LDAP_DEREF_NEVER;
-       op.ors_slimit = -1;
-       op.ors_tlimit = -1;
-       op.ors_attrsonly = 0;
-       op.ors_attrs = NULL;
-       op.ors_filter = str2filter( def_filter_str = "(objectClass=*)" );
-       ber_str2bv( def_filter_str, strlen( def_filter_str ), 1,
-                               &op.ors_filterstr );
+       ch_free( op.o_req_dn.bv_val );
+       ch_free( op.o_req_ndn.bv_val );
+       filter_free( op.ors_filter );
+       ch_free( op.ors_filterstr.bv_val );
 
-       be->be_search( &op, &rs );
+       psub = be->be_nsuffix[0];
 
        /* setup LDAP SYNC control */
        sync_ber = ber_alloc_t( LBER_USE_DER );
+       ber_set_option( sync_ber, LBER_OPT_BER_MEMCTX, op.o_tmpmemctx );
 
        if ( si->syncCookie ) {
                ber_printf( sync_ber, "{eO}", abs(si->type), si->syncCookie );
@@ -375,7 +399,7 @@ do_syncrepl(
        }
        ber_free( sync_ber, 1 );
 
-       sctrls = (LDAPControl**) ch_calloc( 3, sizeof(LDAPControl*) );
+       sctrls = (LDAPControl**) sl_calloc( 3, sizeof(LDAPControl*), op.o_tmpmemctx );
 
        c[0].ldctl_oid = LDAP_CONTROL_SYNC;
        c[0].ldctl_value = (*sync_bvalp);
@@ -397,7 +421,7 @@ do_syncrepl(
        err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, sctrls );
 
        ber_bvfree( sync_bvalp );
-       free( sctrls );
+       ch_free( sctrls );
 
         if ( err != LDAP_OPT_SUCCESS )
                fprintf( stderr, "Could not set controls : %d\n", err );
@@ -422,8 +446,7 @@ do_syncrepl(
 
        /* Add Attributes */
 
-       for ( n = 0; si->attrs[ n ] != NULL; n++ )
-               ;
+       for ( n = 0; si->attrs[ n ] != NULL; n++ ) ;
        
        if ( si->lastmod == LASTMOD_REQ ) {
                descs = add_descs_lastmod;
@@ -442,8 +465,7 @@ do_syncrepl(
 #endif
                }
                si->attrs = tmp;
-               si->attrs[ n++ ] = ( char * ) strndup( descs[i]->ad_cname.bv_val,
-                                                      descs[i]->ad_cname.bv_len );
+               si->attrs[ n++ ] = ch_strdup ( descs[i]->ad_cname.bv_val );
                si->attrs[ n ] = NULL;
        }
 
@@ -454,7 +476,7 @@ do_syncrepl(
                                NULL, -1, &msgid );
 
         if( rc != LDAP_SUCCESS ) {
-                fprintf( stderr, "syncrepl: ldap_search_ext (%d)\n",
+                fprintf( stderr, "syncrepl: ldap_search_ext: %s (%d)\n",
                                        ldap_err2string( rc ), rc );
                 return NULL;
        }
@@ -467,14 +489,18 @@ do_syncrepl(
                {
                        switch( ldap_msgtype( msg ) ) {
                        case LDAP_RES_SEARCH_ENTRY:
-                               entry = syncrepl_message_to_entry( ld, &op, msg, modlist, &syncstate, &syncUUID, &syncCookie );
-                               syncrepl_entry( ld, &op, entry, modlist,
-                                               syncstate, &syncUUID,
-                                               &syncCookie,
-                                               !syncinfo_arrived );
+                               entry = syncrepl_message_to_entry( ld, &op, msg,
+                                       &modlist, &syncstate, &syncUUID, &syncCookie );
+                               rc_efree = syncrepl_entry( ld, &op, entry, modlist,
+                                               syncstate, &syncUUID, &syncCookie, !syncinfo_arrived );
                                if ( syncCookie.bv_len ) {
-                                       syncrepl_updateCookie( ld, &op, &psub,
-                                                              &syncCookie );
+                                       syncrepl_updateCookie( ld, &op, &psub, &syncCookie );
+                               }
+                               if ( rc_efree )
+                                       entry_free( entry );
+                               for ( ml = modlist; ml != NULL; ml = mlnext ) {
+                                       mlnext = ml->sml_next;
+                                       ber_memfree( ml );
                                }
                                break;
 
@@ -492,11 +518,15 @@ do_syncrepl(
                                ldap_parse_result( ld, msg, &err, NULL, NULL, NULL, &rctrls, 0 );
                                if ( rctrls ) {
                                        rctrlp = *rctrls;
-                                       ctrl_ber = ber_init( &rctrlp->ldctl_value );
+                                       ctrl_ber = ber_alloc_t( LBER_USE_DER );
+                                       ber_set_option( ctrl_ber, LBER_OPT_BER_MEMCTX, op.o_tmpmemctx );
+                                       ber_write( ctrl_ber, rctrlp->ldctl_value.bv_val, rctrlp->ldctl_value.bv_len, 0 );
+                                       ber_reset( ctrl_ber, 1 );
+
                                        ber_scanf( ctrl_ber, "{" );
                                        if ( ber_peek_tag( ctrl_ber, &len )
                                                == LDAP_SYNC_TAG_COOKIE ) {
-                                               ber_scanf( ctrl_ber, "m", &syncCookie );
+                                               ber_scanf( ctrl_ber, "o", &syncCookie );
                                        }
                                }
                                if (si->type == LDAP_SYNC_REFRESH_AND_PERSIST) {
@@ -505,19 +535,24 @@ do_syncrepl(
                                                        ber_bvfree( si->syncCookie );
                                                        si->syncCookie = ber_dupbv( NULL, &syncCookie );
                                                }
+                                               if ( ctrl_ber )
+                                                       ber_free( ctrl_ber, 1 );
                                                goto done;
                                        }
-                                       else 
+                                       else {
+                                               if ( ctrl_ber )
+                                                       ber_free( ctrl_ber, 1 );
                                                break;
+                                       }
                                } else {
                                        if ( syncCookie.bv_len ) {
-                                               syncrepl_updateCookie( ld,
-                                                               &op, &psub,
-                                                              &syncCookie );
+                                               syncrepl_updateCookie( ld, &op, &psub, &syncCookie );
                                        }
-                                       goto restart;
+                                       syncrepl_del_nonpresent( ld, &op );
+                                       if ( ctrl_ber )
+                                               ber_free( ctrl_ber, 1 );
+                                       goto done;
                                }
-restart_loop:
                                break;
 
                        case LDAP_RES_INTERMEDIATE_RESP:
@@ -541,8 +576,8 @@ restart_loop:
                                        }
 
                                        if ( ber_peek_tag( res_ber, &len )
-                                               == LDAP_SYNC_TAG_COOKIE ) {
-                                               ber_scanf( res_ber, "m}", &syncCookie );
+                                                               == LDAP_SYNC_TAG_COOKIE ) {
+                                               ber_scanf( res_ber, "o}", &syncCookie );
                                                if ( syncCookie.bv_len ) {
                                                        ber_bvfree( si->syncCookie );
                                                        si->syncCookie = ber_dupbv( NULL, &syncCookie );
@@ -601,20 +636,27 @@ restart_loop:
                Debug( LDAP_DEBUG_ANY,
                        "do_syncrepl : unknown result\n", 0, 0, 0 );
 #endif
-               return NULL;
        }
 
-restart:
-       sleep(si->interval * 60);
-       goto restart_loop;
-//     set alarm clock to send signal to slapd
-//     should set the signal handler beforehand
-//     the signal handler re execute do_syncrepl()
-
 done:
+       if ( syncCookie.bv_val )
+               ch_free( syncCookie.bv_val );
+       if ( syncUUID.bv_val )
+               ch_free( syncUUID.bv_val );
+
        if ( res )
                ldap_msgfree( res );
        ldap_unbind( ld );
+
+       ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
+       ldap_pvt_runqueue_stoptask( &syncrepl_rq, rtask );
+       if ( si->type == LDAP_SYNC_REFRESH_ONLY ) {
+               ldap_pvt_runqueue_resched( &syncrepl_rq, rtask );
+       } else {
+               ldap_pvt_runqueue_remove( &syncrepl_rq, rtask );
+       }
+       ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
+
        return NULL;
 }
 
@@ -623,7 +665,7 @@ syncrepl_message_to_entry(
        LDAP            *ld,
        Operation       *op,
        LDAPMessage     *msg,
-       Modifications   *modlist,
+       Modifications   **modlist,
        int             *syncstate,
        struct berval   *syncUUID,
        struct berval   *syncCookie
@@ -632,19 +674,19 @@ syncrepl_message_to_entry(
        Entry           *e;
        BerElement      *ber = NULL;
        BerElement      *tmpber;
-       struct berval   bv;
+       struct berval   bv = {0, NULL};
        Modifications   tmp;
        Modifications   *mod;
-       Modifications   **modtail = &modlist;
+       Modifications   **modtail = modlist;
        Backend         *be = op->o_bd;
 
        const char      *text;
        char txtbuf[SLAP_TEXT_BUFLEN];
        size_t textlen = sizeof txtbuf;
 
-       struct berval   **bvals;
+       struct berval   **bvals = NULL;
        char            *dn;
-       struct berval   bdn;
+       struct berval   bdn = {0, NULL};
        Attribute       *attr;
        struct berval   empty_bv = { 0, NULL };
        int             rc;
@@ -657,7 +699,9 @@ syncrepl_message_to_entry(
        LDAPControl**   rctrls = NULL;
        BerElement*     ctrl_ber;
 
-       modlist = NULL;
+       ber_tag_t       tag;
+
+       *modlist = NULL;
 
        if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
 #ifdef NEW_LOGGING
@@ -686,19 +730,19 @@ syncrepl_message_to_entry(
        }
 
        e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
-       dnPrettyNormal( NULL, &bdn, &e->e_name, &e->e_nname, NULL );
+       dnPrettyNormal( NULL, &bdn, &e->e_name, &e->e_nname, op->o_tmpmemctx );
 
        e->e_attrs = NULL;
 
-       for ( rc = ldap_get_attribute_ber( ld, msg, ber, &tmp.sml_type, &tmp.sml_bvalues);
-             rc == LDAP_SUCCESS;
-             rc = ldap_get_attribute_ber( ld, msg, ber, &tmp.sml_type, &tmp.sml_bvalues))
-       {
+       while ( ber_remaining( ber ) ) {
+               tag = ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values );
+
+               if ( tag == LBER_ERROR ) break;
                if ( tmp.sml_type.bv_val == NULL ) break;
 
-               mod  = (Modifications *) ch_malloc( sizeof(Modifications) );
+               mod  = (Modifications *) ch_malloc( sizeof( Modifications ));
 
-               mod->sml_op = LDAP_MOD_ADD;
+               mod->sml_op = LDAP_MOD_REPLACE;
                mod->sml_next = NULL;
                mod->sml_desc = NULL;
                mod->sml_type = tmp.sml_type;
@@ -709,16 +753,16 @@ syncrepl_message_to_entry(
                modtail = &mod->sml_next;
        }
 
-        if ( ber_scanf( ber, "}") == LBER_ERROR ) {
+       if ( ber_scanf( ber, "}") == LBER_ERROR ) {
 #ifdef NEW_LOGGING
-                LDAP_LOG( OPERATION, ERR,
-                        "syncrepl_message_to_entry: ber_scanf failed\n", 0, 0, 0 );
+               LDAP_LOG( OPERATION, ERR,
+                               "syncrepl_message_to_entry: ber_scanf failed\n", 0, 0, 0 );
 #else
-                Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: ber_scanf failed\n",
-                       0, 0, 0 );
+               Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: ber_scanf failed\n",
+                               0, 0, 0 );
 #endif
                return NULL;
-        }
+       }
 
        ber_free( ber, 0 );
        tmpber = ldap_get_message_ber( msg );
@@ -741,11 +785,15 @@ syncrepl_message_to_entry(
 
        if ( rctrls ) {
                rctrlp = *rctrls;
-               ctrl_ber = ber_init( &rctrlp->ldctl_value );
-               ber_scanf( ctrl_ber, "{em", syncstate, syncUUID );
+               ctrl_ber = ber_alloc_t( LBER_USE_DER );
+               ber_set_option( ctrl_ber, LBER_OPT_BER_MEMCTX, op->o_tmpmemctx );
+               ber_write( ctrl_ber, rctrlp->ldctl_value.bv_val, rctrlp->ldctl_value.bv_len, 0 );
+               ber_reset( ctrl_ber, 1 );
+               ber_scanf( ctrl_ber, "{eo", syncstate, syncUUID );
                if ( ber_peek_tag( ctrl_ber, &len ) == LDAP_SYNC_TAG_COOKIE ) {
-                       ber_scanf( ctrl_ber, "m}", syncCookie );
+                       ber_scanf( ctrl_ber, "o}", syncCookie );
                }
+               ber_free( ctrl_ber, 1 );
        } else {
 #ifdef NEW_LOGGING
                LDAP_LOG( OPERATION, ERR,"syncrepl_message_to_entry : "
@@ -761,51 +809,51 @@ syncrepl_message_to_entry(
                goto done;
        }
 
-        if ( modlist == NULL ) {
+       if ( *modlist == NULL ) {
 #ifdef NEW_LOGGING
-                LDAP_LOG( OPERATION, ERR,
-                        "syncrepl_message_to_entry: no attributes\n", 0, 0, 0 );
+               LDAP_LOG( OPERATION, ERR,
+                               "syncrepl_message_to_entry: no attributes\n", 0, 0, 0 );
 #else
-                Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: no attributes\n",
-                        0, 0, 0 );
+               Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: no attributes\n",
+                               0, 0, 0 );
 #endif
-        }
+       }
 
-       rc = slap_mods_check_syncrepl( op, &modlist, &text, txtbuf, textlen, NULL );
+       rc = slap_mods_check_syncrepl( op, modlist, &text, txtbuf, textlen, NULL );
 
        if ( rc != LDAP_SUCCESS ) {
 #ifdef NEW_LOGGING
-                LDAP_LOG( OPERATION, ERR,
-                        "syncrepl_message_to_entry: mods check (%s)\n", text, 0, 0 );
+               LDAP_LOG( OPERATION, ERR,
+                               "syncrepl_message_to_entry: mods check (%s)\n", text, 0, 0 );
 #else
-                Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods check (%s)\n",
-                        text, 0, 0 );
+               Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods check (%s)\n",
+                               text, 0, 0 );
 #endif
                return NULL;
        }
        
-       rc = slap_mods_opattrs_syncrepl( op, modlist, modtail,
+       rc = slap_mods_opattrs_syncrepl( op, *modlist, modtail,
                                         &text,txtbuf, textlen );
        
        if( rc != LDAP_SUCCESS ) {
 #ifdef NEW_LOGGING
-                LDAP_LOG( OPERATION, ERR,
-                        "syncrepl_message_to_entry: mods opattrs (%s)\n", text, 0, 0 );
+               LDAP_LOG( OPERATION, ERR,
+                               "syncrepl_message_to_entry: mods opattrs (%s)\n", text, 0, 0 );
 #else
-                Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods opattrs (%s)\n",
-                        text, 0, 0 );
+               Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods opattrs (%s)\n",
+                               text, 0, 0 );
 #endif
                return NULL;
        }
 
-       rc = slap_mods2entry_syncrepl( modlist, &e, 1, &text, txtbuf, textlen );
+       rc = slap_mods2entry_syncrepl( *modlist, &e, 1, &text, txtbuf, textlen );
        if( rc != LDAP_SUCCESS ) {
 #ifdef NEW_LOGGING
-                LDAP_LOG( OPERATION, ERR,
-                        "syncrepl_message_to_entry: mods2entry (%s)\n", text, 0, 0 );
+               LDAP_LOG( OPERATION, ERR,
+                               "syncrepl_message_to_entry: mods2entry (%s)\n", text, 0, 0 );
 #else
-                Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods2entry (%s)\n",
-                        text, 0, 0 );
+               Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods2entry (%s)\n",
+                               text, 0, 0 );
 #endif
        }
 
@@ -816,7 +864,7 @@ done:
        return e;
 }
 
-int 
+int
 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
 {
        const struct berval *uuid1 = v_uuid1;
@@ -841,110 +889,144 @@ syncrepl_entry(
        Backend *be = op->o_bd;
        syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
        slap_callback   cb;
-       struct berval   normdn = {0, NULL};
-       struct berval   prettydn = {0, NULL};
        struct berval   csn_bv = {0, NULL};
        struct berval   *syncuuid_bv = NULL;
        char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
 
        SlapReply       rs = {REP_RESULT};
-       int rc;
+       int rc = LDAP_SUCCESS;
+
+       struct berval base_bv = {0, NULL};
 
        char *filterstr;
-       struct berval filterstr_bv;
        Filter *filter;
 
        Attribute *a;
 
-       if ( syncstate == LDAP_SYNC_PRESENT ) {
+       if ( refresh &&
+                       ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD )) {
                syncuuid_bv = ber_dupbv( NULL, syncUUID );
                avl_insert( &si->presentlist, (caddr_t) syncuuid_bv,
-                               syncuuid_cmp, avl_dup_error );
-               return;
+                                               syncuuid_cmp, avl_dup_error );
+       }
+
+       if ( syncstate == LDAP_SYNC_PRESENT ) {
+               if ( e )
+                       return 1;
+               else
+                       return 0;
        }
 
        if ( !attr_find( e->e_attrs, slap_schema.si_ad_entryUUID )) {
                attr_merge_one( e, slap_schema.si_ad_entryUUID, syncUUID, syncUUID );
        }
 
-       filterstr = (char *) ch_malloc( strlen("entryUUID=") + syncUUID->bv_len + 1 ); 
+       filterstr = (char *) sl_malloc( strlen("entryUUID=") + syncUUID->bv_len + 1, op->o_tmpmemctx ); 
        strcpy( filterstr, "entryUUID=" );
        strcat( filterstr, syncUUID->bv_val );
 
        si->e = e;
        si->syncUUID = syncUUID;
+       si->syncUUID_ndn = NULL;
 
        filter = str2filter( filterstr );
-       ber_str2bv( filterstr, strlen(filterstr), 1, &filterstr_bv );
+       ber_str2bv( filterstr, strlen(filterstr), 1, &op->ors_filterstr );
        ch_free( filterstr );
+       op->ors_filter = filter;
+       op->ors_scope = LDAP_SCOPE_SUBTREE;
 
-       dnPrettyNormal( 0, &(e->e_name), &prettydn, &normdn, NULL );
-
-       free(e->e_name.bv_val);
-       free(e->e_nname.bv_val);
-       e->e_name = prettydn;
-       e->e_nname = normdn;
-       op->o_req_dn = e->e_name;
-       op->o_req_ndn = e->e_nname;
+       /* get syncrepl cookie of shadow replica from subentry */
+       ber_str2bv( si->base, strlen(si->base), 1, &base_bv ); 
+       dnPrettyNormal( 0, &base_bv, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx );
+       ch_free( base_bv.bv_val );
 
+       /* set callback function */
        op->o_callback = &cb;
-       cb.sc_response = null_callback;
+       cb.sc_response = dn_callback;
        cb.sc_private = si;
 
+       be->be_search( op, &rs );
+
+       ch_free( op->o_req_dn.bv_val );
+       ch_free( op->o_req_ndn.bv_val );
+       filter_free( op->ors_filter );
+       ch_free( op->ors_filterstr.bv_val );
+
+       cb.sc_response = null_callback;
+
+       if ( si->syncUUID_ndn )
+               printf("syncUUID_ndn = %s\n", si->syncUUID_ndn );
+
        switch ( syncstate ) {
        case LDAP_SYNC_ADD :
        case LDAP_SYNC_MODIFY :
-sync_add_retry:
-               op->o_tag = LDAP_REQ_MODIFY;
-               op->orm_modlist = modlist;
-               rc = be->be_modify( op, &rs );
-               if ( rc != LDAP_SUCCESS ) {
-                       if ( rc == LDAP_REFERRAL ||
-                            rc == LDAP_NO_SUCH_OBJECT ||
-                            rc == DB_NOTFOUND ) {
-                               op->o_tag = LDAP_REQ_ADD;
-                               op->ora_e = e;
-                               rc = be->be_add( op, &rs );
-                               if ( rc != LDAP_SUCCESS ) {
-                                       if ( rc == LDAP_ALREADY_EXISTS ) {
-                                               goto sync_add_retry;
-                                       } else if ( rc == LDAP_REFERRAL ||
-                                                   rc == LDAP_NO_SUCH_OBJECT ||
-                                                   rc == DB_NOTFOUND ) {
-                                               syncrepl_add_glue(ld, op, e,
-                                                       modlist, syncstate,
-                                                       syncUUID, syncCookie);
-                                       } else {
+
+               rc = LDAP_SUCCESS;
+
+               if ( si->syncUUID_ndn ) {
+                       op->o_req_dn = *si->syncUUID_ndn;
+                       op->o_req_ndn = *si->syncUUID_ndn;
+                       op->o_tag = LDAP_REQ_DELETE;
+                       rc = be->be_delete( op, &rs );
+               }
+
+               if ( rc == LDAP_SUCCESS ||
+                        rc == LDAP_REFERRAL ||
+                        rc == LDAP_NO_SUCH_OBJECT ||
+                        rc == DB_NOTFOUND ) {
+                       op->o_tag = LDAP_REQ_ADD;
+                       op->ora_e = e;
+                       op->o_req_dn = e->e_name;
+                       op->o_req_ndn = e->e_nname;
+                       rc = be->be_add( op, &rs );
+                       if ( rc != LDAP_SUCCESS ) {
+                               if ( rc == LDAP_ALREADY_EXISTS ) {
 #ifdef NEW_LOGGING
-                                               LDAP_LOG( OPERATION, ERR,
-                                                       "be_add failed (%d)\n",
-                                                       rc, 0, 0 );
+                                       LDAP_LOG( OPERATION, ERR,
+                                               "be_add failed : already exists (%d)\n",
+                                               rc, 0, 0 );
 #else
-                                               Debug( LDAP_DEBUG_ANY,
-                                                       "be_add failed (%d)\n",
-                                                       rc, 0, 0 );
+                                       Debug( LDAP_DEBUG_ANY,
+                                               "be_add failed : already exists (%d)\n",
+                                               rc, 0, 0 );
+#endif
+                               } else if ( rc == LDAP_REFERRAL ||
+                                                       rc == LDAP_NO_SUCH_OBJECT ||
+                                                       rc == DB_NOTFOUND ) {
+                                       syncrepl_add_glue(ld, op, e,
+                                               modlist, syncstate,
+                                               syncUUID, syncCookie);
+                               } else {
+#ifdef NEW_LOGGING
+                                       LDAP_LOG( OPERATION, ERR,
+                                               "be_add failed (%d)\n",
+                                               rc, 0, 0 );
+#else
+                                       Debug( LDAP_DEBUG_ANY,
+                                               "be_add failed (%d)\n",
+                                               rc, 0, 0 );
 #endif
-                                       }
                                }
                        } else {
+                               return 0;
+                       }
+               } else {
 #ifdef NEW_LOGGING
-                               LDAP_LOG( OPERATION, ERR,
-                                       "be_modify failed (%d)\n", rc, 0, 0 );
+                       LDAP_LOG( OPERATION, ERR,
+                               "be_modify/be_delete failed (%d)\n", rc, 0, 0 );
 #else
-                               Debug( LDAP_DEBUG_ANY,
-                                       "be_modify failed (%d)\n", rc, 0, 0 );
+                       Debug( LDAP_DEBUG_ANY,
+                               "be_modify/be_delete failed (%d)\n", rc, 0, 0 );
 #endif
-                       }
                }
 
                si->e = NULL;
-               break;
+               return 1;
        case LDAP_SYNC_DELETE :
                op->o_tag = LDAP_REQ_DELETE;
                be->be_delete( op, &rs );
-               entry_free( e );
                si->e = NULL;
-               break;
+               return 1;
        default :
 #ifdef NEW_LOGGING
                LDAP_LOG( OPERATION, ERR,
@@ -953,7 +1035,7 @@ sync_add_retry:
                Debug( LDAP_DEBUG_ANY,
                        "unknown syncstate\n", 0, 0, 0 );
 #endif
-               return;
+               return 1;
        }
 }
 
@@ -969,10 +1051,12 @@ syncrepl_del_nonpresent(
        struct berval   base_bv = {0, NULL};
        Filter *filter;
        SlapReply       rs = {REP_RESULT};
-       struct berval   filterstr_bv;
+       struct berval   filterstr_bv = {0, NULL};
+       struct nonpresent_entry *np_list, *np_prev;
 
        ber_str2bv( si->base, strlen(si->base), 1, &base_bv ); 
-       dnPrettyNormal(0, &base_bv, &op->o_req_dn, &op->o_req_ndn, NULL );
+       dnPrettyNormal(0, &base_bv, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx );
+       ch_free( base_bv.bv_val );
 
        filter = str2filter( si->filterstr );
 
@@ -981,16 +1065,44 @@ syncrepl_del_nonpresent(
 
        op->o_callback = &cb;
        op->o_tag = LDAP_REQ_SEARCH;
-       op->ors_scope = LDAP_SCOPE_BASE;
+       op->ors_scope = si->scope;
        op->ors_deref = LDAP_DEREF_NEVER;
        op->ors_slimit = -1;
        op->ors_tlimit = -1;
        op->ors_attrsonly = 0;
        op->ors_attrs = NULL;
-       op->ors_filter = str2filter( si->filterstr );
+       op->ors_filter = filter;
        ber_str2bv( si->filterstr, strlen( si->filterstr ), 1, &op->ors_filterstr );
 
        be->be_search( op, &rs );
+
+       if ( !LDAP_LIST_EMPTY( &si->nonpresentlist ) ) {
+               np_list = LDAP_LIST_FIRST( &si->nonpresentlist );
+               while ( np_list != NULL ) {
+                       LDAP_LIST_REMOVE( np_list, np_link );
+                       np_prev = np_list;
+                       np_list = LDAP_LIST_NEXT( np_list, np_link );
+                       op->o_tag = LDAP_REQ_DELETE;
+                       op->o_callback = &cb;
+                       cb.sc_response = null_callback;
+                       cb.sc_private = si;
+                       op->o_req_dn = *np_prev->dn;
+                       op->o_req_ndn = *np_prev->ndn;
+                       op->o_bd->be_delete( op, &rs );
+                       ber_bvfree( np_prev->dn );
+                       ber_bvfree( np_prev->ndn );
+                       op->o_req_dn.bv_val = NULL;
+                       op->o_req_ndn.bv_val = NULL;
+                       ch_free( np_prev );
+               }
+       }
+
+       if ( op->o_req_dn.bv_val )
+               ch_free( op->o_req_dn.bv_val );
+       if ( op->o_req_ndn.bv_val )
+               ch_free( op->o_req_ndn.bv_val );
+       filter_free( op->ors_filter );
+       ch_free( op->ors_filterstr.bv_val );
 }
 
 
@@ -1029,25 +1141,33 @@ syncrepl_add_glue(
 
        ber_dupbv( &dn, &e->e_nname );
        ber_dupbv( &pdn, &e->e_nname );
+
        while ( !be_issuffix ( be, &pdn )) {
                dnParent( &dn, &pdn );
+               ch_free( dn.bv_val );
                ber_dupbv( &dn, &pdn );
                levels++;
        }
 
        for ( i = 0; i <= levels; i++ ) {
                glue = (Entry*) ch_calloc( 1, sizeof(Entry) );
+               ch_free( dn.bv_val );
+               ch_free( pdn.bv_val );
                ber_dupbv( &dn, &e->e_nname );
                ber_dupbv( &pdn, &e->e_nname );
                j = levels - i;
                for ( k = 0; k < j; k++ ) {
                        dnParent( &dn, &pdn );
+                       ch_free( dn.bv_val );
                        ber_dupbv( &dn, &pdn );
                }
 
-               dnPrettyNormal( 0, &dn, &pdn, &ndn, NULL );
+               dnPrettyNormal( 0, &dn, &pdn, &ndn, op->o_tmpmemctx );
                ber_dupbv( &glue->e_name, &pdn );
                ber_dupbv( &glue->e_nname, &ndn );
+               ch_free( dn.bv_val );
+               ch_free( pdn.bv_val );
+               ch_free( ndn.bv_val );
 
                a = ch_calloc( 1, sizeof( Attribute ));
                a->a_desc = slap_schema.si_ad_objectClass;
@@ -1083,10 +1203,12 @@ syncrepl_add_glue(
                        op->o_req_ndn = glue->e_nname;
                        op->ora_e = glue;
                        rc = be->be_add ( op, &rs );
-                       if ( rc == LDAP_SUCCESS )
+                       if ( rc == LDAP_SUCCESS ) {
                                be_entry_release_w( op, glue );
-                       else 
+                       } else {
+                       /* incl. ALREADY EXIST */
                                entry_free( glue );
+                       }
                }
        }
 
@@ -1103,14 +1225,16 @@ syncrepl_updateCookie(
 {
        Backend *be = op->o_bd;
        syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
+       Modifications *ml;
+       Modifications *mlnext;
        Modifications *mod;
        Modifications *modlist;
        Modifications **modtail = &modlist;
 
-       struct berval* ocbva;
-       struct berval* cnbva;
-       struct berval* ssbva;
-       struct berval* scbva;
+       struct berval* ocbva = NULL;
+       struct berval* cnbva = NULL;
+       struct berval* ssbva = NULL;
+       struct berval* scbva = NULL;
 
        char substr[64];
        char rdnstr[67];
@@ -1158,7 +1282,6 @@ syncrepl_updateCookie(
        sprintf( rdnstr, "cn=%s", substr );
        ber_str2bv( substr, strlen( substr ), 1, &cnbva[0] );
        ber_str2bv( rdnstr, strlen( rdnstr ), 1, &psubrdn );
-       free( substr );
        cnbva[1].bv_len = 0;
        cnbva[1].bv_val = NULL;
        mod = (Modifications *) ch_malloc( sizeof( Modifications ));
@@ -1185,7 +1308,7 @@ syncrepl_updateCookie(
        *modtail = mod;
        modtail = &mod->sml_next;
 
-       ber_str2bv( " ", 1, 1, &ssbva[0] );
+       ber_str2bv( "{}", strlen("{}"), 1, &ssbva[0] );
        ssbva[1].bv_len = 0;
        ssbva[1].bv_val = NULL;
        mod = (Modifications *) ch_malloc( sizeof( Modifications ));
@@ -1203,10 +1326,10 @@ syncrepl_updateCookie(
 
        if ( rc != LDAP_SUCCESS ) {
 #ifdef NEW_LOGGING
-                LDAP_LOG( OPERATION, ERR,
-                        "syncrepl_updateCookie: mods check (%s)\n", text, 0, 0 );
+               LDAP_LOG( OPERATION, ERR,
+                               "syncrepl_updateCookie: mods check (%s)\n", text, 0, 0 );
 #else
-                Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods check (%s)\n",
+               Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods check (%s)\n",
                         text, 0, 0 );
 #endif
        }
@@ -1216,10 +1339,10 @@ syncrepl_updateCookie(
 
        if( rc != LDAP_SUCCESS ) {
 #ifdef NEW_LOGGING
-                LDAP_LOG( OPERATION, ERR,
-                        "syncrepl_updateCookie: mods opattrs (%s)\n", text, 0, 0 );
+               LDAP_LOG( OPERATION, ERR,
+                               "syncrepl_updateCookie: mods opattrs (%s)\n", text, 0, 0 );
 #else
-                Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods opattrs (%s)\n",
+               Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods opattrs (%s)\n",
                         text, 0, 0 );
 #endif
        }
@@ -1227,7 +1350,9 @@ syncrepl_updateCookie(
        e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
 
        build_new_dn( &sub_bv, pdn, &psubrdn );
-       dnPrettyNormal( NULL, &sub_bv, &e->e_name, &e->e_nname, NULL );
+       dnPrettyNormal( NULL, &sub_bv, &e->e_name, &e->e_nname, op->o_tmpmemctx );
+       ch_free( sub_bv.bv_val );
+       ch_free( psubrdn.bv_val );
 
        e->e_attrs = NULL;
 
@@ -1235,10 +1360,10 @@ syncrepl_updateCookie(
 
        if( rc != LDAP_SUCCESS ) {
 #ifdef NEW_LOGGING
-                LDAP_LOG( OPERATION, ERR,
-                        "syncrepl_updateCookie: mods2entry (%s)\n", text, 0, 0 );
+               LDAP_LOG( OPERATION, ERR,
+                               "syncrepl_updateCookie: mods2entry (%s)\n", text, 0, 0 );
 #else
-                Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods2entry (%s)\n",
+               Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods2entry (%s)\n",
                         text, 0, 0 );
 #endif
        }
@@ -1250,12 +1375,6 @@ syncrepl_updateCookie(
        op->o_req_dn = e->e_name;
        op->o_req_ndn = e->e_nname;
 
-       /*
-       for( mod = modlist; mod != NULL; mod = mod->sml_next ) {
-               mod->sml_op = LDAP_MOD_REPLACE;
-       }
-       */
-
        /* update persistent cookie */
 update_cookie_retry:
        op->o_tag = LDAP_REQ_MODIFY;
@@ -1263,8 +1382,8 @@ update_cookie_retry:
        rc = be->be_modify( op, &rs );
        if ( rc != LDAP_SUCCESS ) {
                if ( rc == LDAP_REFERRAL ||
-                    rc == LDAP_NO_SUCH_OBJECT ||
-                    rc == DB_NOTFOUND ) {
+                        rc == LDAP_NO_SUCH_OBJECT ||
+                        rc == DB_NOTFOUND ) {
                        op->o_tag = LDAP_REQ_ADD;
                        op->ora_e = e;
                        rc = be->be_add( op, &rs );
@@ -1272,8 +1391,8 @@ update_cookie_retry:
                                if ( rc == LDAP_ALREADY_EXISTS ) {
                                        goto update_cookie_retry;
                                } else if ( rc == LDAP_REFERRAL ||
-                                           rc == LDAP_NO_SUCH_OBJECT ||
-                                           rc == DB_NOTFOUND ) {
+                                                       rc == LDAP_NO_SUCH_OBJECT ||
+                                                       rc == DB_NOTFOUND ) {
 #ifdef NEW_LOGGING
                                        LDAP_LOG( OPERATION, ERR,
                                                "cookie will be non-persistent\n",
@@ -1294,6 +1413,8 @@ update_cookie_retry:
                                                rc, 0, 0 );
 #endif
                                }
+                       } else {
+                               goto done;
                        }
                } else {
 #ifdef NEW_LOGGING
@@ -1305,19 +1426,31 @@ update_cookie_retry:
 #endif
                }
        }
+
+       if ( e != NULL )
+               entry_free( e );
+
+done :
+
+       for ( ml = modlist; ml != NULL; ml = mlnext ) {
+               mlnext = ml->sml_next;
+               free( ml );
+       }
+
+       return;
 }
 
 
 static
 int slap_mods_check_syncrepl(
        Operation *op,
-        Modifications **mlp,
-        const char **text,
-        char *textbuf,
-        size_t textlen,
+       Modifications **mlp,
+       const char **text,
+       char *textbuf,
+       size_t textlen,
        void *ctx )
 {
-        int rc;
+       int rc;
        Backend *be = op->o_bd;
        syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
        AttributeDescription** descs;
@@ -1327,19 +1460,19 @@ int slap_mods_check_syncrepl(
        Modifications *ml = *mlp;
 
        while ( ml != NULL ) {
-                AttributeDescription *ad = NULL;
+               AttributeDescription *ad = NULL;
 
-                /* convert to attribute description */
-                rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, text );
+               /* convert to attribute description */
+               rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, text );
 
-                if( rc != LDAP_SUCCESS ) {
-                        snprintf( textbuf, textlen, "%s: %s",
-                                ml->sml_type.bv_val, *text );
-                        *text = textbuf;
-                        return rc;
-                }
+               if( rc != LDAP_SUCCESS ) {
+                       snprintf( textbuf, textlen, "%s: %s",
+                                               ml->sml_type.bv_val, *text );
+                       *text = textbuf;
+                       return rc;
+               }
 
-                ad = ml->sml_desc;
+               ad = ml->sml_desc;
 
                if ( si->lastmod == LASTMOD_REQ ) {
                        descs = del_descs_lastmod;
@@ -1363,312 +1496,298 @@ int slap_mods_check_syncrepl(
                        }
                }
 
-                if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
-                        && !slap_ad_is_binary( ad ))
-                {
-                        /* attribute requires binary transfer */
-                        snprintf( textbuf, textlen,
-                                "%s: requires ;binary transfer",
-                                ml->sml_type.bv_val );
-                        *text = textbuf;
-                        return LDAP_UNDEFINED_TYPE;
-                }
-
-                if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
-                        && slap_ad_is_binary( ad ))
-                {
-                        /* attribute requires binary transfer */
-                        snprintf( textbuf, textlen,
-                                "%s: disallows ;binary transfer",
-                                ml->sml_type.bv_val );
-                        *text = textbuf;
-                        return LDAP_UNDEFINED_TYPE;
-                }
-
-                if( slap_ad_is_tag_range( ad )) {
-                        /* attribute requires binary transfer */
-                        snprintf( textbuf, textlen,
-                                "%s: inappropriate use of tag range option",
-                                ml->sml_type.bv_val );
-                        *text = textbuf;
-                        return LDAP_UNDEFINED_TYPE;
-                }
-
-                if ( is_at_obsolete( ad->ad_type ) &&
-                        ( ml->sml_op == LDAP_MOD_ADD || ml->sml_values != NULL ) )
-                {
-                        /*
-                         * attribute is obsolete,
-                         * only allow replace/delete with no values
-                         */
-                        snprintf( textbuf, textlen,
-                                "%s: attribute is obsolete",
-                                ml->sml_type.bv_val );
-                        *text = textbuf;
-                        return LDAP_CONSTRAINT_VIOLATION;
-                }
-
-                /*
-                 * check values
-                 */
-                if( ml->sml_values != NULL ) {
-                        ber_len_t nvals;
-                        slap_syntax_validate_func *validate =
-                                ad->ad_type->sat_syntax->ssyn_validate;
-                        slap_syntax_transform_func *pretty =
-                                ad->ad_type->sat_syntax->ssyn_pretty;
-
-                               if( !pretty && !validate ) {
-                                       *text = "no validator for syntax";
-                                snprintf( textbuf, textlen,
-                                        "%s: no validator for syntax %s",
-                                        ml->sml_type.bv_val,
-                                        ad->ad_type->sat_syntax->ssyn_oid );
-                                *text = textbuf;
-                                return LDAP_INVALID_SYNTAX;
-                        }
-
-                        /*
-                         * check that each value is valid per syntax
-                         *      and pretty if appropriate
-                         */
-                        for( nvals = 0; ml->sml_values[nvals].bv_val; nvals++ ) {
-                                struct berval pval;
-                                if( pretty ) {
-                                        rc = pretty( ad->ad_type->sat_syntax,
-                                                &ml->sml_values[nvals], &pval,
-                                               ctx );
-                                } else {
-                                        rc = validate( ad->ad_type->sat_syntax,
-                                                &ml->sml_values[nvals] );
-                                }
-
-                                if( rc != 0 ) {
-                                        snprintf( textbuf, textlen,
-                                                "%s: value #%ld invalid per syntax",
-                                                ml->sml_type.bv_val, (long) nvals );
-                                        *text = textbuf;
-                                        return LDAP_INVALID_SYNTAX;
-                                }
-
-                                if( pretty ) {
-                                        ber_memfree( ml->sml_values[nvals].bv_val );
-                                        ml->sml_values[nvals] = pval;
-                                }
-                        }
-
-                        /*
-                         * a rough single value check... an additional check is needed
-                         * to catch add of single value to existing single valued attribute
-                         */
-                        if ((ml->sml_op == LDAP_MOD_ADD || ml->sml_op == LDAP_MOD_REPLACE)
-                                && nvals > 1 && is_at_single_value( ad->ad_type ))
-                        {
-                                snprintf( textbuf, textlen,
-                                        "%s: multiple values provided",
-                                        ml->sml_type.bv_val );
-                                *text = textbuf;
-                                return LDAP_CONSTRAINT_VIOLATION;
-                        }
-
-                        if( nvals && ad->ad_type->sat_equality &&
-                                ad->ad_type->sat_equality->smr_normalize )
-                        {
-                                ml->sml_nvalues = ch_malloc( (nvals+1)*sizeof(struct berval) );
-                                for( nvals = 0; ml->sml_values[nvals].bv_val; nvals++ ) {
-                                        rc = ad->ad_type->sat_equality->smr_normalize(
-                                                0,
-                                                ad->ad_type->sat_syntax,
-                                                ad->ad_type->sat_equality,
-                                                &ml->sml_values[nvals], &ml->sml_nvalues[nvals],
-                                               ctx );
-                                        if( rc ) {
+               if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
+                               && !slap_ad_is_binary( ad )) {
+                       /* attribute requires binary transfer */
+                       snprintf( textbuf, textlen,
+                                       "%s: requires ;binary transfer",
+                                       ml->sml_type.bv_val );
+                       *text = textbuf;
+                       return LDAP_UNDEFINED_TYPE;
+               }
+
+               if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
+                                       && slap_ad_is_binary( ad )) {
+                       /* attribute requires binary transfer */
+                       snprintf( textbuf, textlen,
+                                       "%s: disallows ;binary transfer",
+                                       ml->sml_type.bv_val );
+                       *text = textbuf;
+                       return LDAP_UNDEFINED_TYPE;
+               }
+
+               if( slap_ad_is_tag_range( ad )) {
+                       /* attribute requires binary transfer */
+                       snprintf( textbuf, textlen,
+                                       "%s: inappropriate use of tag range option",
+                                       ml->sml_type.bv_val );
+                       *text = textbuf;
+                       return LDAP_UNDEFINED_TYPE;
+               }
+
+               if ( is_at_obsolete( ad->ad_type ) &&
+                               ( ml->sml_op == LDAP_MOD_ADD || ml->sml_values != NULL ) ) {
+                       /*
+                        * attribute is obsolete,
+                        * only allow replace/delete with no values
+                        */
+                       snprintf( textbuf, textlen,
+                                       "%s: attribute is obsolete",
+                                       ml->sml_type.bv_val );
+                       *text = textbuf;
+                       return LDAP_CONSTRAINT_VIOLATION;
+               }
+
+               /*
+                * check values
+                */
+               if( ml->sml_values != NULL ) {
+                       ber_len_t nvals;
+                       slap_syntax_validate_func *validate =
+                       ad->ad_type->sat_syntax->ssyn_validate;
+                       slap_syntax_transform_func *pretty =
+                       ad->ad_type->sat_syntax->ssyn_pretty;
+
+                       if( !pretty && !validate ) {
+                               *text = "no validator for syntax";
+                               snprintf( textbuf, textlen,
+                                               "%s: no validator for syntax %s",
+                                               ml->sml_type.bv_val,
+                                               ad->ad_type->sat_syntax->ssyn_oid );
+                               *text = textbuf;
+                               return LDAP_INVALID_SYNTAX;
+                       }
+
+                       /*
+                        * check that each value is valid per syntax
+                        * and pretty if appropriate
+                        */
+                       for( nvals = 0; ml->sml_values[nvals].bv_val; nvals++ ) {
+                               struct berval pval = {0, NULL};
+                               if( pretty ) {
+                                       rc = pretty( ad->ad_type->sat_syntax,
+                                                       &ml->sml_values[nvals], &pval, ctx );
+                               } else {
+                                       rc = validate( ad->ad_type->sat_syntax,
+                                                       &ml->sml_values[nvals] );
+                               }
+
+                               if( rc != 0 ) {
+                                       snprintf( textbuf, textlen,
+                                                       "%s: value #%ld invalid per syntax",
+                                                       ml->sml_type.bv_val, (long) nvals );
+                                       *text = textbuf;
+                                       return LDAP_INVALID_SYNTAX;
+                               }
+
+                               if( pretty ) {
+                                       ber_memfree( ml->sml_values[nvals].bv_val );
+                                       ml->sml_values[nvals] = pval;
+                               }
+                       }
+
+                       /*
+                        * a rough single value check... an additional check is needed
+                        * to catch add of single value to existing single valued attribute
+                        */
+                       if ((ml->sml_op == LDAP_MOD_ADD || ml->sml_op == LDAP_MOD_REPLACE)
+                                       && nvals > 1 && is_at_single_value( ad->ad_type )) {
+                               snprintf( textbuf, textlen,
+                                               "%s: multiple values provided",
+                                               ml->sml_type.bv_val );
+                               *text = textbuf;
+                               return LDAP_CONSTRAINT_VIOLATION;
+                       }
+
+                       if( nvals && ad->ad_type->sat_equality &&
+                                       ad->ad_type->sat_equality->smr_normalize ) {
+                               ml->sml_nvalues = ch_malloc( (nvals+1)*sizeof(struct berval) );
+                               for( nvals = 0; ml->sml_values[nvals].bv_val; nvals++ ) {
+                                       rc = ad->ad_type->sat_equality->smr_normalize( 0,
+                                                       ad->ad_type->sat_syntax, ad->ad_type->sat_equality,
+                                                       &ml->sml_values[nvals], &ml->sml_nvalues[nvals], ctx );
+                                       if( rc ) {
 #ifdef NEW_LOGGING
-                                                LDAP_LOG( OPERATION, DETAIL1,
-                                                        "str2entry:  NULL (ssyn_normalize %d)\n",
-                                                        rc, 0, 0 );
+                                               LDAP_LOG( OPERATION, DETAIL1,
+                                                               "str2entry:  NULL (ssyn_normalize %d)\n", rc, 0, 0 );
 #else
-                                                Debug( LDAP_DEBUG_ANY,
-                                                        "<= str2entry NULL (ssyn_normalize %d)\n",
-                                                        rc, 0, 0 );
+                                               Debug( LDAP_DEBUG_ANY,
+                                                               "<= str2entry NULL (ssyn_normalize %d)\n", rc, 0, 0 );
 #endif
-                                                snprintf( textbuf, textlen,
-                                                        "%s: value #%ld normalization failed",
-                                                        ml->sml_type.bv_val, (long) nvals );
-                                                *text = textbuf;
-                                                return rc;
-                                        }
-                                }
-                                ml->sml_nvalues[nvals].bv_val = NULL;
-                                ml->sml_nvalues[nvals].bv_len = 0;
-                        }
-                }
+                                               snprintf( textbuf, textlen,
+                                                               "%s: value #%ld normalization failed",
+                                                               ml->sml_type.bv_val, (long) nvals );
+                                               *text = textbuf;
+                                               return rc;
+                                       }
+                               }
+                               ml->sml_nvalues[nvals].bv_val = NULL;
+                               ml->sml_nvalues[nvals].bv_len = 0;
+                       }
+               }
                prevml = ml;
                ml = ml->sml_next;
-        }
+       }
 
-        return LDAP_SUCCESS;
+       return LDAP_SUCCESS;
 }
 
 static
 int slap_mods_opattrs_syncrepl(
-        Operation *op,
-        Modifications *mods,
-        Modifications **modtail,
-        const char **text,
-        char *textbuf, size_t textlen )
+       Operation *op,
+       Modifications *mods,
+       Modifications **modtail,
+       const char **text,
+       char *textbuf, size_t textlen )
 {
-        struct berval name, timestamp, csn;
-        struct berval nname;
-        char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
-        char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
-        Modifications *mod;
+       struct berval name = {0, NULL};
+       struct berval timestamp = {0, NULL};
+       struct berval csn = {0, NULL};
+       struct berval nname = {0, NULL};
+       char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
+       char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
+       Modifications *mod;
        Backend *be = op->o_bd;
        syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
 
-    //    int mop = op->o_tag == LDAP_REQ_ADD ? LDAP_MOD_ADD : LDAP_MOD_REPLACE;
        int mop = LDAP_MOD_REPLACE;
 
-        assert( modtail != NULL );
-        assert( *modtail == NULL );
-
-        if( si->lastmod == LASTMOD_GEN ) {
-                struct tm *ltm;
-                time_t now = slap_get_time();
-
-                ldap_pvt_thread_mutex_lock( &gmtime_mutex );
-                ltm = gmtime( &now );
-                lutil_gentime( timebuf, sizeof(timebuf), ltm );
-
-                csn.bv_len = lutil_csnstr( csnbuf, sizeof( csnbuf ), 0, 0 );
-                ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
-                csn.bv_val = csnbuf;
-
-                timestamp.bv_val = timebuf;
-                timestamp.bv_len = strlen(timebuf);
-
-                if( op->o_dn.bv_len == 0 ) {
-                        name.bv_val = SLAPD_ANONYMOUS;
-                        name.bv_len = sizeof(SLAPD_ANONYMOUS)-1;
-                        nname = name;
-                } else {
-                        name = op->o_dn;
-                        nname = op->o_ndn;
-                }
-        }
-
-        if( op->o_tag == LDAP_REQ_ADD ) {
-                struct berval tmpval;
-
-                if( global_schemacheck ) {
-                        int rc = mods_structural_class( mods, &tmpval,
-                                text, textbuf, textlen );
-                        if( rc != LDAP_SUCCESS ) {
-                                return rc;
-                        }
-
-                        mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
+       assert( modtail != NULL );
+       assert( *modtail == NULL );
+
+       if( si->lastmod == LASTMOD_GEN ) {
+               struct tm *ltm;
+               time_t now = slap_get_time();
+
+               ldap_pvt_thread_mutex_lock( &gmtime_mutex );
+               ltm = gmtime( &now );
+               lutil_gentime( timebuf, sizeof(timebuf), ltm );
+
+               csn.bv_len = lutil_csnstr( csnbuf, sizeof( csnbuf ), 0, 0 );
+               ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
+               csn.bv_val = csnbuf;
+
+               timestamp.bv_val = timebuf;
+               timestamp.bv_len = strlen(timebuf);
+
+               if( op->o_dn.bv_len == 0 ) {
+                       name.bv_val = SLAPD_ANONYMOUS;
+                       name.bv_len = sizeof(SLAPD_ANONYMOUS)-1;
+                       nname = name;
+               } else {
+                       name = op->o_dn;
+                       nname = op->o_ndn;
+               }
+       }
+
+       if( op->o_tag == LDAP_REQ_ADD ) {
+               struct berval tmpval = {0, NULL};
+
+               if( global_schemacheck ) {
+                       int rc = mods_structural_class( mods, &tmpval,
+                                                                       text, textbuf, textlen );
+                       if( rc != LDAP_SUCCESS ) {
+                               return rc;
+                       }
+
+                       mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
                        mod->sml_op = mop;
-                        mod->sml_type.bv_val = NULL;
-                        mod->sml_desc = slap_schema.si_ad_structuralObjectClass;
-                        mod->sml_values =
-                                (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
-                        ber_dupbv( &mod->sml_values[0], &tmpval );
-                        mod->sml_values[1].bv_len = 0;
-                        mod->sml_values[1].bv_val = NULL;
-                        assert( mod->sml_values[0].bv_val );
-                        mod->sml_nvalues =
-                                (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
-                        ber_dupbv( &mod->sml_nvalues[0], &tmpval );
-                        mod->sml_nvalues[1].bv_len = 0;
-                        mod->sml_nvalues[1].bv_val = NULL;
-                        assert( mod->sml_nvalues[0].bv_val );
-                        *modtail = mod;
-                        modtail = &mod->sml_next;
-                }
-
-                if( si->lastmod == LASTMOD_GEN ) {
-                        mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
-                        mod->sml_op = mop;
-                        mod->sml_type.bv_val = NULL;
-                        mod->sml_desc = slap_schema.si_ad_creatorsName;
-                        mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
-                        ber_dupbv( &mod->sml_values[0], &name );
-                        mod->sml_values[1].bv_len = 0;
-                        mod->sml_values[1].bv_val = NULL;
-                        assert( mod->sml_values[0].bv_val );
-                        mod->sml_nvalues =
-                                (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
-                        ber_dupbv( &mod->sml_nvalues[0], &nname );
-                        mod->sml_nvalues[1].bv_len = 0;
-                        mod->sml_nvalues[1].bv_val = NULL;
-                        assert( mod->sml_nvalues[0].bv_val );
-                        *modtail = mod;
-                        modtail = &mod->sml_next;
-
-                        mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
-                        mod->sml_op = mop;
-                        mod->sml_type.bv_val = NULL;
-                        mod->sml_desc = slap_schema.si_ad_createTimestamp;
-                        mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
-                        ber_dupbv( &mod->sml_values[0], &timestamp );
-                        mod->sml_values[1].bv_len = 0;
-                        mod->sml_values[1].bv_val = NULL;
-                        assert( mod->sml_values[0].bv_val );
-                        mod->sml_nvalues = NULL;
-                        *modtail = mod;
-                        modtail = &mod->sml_next;
-                }
-        }
-
-        if( si->lastmod == LASTMOD_GEN ) {
-                mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
-                mod->sml_op = mop;
-                mod->sml_type.bv_val = NULL;
-                mod->sml_desc = slap_schema.si_ad_entryCSN;
-                mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
-                ber_dupbv( &mod->sml_values[0], &csn );
-                mod->sml_values[1].bv_len = 0;
-                mod->sml_values[1].bv_val = NULL;
-                assert( mod->sml_values[0].bv_val );
-                mod->sml_nvalues = NULL;
-                *modtail = mod;
-                modtail = &mod->sml_next;
-
-                mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
-                mod->sml_op = mop;
-                mod->sml_type.bv_val = NULL;
-                mod->sml_desc = slap_schema.si_ad_modifiersName;
-                mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
-                ber_dupbv( &mod->sml_values[0], &name );
-                mod->sml_values[1].bv_len = 0;
-                mod->sml_values[1].bv_val = NULL;
-                assert( mod->sml_values[0].bv_val );
-                mod->sml_nvalues =
-                        (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
-                ber_dupbv( &mod->sml_nvalues[0], &nname );
-                mod->sml_nvalues[1].bv_len = 0;
-                mod->sml_nvalues[1].bv_val = NULL;
-                assert( mod->sml_nvalues[0].bv_val );
-                *modtail = mod;
-                modtail = &mod->sml_next;
-
-                mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
-                mod->sml_op = mop;
-                mod->sml_type.bv_val = NULL;
-                mod->sml_desc = slap_schema.si_ad_modifyTimestamp;
-                mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
-                ber_dupbv( &mod->sml_values[0], &timestamp );
-                mod->sml_values[1].bv_len = 0;
-                mod->sml_values[1].bv_val = NULL;
-                assert( mod->sml_values[0].bv_val );
-                mod->sml_nvalues = NULL;
-                *modtail = mod;
-                modtail = &mod->sml_next;
-        }
-
-        *modtail = NULL;
-        return LDAP_SUCCESS;
+                       mod->sml_type.bv_val = NULL;
+                       mod->sml_desc = slap_schema.si_ad_structuralObjectClass;
+                       mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+                       ber_dupbv( &mod->sml_values[0], &tmpval );
+                       mod->sml_values[1].bv_len = 0;
+                       mod->sml_values[1].bv_val = NULL;
+                       assert( mod->sml_values[0].bv_val );
+                       mod->sml_nvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+                       ber_dupbv( &mod->sml_nvalues[0], &tmpval );
+                       mod->sml_nvalues[1].bv_len = 0;
+                       mod->sml_nvalues[1].bv_val = NULL;
+                       assert( mod->sml_nvalues[0].bv_val );
+                       *modtail = mod;
+                       modtail = &mod->sml_next;
+               }
+
+               if( si->lastmod == LASTMOD_GEN ) {
+                       mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
+                       mod->sml_op = mop;
+                       mod->sml_type.bv_val = NULL;
+                       mod->sml_desc = slap_schema.si_ad_creatorsName;
+                       mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+                       ber_dupbv( &mod->sml_values[0], &name );
+                       mod->sml_values[1].bv_len = 0;
+                       mod->sml_values[1].bv_val = NULL;
+                       assert( mod->sml_values[0].bv_val );
+                       mod->sml_nvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+                       ber_dupbv( &mod->sml_nvalues[0], &nname );
+                       mod->sml_nvalues[1].bv_len = 0;
+                       mod->sml_nvalues[1].bv_val = NULL;
+                       assert( mod->sml_nvalues[0].bv_val );
+                       *modtail = mod;
+                       modtail = &mod->sml_next;
+
+                       mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
+                       mod->sml_op = mop;
+                       mod->sml_type.bv_val = NULL;
+                       mod->sml_desc = slap_schema.si_ad_createTimestamp;
+                       mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+                       ber_dupbv( &mod->sml_values[0], &timestamp );
+                       mod->sml_values[1].bv_len = 0;
+                       mod->sml_values[1].bv_val = NULL;
+                       assert( mod->sml_values[0].bv_val );
+                       mod->sml_nvalues = NULL;
+                       *modtail = mod;
+                       modtail = &mod->sml_next;
+               }
+       }
+
+       if( si->lastmod == LASTMOD_GEN ) {
+               mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
+               mod->sml_op = mop;
+               mod->sml_type.bv_val = NULL;
+               mod->sml_desc = slap_schema.si_ad_entryCSN;
+               mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+               ber_dupbv( &mod->sml_values[0], &csn );
+               mod->sml_values[1].bv_len = 0;
+               mod->sml_values[1].bv_val = NULL;
+               assert( mod->sml_values[0].bv_val );
+               mod->sml_nvalues = NULL;
+               *modtail = mod;
+               modtail = &mod->sml_next;
+
+               mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
+               mod->sml_op = mop;
+               mod->sml_type.bv_val = NULL;
+               mod->sml_desc = slap_schema.si_ad_modifiersName;
+               mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+               ber_dupbv( &mod->sml_values[0], &name );
+               mod->sml_values[1].bv_len = 0;
+               mod->sml_values[1].bv_val = NULL;
+               assert( mod->sml_values[0].bv_val );
+               mod->sml_nvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+               ber_dupbv( &mod->sml_nvalues[0], &nname );
+               mod->sml_nvalues[1].bv_len = 0;
+               mod->sml_nvalues[1].bv_val = NULL;
+               assert( mod->sml_nvalues[0].bv_val );
+               *modtail = mod;
+               modtail = &mod->sml_next;
+
+               mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
+               mod->sml_op = mop;
+               mod->sml_type.bv_val = NULL;
+               mod->sml_desc = slap_schema.si_ad_modifyTimestamp;
+               mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+               ber_dupbv( &mod->sml_values[0], &timestamp );
+               mod->sml_values[1].bv_len = 0;
+               mod->sml_values[1].bv_val = NULL;
+               assert( mod->sml_values[0].bv_val );
+               mod->sml_nvalues = NULL;
+               *modtail = mod;
+               modtail = &mod->sml_next;
+       }
+
+       *modtail = NULL;
+       return LDAP_SUCCESS;
 }
 
 
@@ -1828,6 +1947,21 @@ cookie_callback(
        return LDAP_SUCCESS;
 }
 
+static int
+dn_callback(
+       Operation*      op,
+       SlapReply*      rs
+)
+{
+       syncinfo_t *si = op->o_callback->sc_private;
+       
+       if ( rs->sr_type == REP_SEARCH ) {
+               si->syncUUID_ndn = &rs->sr_entry->e_nname;
+       }
+
+       return LDAP_SUCCESS;
+}
+
 static int
 nonpresent_callback(
        Operation*      op,
@@ -1840,6 +1974,7 @@ nonpresent_callback(
        struct berval* present_uuid = NULL;
        slap_callback cb;
        SlapReply       rs_cb = {REP_RESULT};
+       struct nonpresent_entry *np_entry;
 
        if ( rs->sr_type == REP_RESULT ) {
                count = avl_free( si->presentlist, avl_ber_bvfree );
@@ -1850,17 +1985,14 @@ nonpresent_callback(
                if ( a == NULL )
                        return 0;
 
-               present_uuid = avl_find( si->presentlist,
-                                       &a->a_vals[0], syncuuid_cmp );
-       
+               present_uuid = avl_find( si->presentlist, &a->a_vals[0], syncuuid_cmp );
+
                if ( present_uuid == NULL ) {
-                       op->o_tag = LDAP_REQ_DELETE;
-                       op->o_callback = &cb;
-                       cb.sc_response = null_callback;
-                       cb.sc_private = si;
-                       op->o_req_dn = rs->sr_entry->e_name;
-                       op->o_req_ndn = rs->sr_entry->e_nname;
-                       op->o_bd->be_delete( op, &rs_cb );
+                       np_entry = (struct nonpresent_entry *)
+                                               ch_calloc( 1, sizeof( struct nonpresent_entry ));
+                       np_entry->dn = ber_dupbv( NULL, &rs->sr_entry->e_name );
+                       np_entry->ndn = ber_dupbv( NULL, &rs->sr_entry->e_nname );
+                       LDAP_LIST_INSERT_HEAD( &si->nonpresentlist, np_entry, np_link );
                } else {
                        avl_delete( &si->presentlist,
                                        &a->a_vals[0], syncuuid_cmp );
@@ -1879,10 +2011,10 @@ null_callback(
 )
 {
        if ( rs->sr_err != LDAP_SUCCESS &&
-            rs->sr_err != LDAP_REFERRAL &&
-            rs->sr_err != LDAP_ALREADY_EXISTS &&
-            rs->sr_err != LDAP_NO_SUCH_OBJECT &&
-            rs->sr_err != DB_NOTFOUND ) {
+                rs->sr_err != LDAP_REFERRAL &&
+                rs->sr_err != LDAP_ALREADY_EXISTS &&
+                rs->sr_err != LDAP_NO_SUCH_OBJECT &&
+                rs->sr_err != DB_NOTFOUND ) {
 #ifdef NEW_LOGGING
                LDAP_LOG( OPERATION, ERR,
                        "null_callback : error code 0x%x\n",
@@ -1890,10 +2022,50 @@ null_callback(
 #else
                Debug( LDAP_DEBUG_ANY,
                        "null_callback : error code 0x%x\n",
-                       rs->sr_err, 0, 0 );
+                       rs->sr_err, 0, 0 );
 #endif
        }
        return LDAP_SUCCESS;
 }
 
+
+char **
+str2clist( char **out, char *in, const char *brkstr )
+{
+       char    *str;
+       char    *s;
+       char    *lasts;
+       int     i, j;
+       const char *text;
+       char    **new;
+
+       /* find last element in list */
+       for (i = 0; out && out[i]; i++);
+       
+       /* protect the input string from strtok */
+       str = ch_strdup( in );
+
+       /* Count words in string */
+       j=1;
+       for ( s = str; *s; s++ ) {
+               if ( strchr( brkstr, *s ) != NULL ) {
+                       j++;
+               }
+       }
+
+       out = ch_realloc( out, ( i + j + 1 ) * sizeof( char * ) );
+       new = out + i;
+       for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
+               s != NULL;
+               s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
+       {
+               *new = ch_strdup( s );
+               new++;
+       }
+
+       *new = NULL;
+       free( str );
+       return( out );
+}
+
 #endif