Back to index

openldap  2.4.31
syncrepl.c
Go to the documentation of this file.
00001 /* syncrepl.c -- Replication Engine which uses the LDAP Sync protocol */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2003-2012 The OpenLDAP Foundation.
00006  * Portions Copyright 2003 by IBM Corporation.
00007  * Portions Copyright 2003-2008 by Howard Chu, Symas Corporation.
00008  * All rights reserved.
00009  *
00010  * Redistribution and use in source and binary forms, with or without
00011  * modification, are permitted only as authorized by the OpenLDAP
00012  * Public License.
00013  *
00014  * A copy of this license is available in the file LICENSE in the
00015  * top-level directory of the distribution or, alternatively, at
00016  * <http://www.OpenLDAP.org/license.html>.
00017  */
00018 
00019 #include "portable.h"
00020 
00021 #include <stdio.h>
00022 
00023 #include <ac/string.h>
00024 #include <ac/socket.h>
00025 
00026 #include "lutil.h"
00027 #include "slap.h"
00028 #include "lutil_ldap.h"
00029 
00030 #include "config.h"
00031 
00032 #include "ldap_rq.h"
00033 
00034 #ifdef ENABLE_REWRITE
00035 #include "rewrite.h"
00036 #define SUFFIXM_CTX  "<suffix massage>"
00037 #endif
00038 
00039 struct nonpresent_entry {
00040        struct berval *npe_name;
00041        struct berval *npe_nname;
00042        LDAP_LIST_ENTRY(nonpresent_entry) npe_link;
00043 };
00044 
00045 typedef struct cookie_state {
00046        ldap_pvt_thread_mutex_t     cs_mutex;
00047        struct berval *cs_vals;
00048        int *cs_sids;
00049        int    cs_num;
00050        int cs_age;
00051        int cs_ref;
00052 
00053        /* pending changes, not yet committed */
00054        ldap_pvt_thread_mutex_t     cs_pmutex;
00055        struct berval *cs_pvals;
00056        int *cs_psids;
00057        int    cs_pnum;
00058 } cookie_state;
00059 
00060 #define       SYNCDATA_DEFAULT     0      /* entries are plain LDAP entries */
00061 #define       SYNCDATA_ACCESSLOG   1      /* entries are accesslog format */
00062 #define       SYNCDATA_CHANGELOG   2      /* entries are changelog format */
00063 
00064 #define       SYNCLOG_LOGGING             0      /* doing a log-based update */
00065 #define       SYNCLOG_FALLBACK     1      /* doing a full refresh */
00066 
00067 #define RETRYNUM_FOREVER    (-1)   /* retry forever */
00068 #define RETRYNUM_TAIL              (-2)   /* end of retrynum array */
00069 #define RETRYNUM_VALID(n)   ((n) >= RETRYNUM_FOREVER)   /* valid retrynum */
00070 #define RETRYNUM_FINITE(n)  ((n) > RETRYNUM_FOREVER)    /* not forever */
00071 
00072 typedef struct syncinfo_s {
00073        struct syncinfo_s    *si_next;
00074        BackendDB            *si_be;
00075        BackendDB            *si_wbe;
00076        struct re_s          *si_re;
00077        int                  si_rid;
00078        char                 si_ridtxt[ STRLENOF("rid=999") + 1 ];
00079        slap_bindconf        si_bindconf;
00080        struct berval        si_base;
00081        struct berval        si_logbase;
00082        struct berval        si_filterstr;
00083        Filter               *si_filter;
00084        struct berval        si_logfilterstr;
00085        struct berval        si_contextdn;
00086        int                  si_scope;
00087        int                  si_attrsonly;
00088        char                 *si_anfile;
00089        AttributeName        *si_anlist;
00090        AttributeName        *si_exanlist;
00091        char                 **si_attrs;
00092        char                 **si_exattrs;
00093        int                  si_allattrs;
00094        int                  si_allopattrs;
00095        int                  si_schemachecking;
00096        int                  si_type;      /* the active type */
00097        int                  si_ctype;     /* the configured type */
00098        time_t               si_interval;
00099        time_t               *si_retryinterval;
00100        int                  *si_retrynum_init;
00101        int                  *si_retrynum;
00102        struct sync_cookie   si_syncCookie;
00103        cookie_state         *si_cookieState;
00104        int                  si_cookieAge;
00105        int                  si_manageDSAit;
00106        int                  si_slimit;
00107        int                  si_tlimit;
00108        int                  si_refreshDelete;
00109        int                  si_refreshPresent;
00110        int                  si_refreshDone;
00111        int                  si_syncdata;
00112        int                  si_logstate;
00113        int                  si_got;
00114        int                  si_strict_refresh;   /* stop listening during fallback refresh */
00115        ber_int_t     si_msgid;
00116        Avlnode                     *si_presentlist;
00117        LDAP                 *si_ld;
00118        Connection           *si_conn;
00119        LDAP_LIST_HEAD(np, nonpresent_entry)      si_nonpresentlist;
00120 #ifdef ENABLE_REWRITE
00121        struct rewrite_info *si_rewrite;
00122        struct berval si_suffixm;
00123 #endif
00124        ldap_pvt_thread_mutex_t     si_mutex;
00125 } syncinfo_t;
00126 
00127 static int syncuuid_cmp( const void *, const void * );
00128 static int avl_presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
00129 static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
00130 static int syncrepl_message_to_op(
00131                                    syncinfo_t *, Operation *, LDAPMessage * );
00132 static int syncrepl_message_to_entry(
00133                                    syncinfo_t *, Operation *, LDAPMessage *,
00134                                    Modifications **, Entry **, int, struct berval* );
00135 static int syncrepl_entry(
00136                                    syncinfo_t *, Operation*, Entry*,
00137                                    Modifications**,int, struct berval*,
00138                                    struct berval *cookieCSN );
00139 static int syncrepl_updateCookie(
00140                                    syncinfo_t *, Operation *,
00141                                    struct sync_cookie * );
00142 static struct berval * slap_uuidstr_from_normalized(
00143                                    struct berval *, struct berval *, void * );
00144 static int syncrepl_add_glue_ancestors(
00145        Operation* op, Entry *e );
00146 
00147 /* delta-mmr overlay handler */
00148 static int syncrepl_op_modify( Operation *op, SlapReply *rs );
00149 
00150 /* callback functions */
00151 static int dn_callback( Operation *, SlapReply * );
00152 static int nonpresent_callback( Operation *, SlapReply * );
00153 static int null_callback( Operation *, SlapReply * );
00154 
00155 static AttributeDescription *sync_descs[4];
00156 
00157 /* delta-mmr */
00158 static AttributeDescription *ad_reqMod, *ad_reqDN;
00159 
00160 typedef struct logschema {
00161        struct berval ls_dn;
00162        struct berval ls_req;
00163        struct berval ls_mod;
00164        struct berval ls_newRdn;
00165        struct berval ls_delRdn;
00166        struct berval ls_newSup;
00167 } logschema;
00168 
00169 static logschema changelog_sc = {
00170        BER_BVC("targetDN"),
00171        BER_BVC("changeType"),
00172        BER_BVC("changes"),
00173        BER_BVC("newRDN"),
00174        BER_BVC("deleteOldRDN"),
00175        BER_BVC("newSuperior")
00176 };
00177 
00178 static logschema accesslog_sc = {
00179        BER_BVC("reqDN"),
00180        BER_BVC("reqType"),
00181        BER_BVC("reqMod"),
00182        BER_BVC("reqNewRDN"),
00183        BER_BVC("reqDeleteOldRDN"),
00184        BER_BVC("reqNewSuperior")
00185 };
00186 
00187 static const char *
00188 syncrepl_state2str( int state )
00189 {
00190        switch ( state ) {
00191        case LDAP_SYNC_PRESENT:
00192               return "PRESENT";
00193 
00194        case LDAP_SYNC_ADD:
00195               return "ADD";
00196 
00197        case LDAP_SYNC_MODIFY:
00198               return "MODIFY";
00199 
00200        case LDAP_SYNC_DELETE:
00201               return "DELETE";
00202        }
00203 
00204        return "UNKNOWN";
00205 }
00206 
00207 static slap_overinst syncrepl_ov;
00208 
00209 static void
00210 init_syncrepl(syncinfo_t *si)
00211 {
00212        int i, j, k, l, n;
00213        char **attrs, **exattrs;
00214 
00215        if ( !syncrepl_ov.on_bi.bi_type ) {
00216               syncrepl_ov.on_bi.bi_type = "syncrepl";
00217               syncrepl_ov.on_bi.bi_op_modify = syncrepl_op_modify;
00218               overlay_register( &syncrepl_ov );
00219        }
00220 
00221        /* delta-MMR needs the overlay, nothing else does.
00222         * This must happen before accesslog overlay is configured.
00223         */
00224        if ( si->si_syncdata &&
00225               !overlay_is_inst( si->si_be, syncrepl_ov.on_bi.bi_type )) {
00226               overlay_config( si->si_be, syncrepl_ov.on_bi.bi_type, -1, NULL, NULL );
00227               if ( !ad_reqMod ) {
00228                      const char *text;
00229                      logschema *ls = &accesslog_sc;
00230 
00231                      slap_bv2ad( &ls->ls_mod, &ad_reqMod, &text );
00232                      slap_bv2ad( &ls->ls_dn, &ad_reqDN, &text );
00233               }
00234        }
00235 
00236        if ( !sync_descs[0] ) {
00237               sync_descs[0] = slap_schema.si_ad_objectClass;
00238               sync_descs[1] = slap_schema.si_ad_structuralObjectClass;
00239               sync_descs[2] = slap_schema.si_ad_entryCSN;
00240               sync_descs[3] = NULL;
00241        }
00242 
00243        if ( si->si_allattrs && si->si_allopattrs )
00244               attrs = NULL;
00245        else
00246               attrs = anlist2attrs( si->si_anlist );
00247 
00248        if ( attrs ) {
00249               if ( si->si_allattrs ) {
00250                      i = 0;
00251                      while ( attrs[i] ) {
00252                             if ( !is_at_operational( at_find( attrs[i] ) ) ) {
00253                                    for ( j = i; attrs[j] != NULL; j++ ) {
00254                                           if ( j == i )
00255                                                  ch_free( attrs[i] );
00256                                           attrs[j] = attrs[j+1];
00257                                    }
00258                             } else {
00259                                    i++;
00260                             }
00261                      }
00262                      attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
00263                      attrs[i] = ch_strdup("*");
00264                      attrs[i + 1] = NULL;
00265 
00266               } else if ( si->si_allopattrs ) {
00267                      i = 0;
00268                      while ( attrs[i] ) {
00269                             if ( is_at_operational( at_find( attrs[i] ) ) ) {
00270                                    for ( j = i; attrs[j] != NULL; j++ ) {
00271                                           if ( j == i )
00272                                                  ch_free( attrs[i] );
00273                                           attrs[j] = attrs[j+1];
00274                                    }
00275                             } else {
00276                                    i++;
00277                             }
00278                      }
00279                      attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
00280                      attrs[i] = ch_strdup("+");
00281                      attrs[i + 1] = NULL;
00282               }
00283 
00284               for ( i = 0; sync_descs[i] != NULL; i++ ) {
00285                      j = 0;
00286                      while ( attrs[j] ) {
00287                             if ( !strcmp( attrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
00288                                    for ( k = j; attrs[k] != NULL; k++ ) {
00289                                           if ( k == j )
00290                                                  ch_free( attrs[k] );
00291                                           attrs[k] = attrs[k+1];
00292                                    }
00293                             } else {
00294                                    j++;
00295                             }
00296                      }
00297               }
00298 
00299               for ( n = 0; attrs[ n ] != NULL; n++ ) /* empty */;
00300 
00301               if ( si->si_allopattrs ) {
00302                      attrs = ( char ** ) ch_realloc( attrs, (n + 2)*sizeof( char * ) );
00303               } else {
00304                      attrs = ( char ** ) ch_realloc( attrs, (n + 4)*sizeof( char * ) );
00305               }
00306 
00307               /* Add Attributes */
00308               if ( si->si_allopattrs ) {
00309                      attrs[n++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
00310               } else {
00311                      for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
00312                             attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
00313                      }
00314               }
00315               attrs[ n ] = NULL;
00316 
00317        } else {
00318 
00319               i = 0;
00320               if ( si->si_allattrs == si->si_allopattrs ) {
00321                      attrs = (char**) ch_malloc( 3 * sizeof(char*) );
00322                      attrs[i++] = ch_strdup( "*" );
00323                      attrs[i++] = ch_strdup( "+" );
00324               } else if ( si->si_allattrs && !si->si_allopattrs ) {
00325                      for ( n = 0; sync_descs[ n ] != NULL; n++ ) ;
00326                      attrs = (char**) ch_malloc( (n+1)* sizeof(char*) );
00327                      attrs[i++] = ch_strdup( "*" );
00328                      for ( j = 1; sync_descs[ j ] != NULL; j++ ) {
00329                             attrs[i++] = ch_strdup ( sync_descs[j]->ad_cname.bv_val );
00330                      }
00331               } else if ( !si->si_allattrs && si->si_allopattrs ) {
00332                      attrs = (char**) ch_malloc( 3 * sizeof(char*) );
00333                      attrs[i++] = ch_strdup( "+" );
00334                      attrs[i++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
00335               }
00336               attrs[i] = NULL;
00337        }
00338        
00339        si->si_attrs = attrs;
00340 
00341        exattrs = anlist2attrs( si->si_exanlist );
00342 
00343        if ( exattrs ) {
00344               for ( n = 0; exattrs[n] != NULL; n++ ) ;
00345 
00346               for ( i = 0; sync_descs[i] != NULL; i++ ) {
00347                      j = 0;
00348                      while ( exattrs[j] != NULL ) {
00349                             if ( !strcmp( exattrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
00350                                    ch_free( exattrs[j] );
00351                                    for ( k = j; exattrs[k] != NULL; k++ ) {
00352                                           exattrs[k] = exattrs[k+1];
00353                                    }
00354                             } else {
00355                                    j++;
00356                             }
00357                      }
00358               }
00359 
00360               for ( i = 0; exattrs[i] != NULL; i++ ) {
00361                      for ( j = 0; si->si_anlist[j].an_name.bv_val; j++ ) {
00362                             ObjectClass   *oc;
00363                             if ( ( oc = si->si_anlist[j].an_oc ) ) {
00364                                    k = 0;
00365                                    while ( oc->soc_required[k] ) {
00366                                           if ( !strcmp( exattrs[i],
00367                                                   oc->soc_required[k]->sat_cname.bv_val ) ) {
00368                                                  ch_free( exattrs[i] );
00369                                                  for ( l = i; exattrs[l]; l++ ) {
00370                                                         exattrs[l] = exattrs[l+1];
00371                                                  }
00372                                           } else {
00373                                                  k++;
00374                                           }
00375                                    }
00376                             }
00377                      }
00378               }
00379 
00380               for ( i = 0; exattrs[i] != NULL; i++ ) ;
00381 
00382               if ( i != n )
00383                      exattrs = (char **) ch_realloc( exattrs, (i + 1)*sizeof(char *) );
00384        }
00385 
00386        si->si_exattrs = exattrs;   
00387 }
00388 
00389 static int
00390 ldap_sync_search(
00391        syncinfo_t *si,
00392        void *ctx )
00393 {
00394        BerElementBuffer berbuf;
00395        BerElement *ber = (BerElement *)&berbuf;
00396        LDAPControl c[3], *ctrls[4];
00397        int rc;
00398        int rhint;
00399        char *base;
00400        char **attrs, *lattrs[8];
00401        char *filter;
00402        int attrsonly;
00403        int scope;
00404 
00405        /* setup LDAP SYNC control */
00406        ber_init2( ber, NULL, LBER_USE_DER );
00407        ber_set_option( ber, LBER_OPT_BER_MEMCTX, &ctx );
00408 
00409        /* If we're using a log but we have no state, then fallback to
00410         * normal mode for a full refresh.
00411         */
00412        if ( si->si_syncdata && !si->si_syncCookie.numcsns ) {
00413               si->si_logstate = SYNCLOG_FALLBACK;
00414        }
00415 
00416        /* Use the log parameters if we're in log mode */
00417        if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
00418               logschema *ls;
00419               if ( si->si_syncdata == SYNCDATA_ACCESSLOG )
00420                      ls = &accesslog_sc;
00421               else
00422                      ls = &changelog_sc;
00423               lattrs[0] = ls->ls_dn.bv_val;
00424               lattrs[1] = ls->ls_req.bv_val;
00425               lattrs[2] = ls->ls_mod.bv_val;
00426               lattrs[3] = ls->ls_newRdn.bv_val;
00427               lattrs[4] = ls->ls_delRdn.bv_val;
00428               lattrs[5] = ls->ls_newSup.bv_val;
00429               lattrs[6] = slap_schema.si_ad_entryCSN->ad_cname.bv_val;
00430               lattrs[7] = NULL;
00431 
00432               rhint = 0;
00433               base = si->si_logbase.bv_val;
00434               filter = si->si_logfilterstr.bv_val;
00435               attrs = lattrs;
00436               attrsonly = 0;
00437               scope = LDAP_SCOPE_SUBTREE;
00438        } else {
00439               rhint = 1;
00440               base = si->si_base.bv_val;
00441               filter = si->si_filterstr.bv_val;
00442               attrs = si->si_attrs;
00443               attrsonly = si->si_attrsonly;
00444               scope = si->si_scope;
00445        }
00446        if ( si->si_syncdata && si->si_logstate == SYNCLOG_FALLBACK ) {
00447               si->si_type = LDAP_SYNC_REFRESH_ONLY;
00448        } else {
00449               si->si_type = si->si_ctype;
00450        }
00451 
00452        if ( !BER_BVISNULL( &si->si_syncCookie.octet_str ) )
00453        {
00454               ber_printf( ber, "{eOb}",
00455                      abs(si->si_type), &si->si_syncCookie.octet_str, rhint );
00456        } else {
00457               ber_printf( ber, "{eb}",
00458                      abs(si->si_type), rhint );
00459        }
00460 
00461        if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
00462               ber_free_buf( ber );
00463               return rc;
00464        }
00465 
00466        c[0].ldctl_oid = LDAP_CONTROL_SYNC;
00467        c[0].ldctl_iscritical = si->si_type < 0;
00468        ctrls[0] = &c[0];
00469 
00470        c[1].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
00471        BER_BVZERO( &c[1].ldctl_value );
00472        c[1].ldctl_iscritical = 1;
00473        ctrls[1] = &c[1];
00474 
00475        if ( !BER_BVISNULL( &si->si_bindconf.sb_authzId ) ) {
00476               c[2].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
00477               c[2].ldctl_value = si->si_bindconf.sb_authzId;
00478               c[2].ldctl_iscritical = 1;
00479               ctrls[2] = &c[2];
00480               ctrls[3] = NULL;
00481        } else {
00482               ctrls[2] = NULL;
00483        }
00484 
00485        rc = ldap_search_ext( si->si_ld, base, scope, filter, attrs, attrsonly,
00486               ctrls, NULL, NULL, si->si_slimit, &si->si_msgid );
00487        ber_free_buf( ber );
00488        return rc;
00489 }
00490 
00491 static int
00492 check_syncprov(
00493        Operation *op,
00494        syncinfo_t *si )
00495 {
00496        AttributeName at[2];
00497        Attribute a = {0};
00498        Entry e = {0};
00499        SlapReply rs = {REP_SEARCH};
00500        int i, j, changed = 0;
00501 
00502        /* Look for contextCSN from syncprov overlay. If
00503         * there's no overlay, this will be a no-op. That means
00504         * this is a pure consumer, so local changes will not be
00505         * allowed, and all changes will already be reflected in
00506         * the cookieState.
00507         */
00508        a.a_desc = slap_schema.si_ad_contextCSN;
00509        e.e_attrs = &a;
00510        e.e_name = si->si_contextdn;
00511        e.e_nname = si->si_contextdn;
00512        at[0].an_name = a.a_desc->ad_cname;
00513        at[0].an_desc = a.a_desc;
00514        BER_BVZERO( &at[1].an_name );
00515        rs.sr_entry = &e;
00516        rs.sr_flags = REP_ENTRY_MODIFIABLE;
00517        rs.sr_attrs = at;
00518        op->o_req_dn = e.e_name;
00519        op->o_req_ndn = e.e_nname;
00520 
00521        ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
00522        i = backend_operational( op, &rs );
00523        if ( i == LDAP_SUCCESS && a.a_nvals ) {
00524               int num = a.a_numvals;
00525               /* check for differences */
00526               if ( num != si->si_cookieState->cs_num ) {
00527                      changed = 1;
00528               } else {
00529                      for ( i=0; i<num; i++ ) {
00530                             if ( ber_bvcmp( &a.a_nvals[i],
00531                                    &si->si_cookieState->cs_vals[i] )) {
00532                                    changed = 1;
00533                                    break;
00534                             }
00535                      }
00536               }
00537               if ( changed ) {
00538                      ber_bvarray_free( si->si_cookieState->cs_vals );
00539                      ch_free( si->si_cookieState->cs_sids );
00540                      si->si_cookieState->cs_num = num;
00541                      si->si_cookieState->cs_vals = a.a_nvals;
00542                      si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_nvals,
00543                             num, NULL );
00544                      si->si_cookieState->cs_age++;
00545               } else {
00546                      ber_bvarray_free( a.a_nvals );
00547               }
00548               ber_bvarray_free( a.a_vals );
00549        }
00550        /* See if the cookieState has changed due to anything outside
00551         * this particular consumer. That includes other consumers in
00552         * the same context, or local changes detected above.
00553         */
00554        if ( si->si_cookieState->cs_num > 0 && si->si_cookieAge !=
00555               si->si_cookieState->cs_age ) {
00556               if ( !si->si_syncCookie.numcsns ) {
00557                      ber_bvarray_free( si->si_syncCookie.ctxcsn );
00558                      ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
00559                             si->si_cookieState->cs_vals, NULL );
00560                      changed = 1;
00561               } else {
00562                      for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) {
00563                             /* bogus, just dup everything */
00564                             if ( si->si_syncCookie.sids[i] == -1 ) {
00565                                    ber_bvarray_free( si->si_syncCookie.ctxcsn );
00566                                    ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
00567                                           si->si_cookieState->cs_vals, NULL );
00568                                    changed = 1;
00569                                    break;
00570                             }
00571                             for (j=0; j<si->si_cookieState->cs_num; j++) {
00572                                    if ( si->si_syncCookie.sids[i] !=
00573                                           si->si_cookieState->cs_sids[j] )
00574                                           continue;
00575                                    if ( bvmatch( &si->si_syncCookie.ctxcsn[i],
00576                                           &si->si_cookieState->cs_vals[j] ))
00577                                           break;
00578                                    ber_bvreplace( &si->si_syncCookie.ctxcsn[i],
00579                                           &si->si_cookieState->cs_vals[j] );
00580                                    changed = 1;
00581                                    break;
00582                             }
00583                      }
00584               }
00585        }
00586        if ( changed ) {
00587               si->si_cookieAge = si->si_cookieState->cs_age;
00588               ch_free( si->si_syncCookie.octet_str.bv_val );
00589               slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
00590                      si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
00591                      si->si_syncCookie.sid );
00592               slap_parse_sync_cookie( &si->si_syncCookie, NULL );
00593        }
00594        ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
00595        return changed;
00596 }
00597 
00598 static int
00599 do_syncrep1(
00600        Operation *op,
00601        syncinfo_t *si )
00602 {
00603        int    rc;
00604        int cmdline_cookie_found = 0;
00605 
00606        struct sync_cookie   *sc = NULL;
00607 #ifdef HAVE_TLS
00608        void   *ssl;
00609 #endif
00610 
00611        rc = slap_client_connect( &si->si_ld, &si->si_bindconf );
00612        if ( rc != LDAP_SUCCESS ) {
00613               goto done;
00614        }
00615        op->o_protocol = LDAP_VERSION3;
00616 
00617        /* Set SSF to strongest of TLS, SASL SSFs */
00618        op->o_sasl_ssf = 0;
00619        op->o_tls_ssf = 0;
00620        op->o_transport_ssf = 0;
00621 #ifdef HAVE_TLS
00622        if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl )
00623               == LDAP_SUCCESS && ssl != NULL )
00624        {
00625               op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
00626        }
00627 #endif /* HAVE_TLS */
00628        {
00629               ber_len_t ssf; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought
00630                                             to use sasl_ssf_t but currently uses ber_len_t */
00631               if ( ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf )
00632                      == LDAP_SUCCESS )
00633                      op->o_sasl_ssf = ssf;
00634        }
00635        op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
00636               ?  op->o_sasl_ssf : op->o_tls_ssf;
00637 
00638        ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );
00639 
00640        rc = LDAP_DEREF_NEVER;      /* actually could allow DEREF_FINDING */
00641        ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc );
00642 
00643        ldap_set_option( si->si_ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );
00644 
00645        si->si_syncCookie.rid = si->si_rid;
00646 
00647        /* whenever there are multiple data sources possible, advertise sid */
00648        si->si_syncCookie.sid = ( SLAP_MULTIMASTER( si->si_be ) || si->si_be != si->si_wbe ) ?
00649               slap_serverID : -1;
00650 
00651        /* We've just started up, or the remote server hasn't sent us
00652         * any meaningful state.
00653         */
00654        if ( !si->si_syncCookie.ctxcsn ) {
00655               int i;
00656 
00657               LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) {
00658                      if ( si->si_rid == sc->rid ) {
00659                             cmdline_cookie_found = 1;
00660                             break;
00661                      }
00662               }
00663 
00664               if ( cmdline_cookie_found ) {
00665                      /* cookie is supplied in the command line */
00666 
00667                      LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );
00668 
00669                      /* ctxcsn wasn't parsed yet, do it now */
00670                      slap_parse_sync_cookie( sc, NULL );
00671                      slap_sync_cookie_free( &si->si_syncCookie, 0 );
00672                      slap_dup_sync_cookie( &si->si_syncCookie, sc );
00673                      slap_sync_cookie_free( sc, 1 );
00674               } else {
00675                      ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
00676                      if ( !si->si_cookieState->cs_num ) {
00677                             /* get contextCSN shadow replica from database */
00678                             BerVarray csn = NULL;
00679                             void *ctx = op->o_tmpmemctx;
00680 
00681                             op->o_req_ndn = si->si_contextdn;
00682                             op->o_req_dn = op->o_req_ndn;
00683 
00684                             /* try to read stored contextCSN */
00685                             op->o_tmpmemctx = NULL;
00686                             backend_attribute( op, NULL, &op->o_req_ndn,
00687                                    slap_schema.si_ad_contextCSN, &csn, ACL_READ );
00688                             op->o_tmpmemctx = ctx;
00689                             if ( csn ) {
00690                                    si->si_cookieState->cs_vals = csn;
00691                                    for (i=0; !BER_BVISNULL( &csn[i] ); i++);
00692                                    si->si_cookieState->cs_num = i;
00693                                    si->si_cookieState->cs_sids = slap_parse_csn_sids( csn, i, NULL );
00694                                    slap_sort_csn_sids( csn, si->si_cookieState->cs_sids, i, NULL );
00695                             }
00696                      }
00697                      if ( si->si_cookieState->cs_num ) {
00698                             ber_bvarray_free( si->si_syncCookie.ctxcsn );
00699                             if ( ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
00700                                    si->si_cookieState->cs_vals, NULL )) {
00701                                    rc = LDAP_NO_MEMORY;
00702                                    ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
00703                                    goto done;
00704                             }
00705                             si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
00706                             si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num *
00707                                    sizeof(int) );
00708                             for ( i=0; i<si->si_syncCookie.numcsns; i++ )
00709                                    si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i];
00710                      }
00711                      ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
00712               }
00713 
00714               slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
00715                      si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
00716                      si->si_syncCookie.sid );
00717        } else {
00718               /* ITS#6367: recreate the cookie so it has our SID, not our peer's */
00719               ch_free( si->si_syncCookie.octet_str.bv_val );
00720               BER_BVZERO( &si->si_syncCookie.octet_str );
00721               /* Look for contextCSN from syncprov overlay. */
00722               check_syncprov( op, si );
00723               if ( BER_BVISNULL( &si->si_syncCookie.octet_str ))
00724                      slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
00725                             si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
00726                             si->si_syncCookie.sid );
00727        }
00728 
00729        si->si_refreshDone = 0;
00730 
00731        rc = ldap_sync_search( si, op->o_tmpmemctx );
00732 
00733        if( rc != LDAP_SUCCESS ) {
00734               Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s "
00735                      "ldap_search_ext: %s (%d)\n",
00736                      si->si_ridtxt, ldap_err2string( rc ), rc );
00737        }
00738 
00739 done:
00740        if ( rc ) {
00741               if ( si->si_ld ) {
00742                      ldap_unbind_ext( si->si_ld, NULL, NULL );
00743                      si->si_ld = NULL;
00744               }
00745        }
00746 
00747        return rc;
00748 }
00749 
00750 static int
00751 compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
00752 {
00753        int i, j, match = 0;
00754        const char *text;
00755 
00756        *which = 0;
00757 
00758        if ( sc1->numcsns < sc2->numcsns ) {
00759               *which = sc1->numcsns;
00760               return -1;
00761        }
00762 
00763        for (j=0; j<sc2->numcsns; j++) {
00764               for (i=0; i<sc1->numcsns; i++) {
00765                      if ( sc1->sids[i] != sc2->sids[j] )
00766                             continue;
00767                      value_match( &match, slap_schema.si_ad_entryCSN,
00768                             slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
00769                             SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
00770                             &sc1->ctxcsn[i], &sc2->ctxcsn[j], &text );
00771                      if ( match < 0 ) {
00772                             *which = j;
00773                             return match;
00774                      }
00775                      break;
00776               }
00777               if ( i == sc1->numcsns ) {
00778                      /* sc2 has a sid sc1 lacks */
00779                      *which = j;
00780                      return -1;
00781               }
00782        }
00783        return match;
00784 }
00785 
00786 #define       SYNC_PAUSED   -3
00787 
00788 static int
00789 do_syncrep2(
00790        Operation *op,
00791        syncinfo_t *si )
00792 {
00793        BerElementBuffer berbuf;
00794        BerElement    *ber = (BerElement *)&berbuf;
00795 
00796        LDAPMessage   *msg = NULL;
00797 
00798        struct sync_cookie   syncCookie = { NULL };
00799        struct sync_cookie   syncCookie_req = { NULL };
00800 
00801        int           rc,
00802                      err = LDAP_SUCCESS;
00803 
00804        Modifications *modlist = NULL;
00805 
00806        int                         m;
00807 
00808        struct timeval *tout_p = NULL;
00809        struct timeval tout = { 0, 0 };
00810 
00811        int           refreshDeletes = 0;
00812        char empty[6] = "empty";
00813 
00814        if ( slapd_shutdown ) {
00815               rc = -2;
00816               goto done;
00817        }
00818 
00819        ber_init2( ber, NULL, LBER_USE_DER );
00820        ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
00821 
00822        Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2 %s\n", si->si_ridtxt, 0, 0 );
00823 
00824        slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
00825 
00826        if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST && si->si_refreshDone ) {
00827               tout_p = &tout;
00828        } else {
00829               tout_p = NULL;
00830        }
00831 
00832        while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
00833               tout_p, &msg ) ) > 0 )
00834        {
00835               int                         match, punlock, syncstate;
00836               struct berval *retdata, syncUUID[2], cookie = BER_BVNULL;
00837               char                 *retoid;
00838               LDAPControl          **rctrls = NULL, *rctrlp = NULL;
00839               BerVarray            syncUUIDs;
00840               ber_len_t            len;
00841               ber_tag_t            si_tag;
00842               Entry                *entry;
00843               struct berval bdn;
00844 
00845               if ( slapd_shutdown ) {
00846                      rc = -2;
00847                      goto done;
00848               }
00849               switch( ldap_msgtype( msg ) ) {
00850               case LDAP_RES_SEARCH_ENTRY:
00851                      ldap_get_entry_controls( si->si_ld, msg, &rctrls );
00852                      ldap_get_dn_ber( si->si_ld, msg, NULL, &bdn );
00853                      if (!bdn.bv_len) {
00854                             bdn.bv_val = empty;
00855                             bdn.bv_len = sizeof(empty)-1;
00856                      }
00857                      /* we can't work without the control */
00858                      if ( rctrls ) {
00859                             LDAPControl **next = NULL;
00860                             /* NOTE: make sure we use the right one;
00861                              * a better approach would be to run thru
00862                              * the whole list and take care of all */
00863                             /* NOTE: since we issue the search request,
00864                              * we should know what controls to expect,
00865                              * and there should be none apart from the
00866                              * sync-related control */
00867                             rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_STATE, rctrls, &next );
00868                             if ( next && ldap_control_find( LDAP_CONTROL_SYNC_STATE, next, NULL ) )
00869                             {
00870                                    bdn.bv_val[bdn.bv_len] = '\0';
00871                                    Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
00872                                           "got search entry with multiple "
00873                                           "Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
00874                                    ldap_controls_free( rctrls );
00875                                    rc = -1;
00876                                    goto done;
00877                             }
00878                      }
00879                      if ( rctrlp == NULL ) {
00880                             bdn.bv_val[bdn.bv_len] = '\0';
00881                             Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
00882                                    "got search entry without "
00883                                    "Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
00884                             rc = -1;
00885                             goto done;
00886                      }
00887                      ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
00888                      if ( ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID[0] )
00889                                    == LBER_ERROR ) {
00890                             bdn.bv_val[bdn.bv_len] = '\0';
00891                             Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s malformed message (%s)\n",
00892                                    si->si_ridtxt, bdn.bv_val, 0 );
00893                             ldap_controls_free( rctrls );
00894                             rc = -1;
00895                             goto done;
00896                      }
00897                      /* FIXME: what if syncUUID is NULL or empty?
00898                       * (happens with back-sql...) */
00899                      if ( BER_BVISEMPTY( &syncUUID[0] ) ) {
00900                             bdn.bv_val[bdn.bv_len] = '\0';
00901                             Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
00902                                    "got empty syncUUID with LDAP_SYNC_%s (%s)\n",
00903                                    si->si_ridtxt,
00904                                    syncrepl_state2str( syncstate ), bdn.bv_val );
00905                             ldap_controls_free( rctrls );
00906                             rc = -1;
00907                             goto done;
00908                      }
00909                      punlock = -1;
00910                      if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
00911                             ber_scanf( ber, /*"{"*/ "m}", &cookie );
00912 
00913                             Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
00914                                    si->si_ridtxt,
00915                                    BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
00916 
00917                             if ( !BER_BVISNULL( &cookie ) ) {
00918                                    ch_free( syncCookie.octet_str.bv_val );
00919                                    ber_dupbv( &syncCookie.octet_str, &cookie );
00920                             }
00921                             if ( !BER_BVISNULL( &syncCookie.octet_str ) )
00922                             {
00923                                    slap_parse_sync_cookie( &syncCookie, NULL );
00924                                    if ( syncCookie.ctxcsn ) {
00925                                           int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
00926                                           check_syncprov( op, si );
00927                                           for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
00928                                                  /* new SID */
00929                                                  if ( sid < si->si_cookieState->cs_sids[i] )
00930                                                         break;
00931                                                  if ( si->si_cookieState->cs_sids[i] == sid ) {
00932                                                         if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
00933                                                                bdn.bv_val[bdn.bv_len] = '\0';
00934                                                                Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s (%s)\n",
00935                                                                       si->si_ridtxt, syncCookie.ctxcsn->bv_val, bdn.bv_val );
00936                                                                ldap_controls_free( rctrls );
00937                                                                rc = 0;
00938                                                                goto done;
00939                                                         }
00940                                                         break;
00941                                                  }
00942                                           }
00943                                           /* check pending CSNs too */
00944                                           while ( ldap_pvt_thread_mutex_trylock( &si->si_cookieState->cs_pmutex )) {
00945                                                  if ( slapd_shutdown ) {
00946                                                         rc = -2;
00947                                                         goto done;
00948                                                  }
00949                                                  if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
00950                                                         ldap_pvt_thread_yield();
00951                                           }
00952                                           for ( i =0; i<si->si_cookieState->cs_pnum; i++ ) {
00953                                                  if ( sid < si->si_cookieState->cs_psids[i] )
00954                                                         break;
00955                                                  if ( si->si_cookieState->cs_psids[i] == sid ) {
00956                                                         if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_pvals[i] ) <= 0 ) {
00957                                                                bdn.bv_val[bdn.bv_len] = '\0';
00958                                                                Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN pending, ignoring %s (%s)\n",
00959                                                                       si->si_ridtxt, syncCookie.ctxcsn->bv_val, bdn.bv_val );
00960                                                                ldap_controls_free( rctrls );
00961                                                                rc = 0;
00962                                                                ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
00963                                                                goto done;
00964                                                         }
00965                                                         ber_bvreplace( &si->si_cookieState->cs_pvals[i],
00966                                                                syncCookie.ctxcsn );
00967                                                         break;
00968                                                  }
00969                                           }
00970                                           /* new SID, add it */
00971                                           if ( i == si->si_cookieState->cs_pnum ||
00972                                                  sid != si->si_cookieState->cs_psids[i] ) {
00973                                                  slap_insert_csn_sids(
00974                                                         (struct sync_cookie *)&si->si_cookieState->cs_pvals,
00975                                                         i, sid, syncCookie.ctxcsn );
00976                                           }
00977                                           assert( punlock < 0 );
00978                                           punlock = i;
00979                                    }
00980                                    op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
00981                             }
00982                      }
00983                      rc = 0;
00984                      if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
00985                             modlist = NULL;
00986                             if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
00987                                    syncCookie.ctxcsn )
00988                             {
00989                                    rc = syncrepl_updateCookie( si, op, &syncCookie );
00990                             } else switch ( rc ) {
00991                                    case LDAP_ALREADY_EXISTS:
00992                                    case LDAP_NO_SUCH_OBJECT:
00993                                    case LDAP_NO_SUCH_ATTRIBUTE:
00994                                    case LDAP_TYPE_OR_VALUE_EXISTS:
00995                                    case LDAP_NOT_ALLOWED_ON_NONLEAF:
00996                                           rc = LDAP_SYNC_REFRESH_REQUIRED;
00997                                           si->si_logstate = SYNCLOG_FALLBACK;
00998                                           ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
00999                                           bdn.bv_val[bdn.bv_len] = '\0';
01000                                           Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync on (%s), switching to REFRESH\n",
01001                                                  si->si_ridtxt, bdn.bv_val, 0 );
01002                                           if (si->si_strict_refresh) {
01003                                                  slap_suspend_listeners();
01004                                                  connections_drop();
01005                                           }
01006                                           break;
01007                                    default:
01008                                           break;
01009                             }
01010                      } else if ( ( rc = syncrepl_message_to_entry( si, op, msg,
01011                             &modlist, &entry, syncstate, syncUUID ) ) == LDAP_SUCCESS )
01012                      {
01013                             if ( ( rc = syncrepl_entry( si, op, entry, &modlist,
01014                                    syncstate, syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
01015                                    syncCookie.ctxcsn )
01016                             {
01017                                    rc = syncrepl_updateCookie( si, op, &syncCookie );
01018                             }
01019                      }
01020                      if ( punlock >= 0 ) {
01021                             /* on failure, revert pending CSN */
01022                             if ( rc != LDAP_SUCCESS ) {
01023                                    int i;
01024                                    for ( i = 0; i<si->si_cookieState->cs_num; i++ ) {
01025                                           if ( si->si_cookieState->cs_sids[i] == si->si_cookieState->cs_psids[punlock] ) {
01026                                                  ber_bvreplace( &si->si_cookieState->cs_pvals[punlock],
01027                                                         &si->si_cookieState->cs_vals[i] );
01028                                                  break;
01029                                           }
01030                                    }
01031                                    if ( i == si->si_cookieState->cs_num )
01032                                           si->si_cookieState->cs_pvals[punlock].bv_val[0] = '\0';
01033                             }
01034                             ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
01035                      }
01036                      ldap_controls_free( rctrls );
01037                      if ( modlist ) {
01038                             slap_mods_free( modlist, 1 );
01039                      }
01040                      if ( rc )
01041                             goto done;
01042                      break;
01043 
01044               case LDAP_RES_SEARCH_REFERENCE:
01045                      Debug( LDAP_DEBUG_ANY,
01046                             "do_syncrep2: %s reference received error\n",
01047                             si->si_ridtxt, 0, 0 );
01048                      break;
01049 
01050               case LDAP_RES_SEARCH_RESULT:
01051                      Debug( LDAP_DEBUG_SYNC,
01052                             "do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
01053                             si->si_ridtxt, 0, 0 );
01054                      err = LDAP_OTHER; /* FIXME check parse result properly */
01055                      ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
01056                             &rctrls, 0 );
01057 #ifdef LDAP_X_SYNC_REFRESH_REQUIRED
01058                      if ( err == LDAP_X_SYNC_REFRESH_REQUIRED ) {
01059                             /* map old result code to registered code */
01060                             err = LDAP_SYNC_REFRESH_REQUIRED;
01061                      }
01062 #endif
01063                      if ( err == LDAP_SYNC_REFRESH_REQUIRED ) {
01064                             if ( si->si_logstate == SYNCLOG_LOGGING ) {
01065                                    si->si_logstate = SYNCLOG_FALLBACK;
01066                                    Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync, switching to REFRESH\n",
01067                                           si->si_ridtxt, 0, 0 );
01068                                    if (si->si_strict_refresh) {
01069                                           slap_suspend_listeners();
01070                                           connections_drop();
01071                                    }
01072                             }
01073                             rc = err;
01074                             goto done;
01075                      }
01076                      if ( err ) {
01077                             Debug( LDAP_DEBUG_ANY,
01078                                    "do_syncrep2: %s LDAP_RES_SEARCH_RESULT (%d) %s\n",
01079                                    si->si_ridtxt, err, ldap_err2string( err ) );
01080                      }
01081                      if ( rctrls ) {
01082                             LDAPControl **next = NULL;
01083                             /* NOTE: make sure we use the right one;
01084                              * a better approach would be to run thru
01085                              * the whole list and take care of all */
01086                             /* NOTE: since we issue the search request,
01087                              * we should know what controls to expect,
01088                              * and there should be none apart from the
01089                              * sync-related control */
01090                             rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_DONE, rctrls, &next );
01091                             if ( next && ldap_control_find( LDAP_CONTROL_SYNC_DONE, next, NULL ) )
01092                             {
01093                                    Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
01094                                           "got search result with multiple "
01095                                           "Sync State control\n", si->si_ridtxt, 0, 0 );
01096                                    ldap_controls_free( rctrls );
01097                                    rc = -1;
01098                                    goto done;
01099                             }
01100                      }
01101                      if ( rctrlp ) {
01102                             ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
01103 
01104                             ber_scanf( ber, "{" /*"}"*/);
01105                             if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
01106                                    ber_scanf( ber, "m", &cookie );
01107 
01108                                    Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
01109                                           si->si_ridtxt, 
01110                                           BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
01111 
01112                                    if ( !BER_BVISNULL( &cookie ) ) {
01113                                           ch_free( syncCookie.octet_str.bv_val );
01114                                           ber_dupbv( &syncCookie.octet_str, &cookie);
01115                                    }
01116                                    if ( !BER_BVISNULL( &syncCookie.octet_str ) )
01117                                    {
01118                                           slap_parse_sync_cookie( &syncCookie, NULL );
01119                                           op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
01120                                    }
01121                             }
01122                             if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
01123                             {
01124                                    ber_scanf( ber, "b", &refreshDeletes );
01125                             }
01126                             ber_scanf( ber, /*"{"*/ "}" );
01127                      }
01128                      if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
01129                             slap_sync_cookie_free( &syncCookie_req, 0 );
01130                             slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
01131                      }
01132                      if ( !syncCookie.ctxcsn ) {
01133                             match = 1;
01134                      } else if ( !syncCookie_req.ctxcsn ) {
01135                             match = -1;
01136                             m = 0;
01137                      } else {
01138                             match = compare_csns( &syncCookie_req, &syncCookie, &m );
01139                      }
01140                      if ( rctrls ) {
01141                             ldap_controls_free( rctrls );
01142                      }
01143                      if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
01144                             /* FIXME : different error behaviors according to
01145                              *     1) err code : LDAP_BUSY ...
01146                              *     2) on err policy : stop service, stop sync, retry
01147                              */
01148                             if ( refreshDeletes == 0 && match < 0 &&
01149                                    err == LDAP_SUCCESS &&
01150                                    syncCookie_req.numcsns == syncCookie.numcsns )
01151                             {
01152                                    syncrepl_del_nonpresent( op, si, NULL,
01153                                           &syncCookie, m );
01154                             } else {
01155                                    avl_free( si->si_presentlist, ch_free );
01156                                    si->si_presentlist = NULL;
01157                             }
01158                      }
01159                      if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
01160                      {
01161                             rc = syncrepl_updateCookie( si, op, &syncCookie );
01162                      }
01163                      if ( err == LDAP_SUCCESS
01164                             && si->si_logstate == SYNCLOG_FALLBACK ) {
01165                             si->si_logstate = SYNCLOG_LOGGING;
01166                             rc = LDAP_SYNC_REFRESH_REQUIRED;
01167                             slap_resume_listeners();
01168                      } else {
01169                             rc = -2;
01170                      }
01171                      goto done;
01172 
01173               case LDAP_RES_INTERMEDIATE:
01174                      retoid = NULL;
01175                      retdata = NULL;
01176                      rc = ldap_parse_intermediate( si->si_ld, msg,
01177                             &retoid, &retdata, NULL, 0 );
01178                      if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
01179                             ber_init2( ber, retdata, LBER_USE_DER );
01180 
01181                             switch ( si_tag = ber_peek_tag( ber, &len ) ) {
01182                             ber_tag_t tag;
01183                             case LDAP_TAG_SYNC_NEW_COOKIE:
01184                                    Debug( LDAP_DEBUG_SYNC,
01185                                           "do_syncrep2: %s %s - %s\n", 
01186                                           si->si_ridtxt,
01187                                           "LDAP_RES_INTERMEDIATE", 
01188                                           "NEW_COOKIE" );
01189                                    ber_scanf( ber, "tm", &tag, &cookie );
01190                                    Debug( LDAP_DEBUG_SYNC,
01191                                           "do_syncrep2: %s NEW_COOKIE: %s\n",
01192                                           si->si_ridtxt,
01193                                           cookie.bv_val, 0);
01194                                    if ( !BER_BVISNULL( &cookie ) ) {
01195                                           ch_free( syncCookie.octet_str.bv_val );
01196                                           ber_dupbv( &syncCookie.octet_str, &cookie );
01197                                    }
01198                                    if (!BER_BVISNULL( &syncCookie.octet_str ) ) {
01199                                           slap_parse_sync_cookie( &syncCookie, NULL );
01200                                           op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
01201                                    }
01202                                    break;
01203                             case LDAP_TAG_SYNC_REFRESH_DELETE:
01204                             case LDAP_TAG_SYNC_REFRESH_PRESENT:
01205                                    Debug( LDAP_DEBUG_SYNC,
01206                                           "do_syncrep2: %s %s - %s\n", 
01207                                           si->si_ridtxt,
01208                                           "LDAP_RES_INTERMEDIATE", 
01209                                           si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ?
01210                                           "REFRESH_PRESENT" : "REFRESH_DELETE" );
01211                                    if ( si_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
01212                                           si->si_refreshDelete = 1;
01213                                    } else {
01214                                           si->si_refreshPresent = 1;
01215                                    }
01216                                    ber_scanf( ber, "t{" /*"}"*/, &tag );
01217                                    if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
01218                                    {
01219                                           ber_scanf( ber, "m", &cookie );
01220 
01221                                           Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
01222                                                  si->si_ridtxt, 
01223                                                  BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
01224 
01225                                           if ( !BER_BVISNULL( &cookie ) ) {
01226                                                  ch_free( syncCookie.octet_str.bv_val );
01227                                                  ber_dupbv( &syncCookie.octet_str, &cookie );
01228                                           }
01229                                           if ( !BER_BVISNULL( &syncCookie.octet_str ) )
01230                                           {
01231                                                  slap_parse_sync_cookie( &syncCookie, NULL );
01232                                                  op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
01233                                           }
01234                                    }
01235                                    /* Defaults to TRUE */
01236                                    if ( ber_peek_tag( ber, &len ) ==
01237                                           LDAP_TAG_REFRESHDONE )
01238                                    {
01239                                           ber_scanf( ber, "b", &si->si_refreshDone );
01240                                    } else
01241                                    {
01242                                           si->si_refreshDone = 1;
01243                                    }
01244                                    ber_scanf( ber, /*"{"*/ "}" );
01245                                    if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
01246                                           si->si_refreshDone )
01247                                           tout_p = &tout;
01248                                    break;
01249                             case LDAP_TAG_SYNC_ID_SET:
01250                                    Debug( LDAP_DEBUG_SYNC,
01251                                           "do_syncrep2: %s %s - %s\n", 
01252                                           si->si_ridtxt,
01253                                           "LDAP_RES_INTERMEDIATE", 
01254                                           "SYNC_ID_SET" );
01255                                    ber_scanf( ber, "t{" /*"}"*/, &tag );
01256                                    if ( ber_peek_tag( ber, &len ) ==
01257                                           LDAP_TAG_SYNC_COOKIE )
01258                                    {
01259                                           ber_scanf( ber, "m", &cookie );
01260 
01261                                           Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
01262                                                  si->si_ridtxt,
01263                                                  BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
01264 
01265                                           if ( !BER_BVISNULL( &cookie ) ) {
01266                                                  ch_free( syncCookie.octet_str.bv_val );
01267                                                  ber_dupbv( &syncCookie.octet_str, &cookie );
01268                                           }
01269                                           if ( !BER_BVISNULL( &syncCookie.octet_str ) )
01270                                           {
01271                                                  slap_parse_sync_cookie( &syncCookie, NULL );
01272                                                  op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
01273                                                  compare_csns( &syncCookie_req, &syncCookie, &m );
01274                                           }
01275                                    }
01276                                    if ( ber_peek_tag( ber, &len ) ==
01277                                           LDAP_TAG_REFRESHDELETES )
01278                                    {
01279                                           ber_scanf( ber, "b", &refreshDeletes );
01280                                    }
01281                                    syncUUIDs = NULL;
01282                                    ber_scanf( ber, "[W]", &syncUUIDs );
01283                                    ber_scanf( ber, /*"{"*/ "}" );
01284                                    if ( refreshDeletes ) {
01285                                           syncrepl_del_nonpresent( op, si, syncUUIDs,
01286                                                  &syncCookie, m );
01287                                           ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
01288                                    } else {
01289                                           int i;
01290                                           for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
01291                                                  (void)avl_presentlist_insert( si, &syncUUIDs[i] );
01292                                                  slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx );
01293                                           }
01294                                           slap_sl_free( syncUUIDs, op->o_tmpmemctx );
01295                                    }
01296                                    slap_sync_cookie_free( &syncCookie, 0 );
01297                                    break;
01298                             default:
01299                                    Debug( LDAP_DEBUG_ANY,
01300                                           "do_syncrep2: %s unknown syncinfo tag (%ld)\n",
01301                                           si->si_ridtxt, (long) si_tag, 0 );
01302                                    ldap_memfree( retoid );
01303                                    ber_bvfree( retdata );
01304                                    continue;
01305                             }
01306 
01307                             if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
01308                                    slap_sync_cookie_free( &syncCookie_req, 0 );
01309                                    slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
01310                             }
01311                             if ( !syncCookie.ctxcsn ) {
01312                                    match = 1;
01313                             } else if ( !syncCookie_req.ctxcsn ) {
01314                                    match = -1;
01315                                    m = 0;
01316                             } else {
01317                                    match = compare_csns( &syncCookie_req, &syncCookie, &m );
01318                             }
01319 
01320                             if ( match < 0 ) {
01321                                    if ( si->si_refreshPresent == 1 &&
01322                                           si_tag != LDAP_TAG_SYNC_NEW_COOKIE &&
01323                                           syncCookie_req.numcsns == syncCookie.numcsns ) {
01324                                           syncrepl_del_nonpresent( op, si, NULL,
01325                                                  &syncCookie, m );
01326                                    }
01327 
01328                                    if ( syncCookie.ctxcsn )
01329                                    {
01330                                           rc = syncrepl_updateCookie( si, op, &syncCookie);
01331                                    }
01332                             } 
01333 
01334                             ldap_memfree( retoid );
01335                             ber_bvfree( retdata );
01336 
01337                      } else {
01338                             Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
01339                                    "unknown intermediate response (%d)\n",
01340                                    si->si_ridtxt, rc, 0 );
01341                             ldap_memfree( retoid );
01342                             ber_bvfree( retdata );
01343                      }
01344                      break;
01345 
01346               default:
01347                      Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
01348                             "unknown message (0x%02lx)\n",
01349                             si->si_ridtxt,
01350                             (unsigned long)ldap_msgtype( msg ), 0 );
01351                      break;
01352 
01353               }
01354               if ( !BER_BVISNULL( &syncCookie.octet_str ) ) {
01355                      slap_sync_cookie_free( &syncCookie_req, 0 );
01356                      slap_dup_sync_cookie( &syncCookie_req, &syncCookie );
01357                      slap_sync_cookie_free( &syncCookie, 0 );
01358               }
01359               ldap_msgfree( msg );
01360               msg = NULL;
01361               if ( ldap_pvt_thread_pool_pausing( &connection_pool )) {
01362                      slap_sync_cookie_free( &syncCookie, 0 );
01363                      slap_sync_cookie_free( &syncCookie_req, 0 );
01364                      return SYNC_PAUSED;
01365               }
01366        }
01367 
01368        if ( rc == -1 ) {
01369               rc = LDAP_OTHER;
01370               ldap_get_option( si->si_ld, LDAP_OPT_ERROR_NUMBER, &rc );
01371               err = rc;
01372        }
01373 
01374 done:
01375        if ( err != LDAP_SUCCESS ) {
01376               Debug( LDAP_DEBUG_ANY,
01377                      "do_syncrep2: %s (%d) %s\n",
01378                      si->si_ridtxt, err, ldap_err2string( err ) );
01379        }
01380 
01381        slap_sync_cookie_free( &syncCookie, 0 );
01382        slap_sync_cookie_free( &syncCookie_req, 0 );
01383 
01384        if ( msg ) ldap_msgfree( msg );
01385 
01386        if ( rc && rc != LDAP_SYNC_REFRESH_REQUIRED && si->si_ld ) {
01387               if ( si->si_conn ) {
01388                      connection_client_stop( si->si_conn );
01389                      si->si_conn = NULL;
01390               }
01391               ldap_unbind_ext( si->si_ld, NULL, NULL );
01392               si->si_ld = NULL;
01393        }
01394 
01395        return rc;
01396 }
01397 
01398 static void *
01399 do_syncrepl(
01400        void   *ctx,
01401        void   *arg )
01402 {
01403        struct re_s* rtask = arg;
01404        syncinfo_t *si = ( syncinfo_t * ) rtask->arg;
01405        Connection conn = {0};
01406        OperationBuffer opbuf;
01407        Operation *op;
01408        int rc = LDAP_SUCCESS;
01409        int dostop = 0;
01410        ber_socket_t s;
01411        int i, defer = 1, fail = 0, freeinfo = 0;
01412        Backend *be;
01413 
01414        if ( si == NULL )
01415               return NULL;
01416        if ( slapd_shutdown )
01417               return NULL;
01418 
01419        Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt, 0, 0 );
01420 
01421        /* Don't get stuck here while a pause is initiated */
01422        while ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
01423               if ( slapd_shutdown )
01424                      return NULL;
01425               if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
01426                      ldap_pvt_thread_yield();
01427        }
01428 
01429        if ( si->si_ctype < 1 ) {
01430               goto deleted;
01431        }
01432 
01433        switch( abs( si->si_type ) ) {
01434        case LDAP_SYNC_REFRESH_ONLY:
01435        case LDAP_SYNC_REFRESH_AND_PERSIST:
01436               break;
01437        default:
01438               ldap_pvt_thread_mutex_unlock( &si->si_mutex );
01439               return NULL;
01440        }
01441 
01442        if ( slapd_shutdown ) {
01443               if ( si->si_ld ) {
01444                      if ( si->si_conn ) {
01445                             connection_client_stop( si->si_conn );
01446                             si->si_conn = NULL;
01447                      }
01448                      ldap_unbind_ext( si->si_ld, NULL, NULL );
01449                      si->si_ld = NULL;
01450               }
01451               ldap_pvt_thread_mutex_unlock( &si->si_mutex );
01452               return NULL;
01453        }
01454 
01455        connection_fake_init( &conn, &opbuf, ctx );
01456        op = &opbuf.ob_op;
01457        /* o_connids must be unique for slap_graduate_commit_csn */
01458        op->o_connid = SLAPD_SYNC_RID2SYNCCONN(si->si_rid);
01459 
01460        op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
01461        be = si->si_be;
01462 
01463        /* Coordinate contextCSN updates with any syncprov overlays
01464         * in use. This may be complicated by the use of the glue
01465         * overlay.
01466         *
01467         * Typically there is a single syncprov mastering the entire
01468         * glued tree. In that case, our contextCSN updates should
01469         * go to the master DB. But if there is no syncprov on the
01470         * master DB, then nothing special is needed here.
01471         *
01472         * Alternatively, there may be individual syncprov overlays
01473         * on each glued branch. In that case, each syncprov only
01474         * knows about changes within its own branch. And so our
01475         * contextCSN updates should only go to the local DB.
01476         */
01477        if ( !si->si_wbe ) {
01478               if ( SLAP_GLUE_SUBORDINATE( be ) && !overlay_is_inst( be, "syncprov" )) {
01479                      BackendDB * top_be = select_backend( &be->be_nsuffix[0], 1 );
01480                      if ( overlay_is_inst( top_be, "syncprov" ))
01481                             si->si_wbe = top_be;
01482                      else
01483                             si->si_wbe = be;
01484               } else {
01485                      si->si_wbe = be;
01486               }
01487               if ( SLAP_SYNC_SUBENTRY( si->si_wbe )) {
01488                      build_new_dn( &si->si_contextdn, &si->si_wbe->be_nsuffix[0],
01489                             (struct berval *)&slap_ldapsync_cn_bv, NULL );
01490               } else {
01491                      si->si_contextdn = si->si_wbe->be_nsuffix[0];
01492               }
01493        }
01494        if ( !si->si_schemachecking )
01495               op->o_no_schema_check = 1;
01496 
01497        /* Establish session, do search */
01498        if ( !si->si_ld ) {
01499               si->si_refreshDelete = 0;
01500               si->si_refreshPresent = 0;
01501 
01502               if ( si->si_presentlist ) {
01503                   avl_free( si->si_presentlist, ch_free );
01504                   si->si_presentlist = NULL;
01505               }
01506 
01507               /* use main DB when retrieving contextCSN */
01508               op->o_bd = si->si_wbe;
01509               op->o_dn = op->o_bd->be_rootdn;
01510               op->o_ndn = op->o_bd->be_rootndn;
01511               rc = do_syncrep1( op, si );
01512        }
01513 
01514 reload:
01515        /* Process results */
01516        if ( rc == LDAP_SUCCESS ) {
01517               ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
01518 
01519               /* use current DB */
01520               op->o_bd = be;
01521               op->o_dn = op->o_bd->be_rootdn;
01522               op->o_ndn = op->o_bd->be_rootndn;
01523               rc = do_syncrep2( op, si );
01524               if ( rc == LDAP_SYNC_REFRESH_REQUIRED )   {
01525                      rc = ldap_sync_search( si, op->o_tmpmemctx );
01526                      goto reload;
01527               }
01528 
01529 deleted:
01530               /* We got deleted while running on cn=config */
01531               if ( si->si_ctype < 1 ) {
01532                      if ( si->si_ctype == -1 ) {
01533                             si->si_ctype = 0;
01534                             freeinfo = 1;
01535                      }
01536                      if ( si->si_conn )
01537                             dostop = 1;
01538                      rc = -1;
01539               }
01540 
01541               if ( rc != SYNC_PAUSED ) {
01542                      if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
01543                             /* If we succeeded, enable the connection for further listening.
01544                              * If we failed, tear down the connection and reschedule.
01545                              */
01546                             if ( rc == LDAP_SUCCESS ) {
01547                                    if ( si->si_conn ) {
01548                                           connection_client_enable( si->si_conn );
01549                                    } else {
01550                                           si->si_conn = connection_client_setup( s, do_syncrepl, arg );
01551                                    } 
01552                             } else if ( si->si_conn ) {
01553                                    dostop = 1;
01554                             }
01555                      } else {
01556                             if ( rc == -2 ) rc = 0;
01557                      }
01558               }
01559        }
01560 
01561        /* At this point, we have 5 cases:
01562         * 1) for any hard failure, give up and remove this task
01563         * 2) for ServerDown, reschedule this task to run later
01564         * 3) for threadpool pause, reschedule to run immediately
01565         * 4) for Refresh and Success, reschedule to run
01566         * 5) for Persist and Success, reschedule to defer
01567         */
01568        ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
01569 
01570        if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask ) ) {
01571               ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
01572        }
01573 
01574        if ( dostop ) {
01575               connection_client_stop( si->si_conn );
01576               si->si_conn = NULL;
01577        }
01578 
01579        if ( rc == SYNC_PAUSED ) {
01580               rtask->interval.tv_sec = 0;
01581               ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
01582               rtask->interval.tv_sec = si->si_interval;
01583               rc = 0;
01584        } else if ( rc == LDAP_SUCCESS ) {
01585               if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
01586                      defer = 0;
01587               }
01588               rtask->interval.tv_sec = si->si_interval;
01589               ldap_pvt_runqueue_resched( &slapd_rq, rtask, defer );
01590               if ( si->si_retrynum ) {
01591                      for ( i = 0; si->si_retrynum_init[i] != RETRYNUM_TAIL; i++ ) {
01592                             si->si_retrynum[i] = si->si_retrynum_init[i];
01593                      }
01594                      si->si_retrynum[i] = RETRYNUM_TAIL;
01595               }
01596        } else {
01597               for ( i = 0; si->si_retrynum && si->si_retrynum[i] <= 0; i++ ) {
01598                      if ( si->si_retrynum[i] == RETRYNUM_FOREVER || si->si_retrynum[i] == RETRYNUM_TAIL )
01599                             break;
01600               }
01601 
01602               if ( si->si_ctype < 1
01603                      || !si->si_retrynum || si->si_retrynum[i] == RETRYNUM_TAIL ) {
01604                      if ( si->si_re ) {
01605                             ldap_pvt_runqueue_remove( &slapd_rq, rtask );
01606                             si->si_re = NULL;
01607                      }
01608                      fail = RETRYNUM_TAIL;
01609               } else if ( RETRYNUM_VALID( si->si_retrynum[i] ) ) {
01610                      if ( si->si_retrynum[i] > 0 )
01611                             si->si_retrynum[i]--;
01612                      fail = si->si_retrynum[i];
01613                      rtask->interval.tv_sec = si->si_retryinterval[i];
01614                      ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
01615                      slap_wake_listener();
01616               }
01617        }
01618 
01619        ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
01620        ldap_pvt_thread_mutex_unlock( &si->si_mutex );
01621 
01622        if ( rc ) {
01623               if ( fail == RETRYNUM_TAIL ) {
01624                      Debug( LDAP_DEBUG_ANY,
01625                             "do_syncrepl: %s rc %d quitting\n",
01626                             si->si_ridtxt, rc, 0 );
01627               } else if ( fail > 0 ) {
01628                      Debug( LDAP_DEBUG_ANY,
01629                             "do_syncrepl: %s rc %d retrying (%d retries left)\n",
01630                             si->si_ridtxt, rc, fail );
01631               } else {
01632                      Debug( LDAP_DEBUG_ANY,
01633                             "do_syncrepl: %s rc %d retrying\n",
01634                             si->si_ridtxt, rc, 0 );
01635               }
01636        }
01637 
01638        /* Do final delete cleanup */
01639        if ( freeinfo ) {
01640               syncinfo_free( si, 0 );
01641        }
01642        return NULL;
01643 }
01644 
01645 #ifdef ENABLE_REWRITE
01646 static int
01647 syncrepl_rewrite_dn(
01648        syncinfo_t *si,
01649        struct berval *dn,
01650        struct berval *sdn )
01651 {
01652        char nul;
01653        int rc;
01654 
01655        nul = dn->bv_val[dn->bv_len];
01656        dn->bv_val[dn->bv_len] = 0;
01657        rc = rewrite( si->si_rewrite, SUFFIXM_CTX, dn->bv_val, &sdn->bv_val );
01658        dn->bv_val[dn->bv_len] = nul;
01659 
01660        if ( sdn->bv_val == dn->bv_val )
01661               sdn->bv_val = NULL;
01662        else if ( rc == REWRITE_REGEXEC_OK && sdn->bv_val )
01663               sdn->bv_len = strlen( sdn->bv_val );
01664        return rc;
01665 }
01666 #define       REWRITE_VAL(si, ad, bv, bv2)       \
01667        BER_BVZERO( &bv2 );  \
01668        if ( si->si_rewrite && ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName) \
01669               syncrepl_rewrite_dn( si, &bv, &bv2); \
01670        if ( BER_BVISNULL( &bv2 ))  \
01671               ber_dupbv( &bv2, &bv )
01672 #define REWRITE_DN(si, bv, bv2, dn, ndn) \
01673        BER_BVZERO( &bv2 );  \
01674        if (si->si_rewrite) \
01675               syncrepl_rewrite_dn(si, &bv, &bv2); \
01676        rc = dnPrettyNormal( NULL, bv2.bv_val ? &bv2 : &bv, &dn, &ndn, op->o_tmpmemctx ); \
01677        ch_free(bv2.bv_val)
01678 #else
01679 #define REWRITE_VAL(si, ad, bv, bv2)      ber_dupbv(&bv2, &bv)
01680 #define REWRITE_DN(si, bv, bv2, dn, ndn) \
01681        rc = dnPrettyNormal( NULL, &bv, &dn, &ndn, op->o_tmpmemctx )
01682 #endif
01683 
01684 
01685 static slap_verbmasks modops[] = {
01686        { BER_BVC("add"), LDAP_REQ_ADD },
01687        { BER_BVC("delete"), LDAP_REQ_DELETE },
01688        { BER_BVC("modify"), LDAP_REQ_MODIFY },
01689        { BER_BVC("modrdn"), LDAP_REQ_MODRDN},
01690        { BER_BVNULL, 0 }
01691 };
01692 
01693 static int
01694 syncrepl_accesslog_mods(
01695        syncinfo_t *si,
01696        struct berval *vals,
01697        struct Modifications **modres
01698 )
01699 {
01700        char *colon;
01701        const char *text;
01702        AttributeDescription *ad;
01703        struct berval bv, bv2;
01704        short op;
01705        Modifications *mod = NULL, *modlist = NULL, **modtail;
01706        int i, rc = 0;
01707 
01708        modtail = &modlist;
01709 
01710        for (i=0; !BER_BVISNULL( &vals[i] ); i++) {
01711               ad = NULL;
01712               bv = vals[i];
01713 
01714               colon = ber_bvchr( &bv, ':' );
01715               if ( !colon ) {
01716                      /* Invalid */
01717                      continue;
01718               }
01719 
01720               bv.bv_len = colon - bv.bv_val;
01721               if ( slap_bv2ad( &bv, &ad, &text ) ) {
01722                      /* Invalid */
01723                      Debug( LDAP_DEBUG_ANY, "syncrepl_accesslog_mods: %s "
01724                             "Invalid attribute %s, %s\n",
01725                             si->si_ridtxt, bv.bv_val, text );
01726                      slap_mods_free( modlist, 1 );
01727                      modlist = NULL;
01728                      rc = -1;
01729                      break;
01730               }
01731 
01732               /* Ignore dynamically generated attrs */
01733               if ( ad->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
01734                      continue;
01735               }
01736 
01737               /* Ignore excluded attrs */
01738               if ( ldap_charray_inlist( si->si_exattrs,
01739                      ad->ad_type->sat_cname.bv_val ) )
01740               {
01741                      continue;
01742               }
01743 
01744               switch(colon[1]) {
01745               case '+':     op = LDAP_MOD_ADD; break;
01746               case '-':     op = LDAP_MOD_DELETE; break;
01747               case '=':     op = LDAP_MOD_REPLACE; break;
01748               case '#':     op = LDAP_MOD_INCREMENT; break;
01749               default:      continue;
01750               }
01751 
01752               if ( !mod || ad != mod->sml_desc || op != mod->sml_op ) {
01753                      mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
01754                      mod->sml_flags = 0;
01755                      mod->sml_op = op;
01756                      mod->sml_next = NULL;
01757                      mod->sml_desc = ad;
01758                      mod->sml_type = ad->ad_cname;
01759                      mod->sml_values = NULL;
01760                      mod->sml_nvalues = NULL;
01761                      mod->sml_numvals = 0;
01762 
01763                      *modtail = mod;
01764                      modtail = &mod->sml_next;
01765               }
01766               if ( colon[2] == ' ' ) {
01767                      bv.bv_val = colon + 3;
01768                      bv.bv_len = vals[i].bv_len - ( bv.bv_val - vals[i].bv_val );
01769                      REWRITE_VAL( si, ad, bv, bv2 );
01770                      ber_bvarray_add( &mod->sml_values, &bv2 );
01771                      mod->sml_numvals++;
01772               }
01773        }
01774        *modres = modlist;
01775        return rc;
01776 }
01777 
01778 static int
01779 syncrepl_changelog_mods(
01780        syncinfo_t *si,
01781        struct berval *vals,
01782        struct Modifications **modres
01783 )
01784 {
01785        return -1;    /* FIXME */
01786 }
01787 
01788 typedef struct OpExtraSync {
01789        OpExtra oe;
01790        syncinfo_t *oe_si;
01791 } OpExtraSync;
01792 
01793 /* Copy the original modlist, split Replace ops into Delete/Add,
01794  * and drop mod opattrs since this modification is in the past.
01795  */
01796 static Modifications *mods_dup( Operation *op, Modifications *modlist, int match )
01797 {
01798        Modifications *mod, *modnew = NULL, *modtail = NULL;
01799        int size;
01800        for ( ; modlist; modlist = modlist->sml_next ) {
01801               /* older ops */
01802               if ( match < 0 ) {
01803                      if ( modlist->sml_desc == slap_schema.si_ad_modifiersName ||
01804                             modlist->sml_desc == slap_schema.si_ad_modifyTimestamp ||
01805                             modlist->sml_desc == slap_schema.si_ad_entryCSN )
01806                             continue;
01807                      if ( modlist->sml_op == LDAP_MOD_REPLACE ) {
01808                             mod = op->o_tmpalloc( sizeof(Modifications), op->o_tmpmemctx );
01809                             mod->sml_desc = modlist->sml_desc;
01810                             mod->sml_values = NULL;
01811                             mod->sml_nvalues = NULL;
01812                             mod->sml_op = LDAP_MOD_DELETE;
01813                             mod->sml_numvals = 0;
01814                             mod->sml_flags = 0;
01815                             if ( !modnew )
01816                                    modnew = mod;
01817                             if ( modtail )
01818                                    modtail->sml_next = mod;
01819                             modtail = mod;
01820                      }
01821               }
01822               if ( modlist->sml_numvals ) {
01823                      size = (modlist->sml_numvals+1) * sizeof(struct berval);
01824                      if ( modlist->sml_nvalues ) size *= 2;
01825               } else {
01826                      size = 0;
01827               }
01828               size += sizeof(Modifications);
01829               mod = op->o_tmpalloc( size, op->o_tmpmemctx );
01830               if ( !modnew )
01831                      modnew = mod;
01832               if ( modtail )
01833                      modtail->sml_next = mod;
01834               modtail = mod;
01835               mod->sml_desc = modlist->sml_desc;
01836               mod->sml_numvals = modlist->sml_numvals;
01837               mod->sml_flags = 0;
01838               if ( modlist->sml_numvals ) {
01839                      int i;
01840                      mod->sml_values = (BerVarray)(mod+1);
01841                      for (i=0; i<mod->sml_numvals; i++)
01842                             mod->sml_values[i] = modlist->sml_values[i];
01843                      BER_BVZERO(&mod->sml_values[i]);
01844                      if ( modlist->sml_nvalues ) {
01845                             mod->sml_nvalues = mod->sml_values + mod->sml_numvals + 1;
01846                             for (i=0; i<mod->sml_numvals; i++)
01847                                    mod->sml_nvalues[i] = modlist->sml_nvalues[i];
01848                             BER_BVZERO(&mod->sml_nvalues[i]);
01849                      } else {
01850                             mod->sml_nvalues = NULL;
01851                      }
01852               } else {
01853                      mod->sml_values = NULL;
01854                      mod->sml_nvalues = NULL;
01855               }
01856               if ( match < 0 && modlist->sml_op == LDAP_MOD_REPLACE )
01857                      mod->sml_op = LDAP_MOD_ADD;
01858               else
01859                      mod->sml_op = modlist->sml_op;
01860               mod->sml_next = NULL;
01861        }
01862        return modnew;
01863 }
01864 
01865 typedef struct resolve_ctxt {
01866        syncinfo_t *rx_si;
01867        Modifications *rx_mods;
01868 } resolve_ctxt;
01869 
01870 static void
01871 compare_vals( Modifications *m1, Modifications *m2 )
01872 {
01873        int i, j;
01874        struct berval *bv1, *bv2;
01875 
01876        if ( m2->sml_nvalues ) {
01877               bv2 = m2->sml_nvalues;
01878               bv1 = m1->sml_nvalues;
01879        } else {
01880               bv2 = m2->sml_values;
01881               bv1 = m1->sml_values;
01882        }
01883        for ( j=0; j<m2->sml_numvals; j++ ) {
01884               for ( i=0; i<m1->sml_numvals; i++ ) {
01885                      if ( !ber_bvcmp( &bv1[i], &bv2[j] )) {
01886                             int k;
01887                             for ( k=i; k<m1->sml_numvals-1; k++ ) {
01888                                    m1->sml_values[k] = m1->sml_values[k+1];
01889                                    if ( m1->sml_nvalues )
01890                                           m1->sml_nvalues[k] = m1->sml_nvalues[k+1];
01891                             }
01892                             BER_BVZERO(&m1->sml_values[k]);
01893                             if ( m1->sml_nvalues ) {
01894                                    BER_BVZERO(&m1->sml_nvalues[k]);
01895                             }
01896                             m1->sml_numvals--;
01897                             i--;
01898                      }
01899               }
01900        }
01901 }
01902 
01903 static int
01904 syncrepl_resolve_cb( Operation *op, SlapReply *rs )
01905 {
01906        if ( rs->sr_type == REP_SEARCH ) {
01907               resolve_ctxt *rx = op->o_callback->sc_private;
01908               Attribute *a = attr_find( rs->sr_entry->e_attrs, ad_reqMod );
01909               if ( a ) {
01910                      Modifications *oldmods, *newmods, *m1, *m2, **prev;
01911                      oldmods = rx->rx_mods;
01912                      syncrepl_accesslog_mods( rx->rx_si, a->a_vals, &newmods );
01913                      for ( m2 = newmods; m2; m2=m2->sml_next ) {
01914                             for ( prev = &oldmods, m1 = *prev; m1; m1 = *prev ) {
01915                                    if ( m1->sml_desc != m2->sml_desc ) {
01916                                           prev = &m1->sml_next;
01917                                           continue;
01918                                    }
01919                                    if ( m2->sml_op == LDAP_MOD_DELETE ||
01920                                           m2->sml_op == LDAP_MOD_REPLACE ) {
01921                                           int numvals = m2->sml_numvals;
01922                                           if ( m2->sml_op == LDAP_MOD_REPLACE )
01923                                                  numvals = 0;
01924                                           /* New delete All cancels everything */
01925                                           if ( numvals == 0 ) {
01926 drop:
01927                                                  *prev = m1->sml_next;
01928                                                  op->o_tmpfree( m1, op->o_tmpmemctx );
01929                                                  continue;
01930                                           }
01931                                           if ( m1->sml_op == LDAP_MOD_DELETE ) {
01932                                                  if ( m1->sml_numvals == 0 ) {
01933                                                         /* turn this to SOFTDEL later */
01934                                                         m1->sml_flags = SLAP_MOD_INTERNAL;
01935                                                  } else {
01936                                                         compare_vals( m1, m2 );
01937                                                         if ( !m1->sml_numvals )
01938                                                                goto drop;
01939                                                  }
01940                                           } else if ( m1->sml_op == LDAP_MOD_ADD ) {
01941                                                  compare_vals( m1, m2 );
01942                                                  if ( !m1->sml_numvals )
01943                                                         goto drop;
01944                                           }
01945                                    }
01946 
01947                                    if ( m2->sml_op == LDAP_MOD_ADD ||
01948                                           m2->sml_op == LDAP_MOD_REPLACE ) {
01949                                           if ( m1->sml_op == LDAP_MOD_DELETE ) {
01950                                                  if ( !m1->sml_numvals ) goto drop;
01951                                                  compare_vals( m1, m2 );
01952                                                  if ( !m1->sml_numvals )
01953                                                         goto drop;
01954                                           }
01955                                           if ( m2->sml_desc->ad_type->sat_atype.at_single_value )
01956                                                  goto drop;
01957                                           compare_vals( m1, m2 );
01958                                           if ( !m1->sml_numvals )
01959                                                  goto drop;
01960                                    }
01961                                    prev = &m1->sml_next;
01962                             }
01963                      }
01964                      slap_mods_free( newmods, 1 );
01965               }
01966        }
01967        return LDAP_SUCCESS;
01968 }
01969 
01970 typedef struct modify_ctxt {
01971        Modifications *mx_orig;
01972        Modifications *mx_free;
01973 } modify_ctxt;
01974 
01975 static int
01976 syncrepl_modify_cb( Operation *op, SlapReply *rs )
01977 {
01978        slap_callback *sc = op->o_callback;
01979        modify_ctxt *mx = sc->sc_private;
01980        Modifications *ml;
01981 
01982        op->orm_no_opattrs = 0;
01983        op->orm_modlist = mx->mx_orig;
01984        for ( ml = mx->mx_free; ml; ml = mx->mx_free ) {
01985               mx->mx_free = ml->sml_next;
01986               op->o_tmpfree( ml, op->o_tmpmemctx );
01987        }
01988        op->o_callback = sc->sc_next;
01989        op->o_tmpfree( sc, op->o_tmpmemctx );
01990        return SLAP_CB_CONTINUE;
01991 }
01992 
01993 static int
01994 syncrepl_op_modify( Operation *op, SlapReply *rs )
01995 {
01996        slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
01997        OpExtra *oex;
01998        syncinfo_t *si;
01999        Entry *e;
02000        int rc, match = 0;
02001        Modifications *mod, *newlist;
02002 
02003        LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
02004               if ( oex->oe_key == (void *)syncrepl_message_to_op )
02005                      break;
02006        }
02007        if ( !oex )
02008               return SLAP_CB_CONTINUE;
02009 
02010        si = ((OpExtraSync *)oex)->oe_si;
02011 
02012        /* Check if entryCSN in modlist is newer than entryCSN in entry.
02013         * We do it here because the op has been serialized by accesslog
02014         * by the time we get here. If the CSN is new enough, just do the
02015         * mod. If not, we need to resolve conflicts.
02016         */
02017 
02018        for ( mod = op->orm_modlist; mod; mod=mod->sml_next ) {
02019               if ( mod->sml_desc == slap_schema.si_ad_entryCSN ) break;
02020        }
02021        /* FIXME: what should we do if entryCSN is missing from the mod? */
02022        if ( !mod )
02023               return SLAP_CB_CONTINUE;
02024 
02025        rc = overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on );
02026        if ( rc == 0 ) {
02027               Attribute *a;
02028               const char *text;
02029               a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
02030               value_match( &match, slap_schema.si_ad_entryCSN,
02031                      slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
02032                      SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
02033                      &mod->sml_nvalues[0], &a->a_nvals[0], &text );
02034               overlay_entry_release_ov( op, e, 0, on );
02035        }
02036        /* equal? Should never happen */
02037        if ( match == 0 )
02038               return LDAP_SUCCESS;
02039 
02040        /* mod is older: resolve conflicts...
02041         * 1. Save/copy original modlist. Split Replace to Del/Add.
02042         * 2. Find all mods to this reqDN newer than the mod stamp.
02043         * 3. Resolve any mods in this request that affect attributes
02044         *    touched by newer mods.
02045         *    old         new
02046         *    delete all  delete all  drop
02047         *    delete all  delete X    SOFTDEL
02048         *    delete X    delete all  drop
02049         *    delete X    delete X    drop
02050         *    delete X    delete Y    OK
02051         *    delete all  add X       drop
02052         *    delete X    add X       drop
02053         *    delete X    add Y       OK
02054         *    add X       delete all  drop
02055         *    add X       delete X    drop
02056         *    add X       add X       drop
02057         *    add X       add Y       if SV, drop else OK
02058         *
02059         * 4. Swap original modlist back in response callback so
02060         *    that accesslog logs the original mod.
02061         *
02062         * Even if the mod is newer, other out-of-order changes may
02063         * have been committed, forcing us to tweak the modlist:
02064         * 1. Save/copy original modlist.
02065         * 2. Change deletes to soft deletes.
02066         * 3. Change Adds of single-valued attrs to Replace.
02067         */
02068 
02069        newlist = mods_dup( op, op->orm_modlist, match );
02070 
02071        /* mod is older */
02072        if ( match < 0 ) {
02073               Operation op2 = *op;
02074               AttributeName an[2];
02075               const char *text;
02076               struct berval bv;
02077               char *ptr;
02078               Modifications *ml;
02079               int size, rc;
02080               SlapReply rs1 = {0};
02081               resolve_ctxt rx;
02082               slap_callback cb = { NULL, syncrepl_resolve_cb, NULL, NULL };
02083 
02084               rx.rx_si = si;
02085               rx.rx_mods = newlist;
02086               cb.sc_private = &rx;
02087 
02088               op2.o_tag = LDAP_REQ_SEARCH;
02089               op2.ors_scope = LDAP_SCOPE_SUBTREE;
02090               op2.ors_deref = LDAP_DEREF_NEVER;
02091               op2.o_req_dn = si->si_logbase;
02092               op2.o_req_ndn = si->si_logbase;
02093               op2.ors_tlimit = SLAP_NO_LIMIT;
02094               op2.ors_slimit = SLAP_NO_LIMIT;
02095               op2.ors_limit = NULL;
02096               memset( an, 0, sizeof(an));
02097               an[0].an_desc = ad_reqMod;
02098               an[0].an_name = ad_reqMod->ad_cname;
02099               op2.ors_attrs = an;
02100               op2.ors_attrsonly = 0;
02101 
02102               bv = mod->sml_nvalues[0];
02103 
02104               size = sizeof("(&(entryCSN>=)(reqDN=))");
02105               size += bv.bv_len + op->o_req_ndn.bv_len + si->si_logfilterstr.bv_len;
02106               op2.ors_filterstr.bv_val = op->o_tmpalloc( size, op->o_tmpmemctx );
02107               op2.ors_filterstr.bv_len = sprintf(op2.ors_filterstr.bv_val,
02108                      "(&(entryCSN>=%s)(reqDN=%s)%s)",
02109                      bv.bv_val, op->o_req_ndn.bv_val, si->si_logfilterstr.bv_val );
02110               op2.ors_filter = str2filter_x( op, op2.ors_filterstr.bv_val );
02111 
02112               op2.o_callback = &cb;
02113               op2.o_bd = select_backend( &op2.o_req_ndn, 1 );
02114               op2.o_bd->be_search( &op2, &rs1 );
02115               newlist = rx.rx_mods;
02116        }
02117 
02118        {
02119               slap_callback *sc = op->o_tmpalloc( sizeof(slap_callback) +
02120                      sizeof(modify_ctxt), op->o_tmpmemctx );
02121               modify_ctxt *mx = (modify_ctxt *)(sc+1);
02122               Modifications *ml;
02123 
02124               sc->sc_response = syncrepl_modify_cb;
02125               sc->sc_private = mx;
02126               sc->sc_next = op->o_callback;
02127               sc->sc_cleanup = NULL;
02128               op->o_callback = sc;
02129               op->orm_no_opattrs = 1;
02130               mx->mx_orig = op->orm_modlist;
02131               mx->mx_free = newlist;
02132               for ( ml = newlist; ml; ml=ml->sml_next ) {
02133                      if ( ml->sml_flags == SLAP_MOD_INTERNAL ) {
02134                             ml->sml_flags = 0;
02135                             ml->sml_op = SLAP_MOD_SOFTDEL;
02136                      }
02137                      else if ( ml->sml_op == LDAP_MOD_DELETE )
02138                             ml->sml_op = SLAP_MOD_SOFTDEL;
02139                      else if ( ml->sml_op == LDAP_MOD_ADD &&
02140                             ml->sml_desc->ad_type->sat_atype.at_single_value )
02141                             ml->sml_op = LDAP_MOD_REPLACE;
02142               }
02143               op->orm_modlist = newlist;
02144               op->o_csn = mod->sml_nvalues[0];
02145        }
02146        return SLAP_CB_CONTINUE;
02147 }
02148 
02149 static int
02150 syncrepl_message_to_op(
02151        syncinfo_t    *si,
02152        Operation     *op,
02153        LDAPMessage   *msg
02154 )
02155 {
02156        BerElement    *ber = NULL;
02157        Modifications *modlist = NULL;
02158        logschema *ls;
02159        SlapReply rs = { REP_RESULT };
02160        slap_callback cb = { NULL, null_callback, NULL, NULL };
02161 
02162        const char    *text;
02163        char txtbuf[SLAP_TEXT_BUFLEN];
02164        size_t textlen = sizeof txtbuf;
02165 
02166        struct berval bdn, dn = BER_BVNULL, ndn;
02167        struct berval bv, bv2, *bvals = NULL;
02168        struct berval rdn = BER_BVNULL, sup = BER_BVNULL,
02169               prdn = BER_BVNULL, nrdn = BER_BVNULL,
02170               psup = BER_BVNULL, nsup = BER_BVNULL;
02171        int           rc, deleteOldRdn = 0, freeReqDn = 0;
02172        int           do_graduate = 0;
02173 
02174        if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
02175               Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
02176                      "Message type should be entry (%d)",
02177                      si->si_ridtxt, ldap_msgtype( msg ), 0 );
02178               return -1;
02179        }
02180 
02181        if ( si->si_syncdata == SYNCDATA_ACCESSLOG )
02182               ls = &accesslog_sc;
02183        else
02184               ls = &changelog_sc;
02185 
02186        rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
02187 
02188        if ( rc != LDAP_SUCCESS ) {
02189               Debug( LDAP_DEBUG_ANY,
02190                      "syncrepl_message_to_op: %s dn get failed (%d)",
02191                      si->si_ridtxt, rc, 0 );
02192               return rc;
02193        }
02194 
02195        op->o_tag = LBER_DEFAULT;
02196        op->o_bd = si->si_wbe;
02197 
02198        if ( BER_BVISEMPTY( &bdn )) {
02199               Debug( LDAP_DEBUG_ANY,
02200                      "syncrepl_message_to_op: %s got empty dn",
02201                      si->si_ridtxt, 0, 0 );
02202               return LDAP_OTHER;
02203        }
02204 
02205        while (( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, &bvals ) )
02206               == LDAP_SUCCESS ) {
02207               if ( bv.bv_val == NULL )
02208                      break;
02209 
02210               if ( !ber_bvstrcasecmp( &bv, &ls->ls_dn ) ) {
02211                      bdn = bvals[0];
02212                      REWRITE_DN( si, bdn, bv2, dn, ndn );
02213                      if ( rc != LDAP_SUCCESS ) {
02214                             Debug( LDAP_DEBUG_ANY,
02215                                    "syncrepl_message_to_op: %s "
02216                                    "dn \"%s\" normalization failed (%d)",
02217                                    si->si_ridtxt, bdn.bv_val, rc );
02218                             rc = -1;
02219                             ch_free( bvals );
02220                             goto done;
02221                      }
02222                      ber_dupbv( &op->o_req_dn, &dn );
02223                      ber_dupbv( &op->o_req_ndn, &ndn );
02224                      slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
02225                      slap_sl_free( dn.bv_val, op->o_tmpmemctx );
02226                      freeReqDn = 1;
02227               } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_req ) ) {
02228                      int i = verb_to_mask( bvals[0].bv_val, modops );
02229                      if ( i < 0 ) {
02230                             Debug( LDAP_DEBUG_ANY,
02231                                    "syncrepl_message_to_op: %s unknown op %s",
02232                                    si->si_ridtxt, bvals[0].bv_val, 0 );
02233                             ch_free( bvals );
02234                             rc = -1;
02235                             goto done;
02236                      }
02237                      op->o_tag = modops[i].mask;
02238               } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_mod ) ) {
02239                      /* Parse attribute into modlist */
02240                      if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) {
02241                             rc = syncrepl_accesslog_mods( si, bvals, &modlist );
02242                      } else {
02243                             rc = syncrepl_changelog_mods( si, bvals, &modlist );
02244                      }
02245                      if ( rc ) goto done;
02246               } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newRdn ) ) {
02247                      rdn = bvals[0];
02248               } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_delRdn ) ) {
02249                      if ( !ber_bvstrcasecmp( &slap_true_bv, bvals ) ) {
02250                             deleteOldRdn = 1;
02251                      }
02252               } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newSup ) ) {
02253                      sup = bvals[0];
02254               } else if ( !ber_bvstrcasecmp( &bv,
02255                      &slap_schema.si_ad_entryCSN->ad_cname ) )
02256               {
02257                      slap_queue_csn( op, bvals );
02258                      do_graduate = 1;
02259               }
02260               ch_free( bvals );
02261        }
02262 
02263        /* If we didn't get a mod type or a target DN, bail out */
02264        if ( op->o_tag == LBER_DEFAULT || BER_BVISNULL( &dn ) ) {
02265               rc = -1;
02266               goto done;
02267        }
02268 
02269        op->o_callback = &cb;
02270        slap_op_time( &op->o_time, &op->o_tincr );
02271 
02272        switch( op->o_tag ) {
02273        case LDAP_REQ_ADD:
02274        case LDAP_REQ_MODIFY:
02275               /* If we didn't get required data, bail */
02276               if ( !modlist ) goto done;
02277 
02278               rc = slap_mods_check( op, modlist, &text, txtbuf, textlen, NULL );
02279 
02280               if ( rc != LDAP_SUCCESS ) {
02281                      Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
02282                             "mods check (%s)\n",
02283                             si->si_ridtxt, text, 0 );
02284                      goto done;
02285               }
02286 
02287               if ( op->o_tag == LDAP_REQ_ADD ) {
02288                      Entry *e = entry_alloc();
02289                      op->ora_e = e;
02290                      op->ora_e->e_name = op->o_req_dn;
02291                      op->ora_e->e_nname = op->o_req_ndn;
02292                      freeReqDn = 0;
02293                      rc = slap_mods2entry( modlist, &op->ora_e, 1, 0, &text, txtbuf, textlen);
02294                      if( rc != LDAP_SUCCESS ) {
02295                             Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
02296                             "mods2entry (%s)\n",
02297                                    si->si_ridtxt, text, 0 );
02298                      } else {
02299                             rc = op->o_bd->be_add( op, &rs );
02300                             Debug( LDAP_DEBUG_SYNC,
02301                                    "syncrepl_message_to_op: %s be_add %s (%d)\n", 
02302                                    si->si_ridtxt, op->o_req_dn.bv_val, rc );
02303                             do_graduate = 0;
02304                      }
02305                      if ( e == op->ora_e )
02306                             be_entry_release_w( op, op->ora_e );
02307               } else {
02308                      OpExtraSync oes;
02309                      op->orm_modlist = modlist;
02310                      op->o_bd = si->si_wbe;
02311                      /* delta-mmr needs additional checks in syncrepl_op_modify */
02312                      if ( SLAP_MULTIMASTER( op->o_bd )) {
02313                             oes.oe.oe_key = (void *)syncrepl_message_to_op;
02314                             oes.oe_si = si;
02315                             LDAP_SLIST_INSERT_HEAD( &op->o_extra, &oes.oe, oe_next );
02316                      }
02317                      rc = op->o_bd->be_modify( op, &rs );
02318                      if ( SLAP_MULTIMASTER( op->o_bd )) {
02319                             LDAP_SLIST_REMOVE( &op->o_extra, &oes.oe, OpExtra, oe_next );
02320                             BER_BVZERO( &op->o_csn );
02321                      }
02322                      modlist = op->orm_modlist;
02323                      Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
02324                             "syncrepl_message_to_op: %s be_modify %s (%d)\n", 
02325                             si->si_ridtxt, op->o_req_dn.bv_val, rc );
02326                      op->o_bd = si->si_be;
02327                      do_graduate = 0;
02328               }
02329               break;
02330        case LDAP_REQ_MODRDN:
02331               if ( BER_BVISNULL( &rdn ) ) goto done;
02332 
02333               if ( rdnPretty( NULL, &rdn, &prdn, NULL ) ) {
02334                      goto done;
02335               }
02336               if ( rdnNormalize( 0, NULL, NULL, &rdn, &nrdn, NULL ) ) {
02337                      goto done;
02338               }
02339               if ( !BER_BVISNULL( &sup ) ) {
02340                      REWRITE_DN( si, sup, bv2, psup, nsup );
02341                      if ( rc )
02342                             goto done;
02343                      op->orr_newSup = &psup;
02344                      op->orr_nnewSup = &nsup;
02345               } else {
02346                      op->orr_newSup = NULL;
02347                      op->orr_nnewSup = NULL;
02348               }
02349               op->orr_newrdn = prdn;
02350               op->orr_nnewrdn = nrdn;
02351               op->orr_deleteoldrdn = deleteOldRdn;
02352               op->orr_modlist = NULL;
02353               if ( slap_modrdn2mods( op, &rs ) ) {
02354                      goto done;
02355               }
02356 
02357               /* Append modlist for operational attrs */
02358               {
02359                      Modifications *m;
02360 
02361                      for ( m = op->orr_modlist; m->sml_next; m = m->sml_next )
02362                             ;
02363                      m->sml_next = modlist;
02364                      modlist = NULL;
02365               }
02366               rc = op->o_bd->be_modrdn( op, &rs );
02367               slap_mods_free( op->orr_modlist, 1 );
02368               Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
02369                      "syncrepl_message_to_op: %s be_modrdn %s (%d)\n", 
02370                      si->si_ridtxt, op->o_req_dn.bv_val, rc );
02371               do_graduate = 0;
02372               break;
02373        case LDAP_REQ_DELETE:
02374               rc = op->o_bd->be_delete( op, &rs );
02375               Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
02376                      "syncrepl_message_to_op: %s be_delete %s (%d)\n", 
02377                      si->si_ridtxt, op->o_req_dn.bv_val, rc );
02378               do_graduate = 0;
02379               break;
02380        }
02381 done:
02382        if ( do_graduate )
02383               slap_graduate_commit_csn( op );
02384        op->o_bd = si->si_be;
02385        op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
02386        BER_BVZERO( &op->o_csn );
02387        if ( modlist ) {
02388               slap_mods_free( modlist, op->o_tag != LDAP_REQ_ADD );
02389        }
02390        if ( !BER_BVISNULL( &rdn ) ) {
02391               if ( !BER_BVISNULL( &nsup ) ) {
02392                      ch_free( nsup.bv_val );
02393               }
02394               if ( !BER_BVISNULL( &psup ) ) {
02395                      ch_free( psup.bv_val );
02396               }
02397               if ( !BER_BVISNULL( &nrdn ) ) {
02398                      ch_free( nrdn.bv_val );
02399               }
02400               if ( !BER_BVISNULL( &prdn ) ) {
02401                      ch_free( prdn.bv_val );
02402               }
02403        }
02404        if ( freeReqDn ) {
02405               ch_free( op->o_req_ndn.bv_val );
02406               ch_free( op->o_req_dn.bv_val );
02407        }
02408        ber_free( ber, 0 );
02409        return rc;
02410 }
02411 
02412 static int
02413 syncrepl_message_to_entry(
02414        syncinfo_t    *si,
02415        Operation     *op,
02416        LDAPMessage   *msg,
02417        Modifications **modlist,
02418        Entry                **entry,
02419        int           syncstate,
02420        struct berval *syncUUID
02421 )
02422 {
02423        Entry         *e = NULL;
02424        BerElement    *ber = NULL;
02425        Modifications tmp;
02426        Modifications *mod;
02427        Modifications **modtail = modlist;
02428 
02429        const char    *text;
02430        char txtbuf[SLAP_TEXT_BUFLEN];
02431        size_t textlen = sizeof txtbuf;
02432 
02433        struct berval bdn = BER_BVNULL, dn, ndn, bv2;
02434        int           rc, is_ctx;
02435 
02436        *modlist = NULL;
02437 
02438        if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
02439               Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s "
02440                      "Message type should be entry (%d)",
02441                      si->si_ridtxt, ldap_msgtype( msg ), 0 );
02442               return -1;
02443        }
02444 
02445        op->o_tag = LDAP_REQ_ADD;
02446 
02447        rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
02448        if ( rc != LDAP_SUCCESS ) {
02449               Debug( LDAP_DEBUG_ANY,
02450                      "syncrepl_message_to_entry: %s dn get failed (%d)",
02451                      si->si_ridtxt, rc, 0 );
02452               return rc;
02453        }
02454 
02455        if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) {
02456               Debug( LDAP_DEBUG_ANY,
02457                      "syncrepl_message_to_entry: %s got empty dn",
02458                      si->si_ridtxt, 0, 0 );
02459               return LDAP_OTHER;
02460        }
02461 
02462        /* syncUUID[0] is normalized UUID received over the wire
02463         * syncUUID[1] is denormalized UUID, generated here
02464         */
02465        (void)slap_uuidstr_from_normalized( &syncUUID[1], &syncUUID[0], op->o_tmpmemctx );
02466        Debug( LDAP_DEBUG_SYNC,
02467               "syncrepl_message_to_entry: %s DN: %s, UUID: %s\n",
02468               si->si_ridtxt, bdn.bv_val, syncUUID[1].bv_val );
02469 
02470        if ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_DELETE ) {
02471               /* NOTE: this could be done even before decoding the DN,
02472                * although encoding errors wouldn't be detected */
02473               rc = LDAP_SUCCESS;
02474               goto done;
02475        }
02476 
02477        if ( entry == NULL ) {
02478               return -1;
02479        }
02480 
02481        REWRITE_DN( si, bdn, bv2, dn, ndn );
02482        if ( rc != LDAP_SUCCESS ) {
02483               /* One of the things that could happen is that the schema
02484                * is not lined-up; this could result in unknown attributes.
02485                * A value non conformant to the syntax should be unlikely,
02486                * except when replicating between different versions
02487                * of the software, or when syntax validation bugs are fixed
02488                */
02489               Debug( LDAP_DEBUG_ANY,
02490                      "syncrepl_message_to_entry: "
02491                      "%s dn \"%s\" normalization failed (%d)",
02492                      si->si_ridtxt, bdn.bv_val, rc );
02493               return rc;
02494        }
02495 
02496        ber_dupbv( &op->o_req_dn, &dn );
02497        ber_dupbv( &op->o_req_ndn, &ndn );
02498        slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
02499        slap_sl_free( dn.bv_val, op->o_tmpmemctx );
02500 
02501        is_ctx = dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[0] );
02502 
02503        e = entry_alloc();
02504        e->e_name = op->o_req_dn;
02505        e->e_nname = op->o_req_ndn;
02506 
02507        while ( ber_remaining( ber ) ) {
02508               if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) ==
02509                      LBER_ERROR ) || BER_BVISNULL( &tmp.sml_type ) )
02510               {
02511                      break;
02512               }
02513 
02514               /* Drop all updates to the contextCSN of the context entry
02515                * (ITS#4622, etc.)
02516                */
02517               if ( is_ctx && !strcasecmp( tmp.sml_type.bv_val,
02518                      slap_schema.si_ad_contextCSN->ad_cname.bv_val )) {
02519                      ber_bvarray_free( tmp.sml_values );
02520                      continue;
02521               }
02522 
02523               mod  = (Modifications *) ch_malloc( sizeof( Modifications ) );
02524 
02525               mod->sml_op = LDAP_MOD_REPLACE;
02526               mod->sml_flags = 0;
02527               mod->sml_next = NULL;
02528               mod->sml_desc = NULL;
02529               mod->sml_type = tmp.sml_type;
02530               mod->sml_values = tmp.sml_values;
02531               mod->sml_nvalues = NULL;
02532               mod->sml_numvals = 0;       /* slap_mods_check will set this */
02533 
02534 #ifdef ENABLE_REWRITE
02535               if (si->si_rewrite) {
02536                      AttributeDescription *ad = NULL;
02537                      slap_bv2ad( &tmp.sml_type, &ad, &text );
02538                      if ( ad ) {
02539                             mod->sml_desc = ad;
02540                             mod->sml_type = ad->ad_cname;
02541                             if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) {
02542                                    int i;
02543                                    for ( i = 0; tmp.sml_values[i].bv_val; i++ ) {
02544                                           syncrepl_rewrite_dn( si, &tmp.sml_values[i], &bv2);
02545                                           if ( !BER_BVISNULL( &bv2 )) {
02546                                                  ber_memfree( tmp.sml_values[i].bv_val );
02547                                                  tmp.sml_values[i] = bv2;
02548                                           }
02549                                    }
02550                             }
02551                      }
02552               }
02553 #endif
02554               *modtail = mod;
02555               modtail = &mod->sml_next;
02556        }
02557 
02558        if ( *modlist == NULL ) {
02559               Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s no attributes\n",
02560                      si->si_ridtxt, 0, 0 );
02561               rc = -1;
02562               goto done;
02563        }
02564 
02565        rc = slap_mods_check( op, *modlist, &text, txtbuf, textlen, NULL );
02566 
02567        if ( rc != LDAP_SUCCESS ) {
02568               Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s mods check (%s)\n",
02569                      si->si_ridtxt, text, 0 );
02570               goto done;
02571        }
02572 
02573        /* Strip out dynamically generated attrs */
02574        for ( modtail = modlist; *modtail ; ) {
02575               mod = *modtail;
02576               if ( mod->sml_desc->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
02577                      *modtail = mod->sml_next;
02578                      slap_mod_free( &mod->sml_mod, 0 );
02579                      ch_free( mod );
02580               } else {
02581                      modtail = &mod->sml_next;
02582               }
02583        }
02584 
02585        /* Strip out attrs in exattrs list */
02586        for ( modtail = modlist; *modtail ; ) {
02587               mod = *modtail;
02588               if ( ldap_charray_inlist( si->si_exattrs,
02589                      mod->sml_desc->ad_type->sat_cname.bv_val ) )
02590               {
02591                      *modtail = mod->sml_next;
02592                      slap_mod_free( &mod->sml_mod, 0 );
02593                      ch_free( mod );
02594               } else {
02595                      modtail = &mod->sml_next;
02596               }
02597        }
02598 
02599        rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
02600        if( rc != LDAP_SUCCESS ) {
02601               Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s mods2entry (%s)\n",
02602                      si->si_ridtxt, text, 0 );
02603        }
02604 
02605 done:
02606        ber_free( ber, 0 );
02607        if ( rc != LDAP_SUCCESS ) {
02608               if ( e ) {
02609                      entry_free( e );
02610                      e = NULL;
02611               }
02612        }
02613        if ( entry )
02614               *entry = e;
02615 
02616        return rc;
02617 }
02618 
02619 static struct berval generic_filterstr = BER_BVC("(objectclass=*)");
02620 
02621 /* During a refresh, we may get an LDAP_SYNC_ADD for an already existing
02622  * entry if a previous refresh was interrupted before sending us a new
02623  * context state. We try to compare the new entry to the existing entry
02624  * and ignore the new entry if they are the same.
02625  *
02626  * Also, we may get an update where the entryDN has changed, due to
02627  * a ModDn on the provider. We detect this as well, so we can issue
02628  * the corresponding operation locally.
02629  *
02630  * In the case of a modify, we get a list of all the attributes
02631  * in the original entry. Rather than deleting the entry and re-adding it,
02632  * we issue a Modify request that deletes all the attributes and adds all
02633  * the new ones. This avoids the issue of trying to delete/add a non-leaf
02634  * entry.
02635  *
02636  * We otherwise distinguish ModDN from Modify; in the case of
02637  * a ModDN we just use the CSN, modifyTimestamp and modifiersName
02638  * operational attributes from the entry, and do a regular ModDN.
02639  */
02640 typedef struct dninfo {
02641        Entry *new_entry;
02642        struct berval dn;
02643        struct berval ndn;
02644        struct berval nnewSup;
02645        int renamed;  /* Was an existing entry renamed? */
02646        int delOldRDN;       /* Was old RDN deleted? */
02647        Modifications **modlist;    /* the modlist we received */
02648        Modifications *mods; /* the modlist we compared */
02649        int oldNcount;              /* #values of old naming attr */
02650        AttributeDescription *oldDesc;     /* for renames */
02651        AttributeDescription *newDesc;     /* for renames */
02652 } dninfo;
02653 
02654 /* return 1 if inserted, 0 otherwise */
02655 static int
02656 avl_presentlist_insert(
02657        syncinfo_t* si,
02658        struct berval *syncUUID )
02659 {
02660        struct berval *syncuuid_bv = ch_malloc( sizeof( struct berval ) + syncUUID->bv_len + 1 );
02661 
02662        syncuuid_bv->bv_len = syncUUID->bv_len;
02663        syncuuid_bv->bv_val = (char *)&syncuuid_bv[1];
02664        AC_MEMCPY( syncuuid_bv->bv_val, syncUUID->bv_val, syncUUID->bv_len );
02665        syncuuid_bv->bv_val[ syncuuid_bv->bv_len ] = '\0';
02666 
02667        if ( avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
02668               syncuuid_cmp, avl_dup_error ) )
02669        {
02670               ch_free( syncuuid_bv );
02671               return 0;
02672        }
02673 
02674        return 1;
02675 }
02676 
02677 static int
02678 syncrepl_entry(
02679        syncinfo_t* si,
02680        Operation *op,
02681        Entry* entry,
02682        Modifications** modlist,
02683        int syncstate,
02684        struct berval* syncUUID,
02685        struct berval* syncCSN )
02686 {
02687        Backend *be = op->o_bd;
02688        slap_callback cb = { NULL, NULL, NULL, NULL };
02689        int syncuuid_inserted = 0;
02690 
02691        SlapReply     rs_search = {REP_RESULT};
02692        Filter f = {0};
02693        AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
02694        int rc = LDAP_SUCCESS;
02695 
02696        struct berval pdn = BER_BVNULL;
02697        dninfo dni = {0};
02698        int    retry = 1;
02699        int    freecsn = 1;
02700 
02701        Debug( LDAP_DEBUG_SYNC,
02702               "syncrepl_entry: %s LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_%s)\n",
02703               si->si_ridtxt, syncrepl_state2str( syncstate ), 0 );
02704 
02705        if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ) ) {
02706               if ( !si->si_refreshPresent && !si->si_refreshDone ) {
02707                      syncuuid_inserted = avl_presentlist_insert( si, syncUUID );
02708               }
02709        }
02710 
02711        if ( syncstate == LDAP_SYNC_PRESENT ) {
02712               return 0;
02713        } else if ( syncstate != LDAP_SYNC_DELETE ) {
02714               if ( entry == NULL ) {
02715                      return 0;
02716               }
02717        }
02718 
02719        if ( syncstate != LDAP_SYNC_DELETE ) {
02720               Attribute     *a = attr_find( entry->e_attrs, slap_schema.si_ad_entryUUID );
02721 
02722               if ( a == NULL ) {
02723                      /* add if missing */
02724                      attr_merge_one( entry, slap_schema.si_ad_entryUUID,
02725                             &syncUUID[1], syncUUID );
02726 
02727               } else if ( !bvmatch( &a->a_nvals[0], syncUUID ) ) {
02728                      /* replace only if necessary */
02729                      if ( a->a_nvals != a->a_vals ) {
02730                             ber_memfree( a->a_nvals[0].bv_val );
02731                             ber_dupbv( &a->a_nvals[0], syncUUID );
02732                      }
02733                      ber_memfree( a->a_vals[0].bv_val );
02734                      ber_dupbv( &a->a_vals[0], &syncUUID[1] );
02735               }
02736        }
02737 
02738        f.f_choice = LDAP_FILTER_EQUALITY;
02739        f.f_ava = &ava;
02740        ava.aa_desc = slap_schema.si_ad_entryUUID;
02741        ava.aa_value = *syncUUID;
02742 
02743        if ( syncuuid_inserted ) {
02744               Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s inserted UUID %s\n",
02745                      si->si_ridtxt, syncUUID[1].bv_val, 0 );
02746        }
02747        op->ors_filter = &f;
02748 
02749        op->ors_filterstr.bv_len = STRLENOF( "(entryUUID=)" ) + syncUUID[1].bv_len;
02750        op->ors_filterstr.bv_val = (char *) slap_sl_malloc(
02751               op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); 
02752        AC_MEMCPY( op->ors_filterstr.bv_val, "(entryUUID=", STRLENOF( "(entryUUID=" ) );
02753        AC_MEMCPY( &op->ors_filterstr.bv_val[STRLENOF( "(entryUUID=" )],
02754               syncUUID[1].bv_val, syncUUID[1].bv_len );
02755        op->ors_filterstr.bv_val[op->ors_filterstr.bv_len - 1] = ')';
02756        op->ors_filterstr.bv_val[op->ors_filterstr.bv_len] = '\0';
02757 
02758        op->o_tag = LDAP_REQ_SEARCH;
02759        op->ors_scope = LDAP_SCOPE_SUBTREE;
02760        op->ors_deref = LDAP_DEREF_NEVER;
02761 
02762        /* get the entry for this UUID */
02763 #ifdef ENABLE_REWRITE
02764        if ( si->si_rewrite ) {
02765               op->o_req_dn = si->si_suffixm;
02766               op->o_req_ndn = si->si_suffixm;
02767        } else
02768 #endif
02769        {
02770               op->o_req_dn = si->si_base;
02771               op->o_req_ndn = si->si_base;
02772        }
02773 
02774        op->o_time = slap_get_time();
02775        op->ors_tlimit = SLAP_NO_LIMIT;
02776        op->ors_slimit = 1;
02777        op->ors_limit = NULL;
02778 
02779        op->ors_attrs = slap_anlist_all_attributes;
02780        op->ors_attrsonly = 0;
02781 
02782        /* set callback function */
02783        op->o_callback = &cb;
02784        cb.sc_response = dn_callback;
02785        cb.sc_private = &dni;
02786        dni.new_entry = entry;
02787        dni.modlist = modlist;
02788 
02789        rc = be->be_search( op, &rs_search );
02790        Debug( LDAP_DEBUG_SYNC,
02791                      "syncrepl_entry: %s be_search (%d)\n", 
02792                      si->si_ridtxt, rc, 0 );
02793 
02794        if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
02795               slap_sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
02796        }
02797 
02798        cb.sc_response = null_callback;
02799        cb.sc_private = si;
02800 
02801        if ( entry && !BER_BVISNULL( &entry->e_name ) ) {
02802               Debug( LDAP_DEBUG_SYNC,
02803                             "syncrepl_entry: %s %s\n",
02804                             si->si_ridtxt, entry->e_name.bv_val, 0 );
02805        } else {
02806               Debug( LDAP_DEBUG_SYNC,
02807                             "syncrepl_entry: %s %s\n",
02808                             si->si_ridtxt, dni.dn.bv_val ? dni.dn.bv_val : "(null)", 0 );
02809        }
02810 
02811        assert( BER_BVISNULL( &op->o_csn ) );
02812        if ( syncCSN ) {
02813               slap_queue_csn( op, syncCSN );
02814        }
02815 
02816        slap_op_time( &op->o_time, &op->o_tincr );
02817        switch ( syncstate ) {
02818        case LDAP_SYNC_ADD:
02819        case LDAP_SYNC_MODIFY:
02820               if ( BER_BVISNULL( &op->o_csn ))
02821               {
02822 
02823                      Attribute *a = attr_find( entry->e_attrs, slap_schema.si_ad_entryCSN );
02824                      if ( a ) {
02825                             /* FIXME: op->o_csn is assumed to be
02826                              * on the thread's slab; this needs
02827                              * to be cleared ASAP.
02828                              */
02829                             op->o_csn = a->a_vals[0];
02830                             freecsn = 0;
02831                      }
02832               }
02833 retry_add:;
02834               if ( BER_BVISNULL( &dni.dn ) ) {
02835                      SlapReply     rs_add = {REP_RESULT};
02836 
02837                      op->o_req_dn = entry->e_name;
02838                      op->o_req_ndn = entry->e_nname;
02839                      op->o_tag = LDAP_REQ_ADD;
02840                      op->ora_e = entry;
02841                      op->o_bd = si->si_wbe;
02842 
02843                      rc = op->o_bd->be_add( op, &rs_add );
02844                      Debug( LDAP_DEBUG_SYNC,
02845                                    "syncrepl_entry: %s be_add %s (%d)\n", 
02846                                    si->si_ridtxt, op->o_req_dn.bv_val, rc );
02847                      switch ( rs_add.sr_err ) {
02848                      case LDAP_SUCCESS:
02849                             if ( op->ora_e == entry ) {
02850                                    be_entry_release_w( op, entry );
02851                             }
02852                             entry = NULL;
02853                             break;
02854 
02855                      case LDAP_REFERRAL:
02856                      /* we assume that LDAP_NO_SUCH_OBJECT is returned 
02857                       * only if the suffix entry is not present.
02858                       * This should not happen during Persist phase.
02859                       */
02860                      case LDAP_NO_SUCH_OBJECT:
02861                             if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
02862                                    si->si_refreshDone ) {
02863                                    /* Something's wrong, start over */
02864                                    ber_bvarray_free( si->si_syncCookie.ctxcsn );
02865                                    si->si_syncCookie.ctxcsn = NULL;
02866                                    ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
02867                                    ber_bvarray_free( si->si_cookieState->cs_vals );
02868                                    ch_free( si->si_cookieState->cs_sids );
02869                                    si->si_cookieState->cs_vals = NULL;
02870                                    si->si_cookieState->cs_sids = 0;
02871                                    si->si_cookieState->cs_num = 0;
02872                                    ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
02873                                    return LDAP_NO_SUCH_OBJECT;
02874                             }
02875                             rc = syncrepl_add_glue( op, entry );
02876                             entry = NULL;
02877                             break;
02878 
02879                      /* if an entry was added via syncrepl_add_glue(),
02880                       * it likely has no entryUUID, so the previous
02881                       * be_search() doesn't find it.  In this case,
02882                       * give syncrepl a chance to modify it. Also
02883                       * allow for entries that were recreated with the
02884                       * same DN but a different entryUUID.
02885                       */
02886                      case LDAP_ALREADY_EXISTS:
02887                             if ( retry ) {
02888                                    Operation     op2 = *op;
02889                                    SlapReply     rs2 = { REP_RESULT };
02890                                    slap_callback cb2 = { 0 };
02891 
02892                                    op2.o_bd = be;
02893                                    op2.o_tag = LDAP_REQ_SEARCH;
02894                                    op2.o_req_dn = entry->e_name;
02895                                    op2.o_req_ndn = entry->e_nname;
02896                                    op2.ors_scope = LDAP_SCOPE_BASE;
02897                                    op2.ors_deref = LDAP_DEREF_NEVER;
02898                                    op2.ors_attrs = slap_anlist_all_attributes;
02899                                    op2.ors_attrsonly = 0;
02900                                    op2.ors_limit = NULL;
02901                                    op2.ors_slimit = 1;
02902                                    op2.ors_tlimit = SLAP_NO_LIMIT;
02903 
02904                                    f.f_choice = LDAP_FILTER_PRESENT;
02905                                    f.f_desc = slap_schema.si_ad_objectClass;
02906                                    op2.ors_filter = &f;
02907                                    op2.ors_filterstr = generic_filterstr;
02908 
02909                                    op2.o_callback = &cb2;
02910                                    cb2.sc_response = dn_callback;
02911                                    cb2.sc_private = &dni;
02912 
02913                                    rc = be->be_search( &op2, &rs2 );
02914                                    if ( rc ) goto done;
02915 
02916                                    retry = 0;
02917                                    slap_op_time( &op->o_time, &op->o_tincr );
02918                                    goto retry_add;
02919                             }
02920                             /* FALLTHRU */
02921 
02922                      default:
02923                             Debug( LDAP_DEBUG_ANY,
02924                                    "syncrepl_entry: %s be_add %s failed (%d)\n",
02925                                    si->si_ridtxt, op->o_req_dn.bv_val, rs_add.sr_err );
02926                             break;
02927                      }
02928                      syncCSN = NULL;
02929                      op->o_bd = be;
02930                      goto done;
02931               }
02932               /* FALLTHRU */
02933               op->o_req_dn = dni.dn;
02934               op->o_req_ndn = dni.ndn;
02935               if ( dni.renamed ) {
02936                      struct berval noldp, newp;
02937                      Modifications *mod, **modtail, **ml, *m2;
02938                      int i, got_replace = 0, just_rename = 0;
02939                      SlapReply rs_modify = {REP_RESULT};
02940 
02941                      op->o_tag = LDAP_REQ_MODRDN;
02942                      dnRdn( &entry->e_name, &op->orr_newrdn );
02943                      dnRdn( &entry->e_nname, &op->orr_nnewrdn );
02944 
02945                      if ( !BER_BVISNULL( &dni.nnewSup )) {
02946                             dnParent( &entry->e_name, &newp );
02947                             op->orr_newSup = &newp;
02948                             op->orr_nnewSup = &dni.nnewSup;
02949                      } else {
02950                             op->orr_newSup = NULL;
02951                             op->orr_nnewSup = NULL;
02952                      }
02953                      op->orr_deleteoldrdn = dni.delOldRDN;
02954                      op->orr_modlist = NULL;
02955                      if ( ( rc = slap_modrdn2mods( op, &rs_modify ) ) ) {
02956                             goto done;
02957                      }
02958 
02959                      /* Drop the RDN-related mods from this op, because their
02960                       * equivalents were just setup by slap_modrdn2mods.
02961                       *
02962                       * If delOldRDN is TRUE then we should see a delete modop
02963                       * for oldDesc. We might see a replace instead.
02964                       *  delete with no values: therefore newDesc != oldDesc.
02965                       *   if oldNcount == 1, then Drop this op.
02966                       *  delete with 1 value: can only be the oldRDN value. Drop op.
02967                       *  delete with N values: Drop oldRDN value, keep remainder.
02968                       *  replace with 1 value: if oldNcount == 1 and
02969                       *     newDesc == oldDesc, Drop this op.
02970                       * Any other cases must be left intact.
02971                       *
02972                       * We should also see an add modop for newDesc. (But not if
02973                       * we got a replace modop due to delOldRDN.) If it has
02974                       * multiple values, we'll have to drop the new RDN value.
02975                       */
02976                      modtail = &op->orr_modlist;
02977                      if ( dni.delOldRDN ) {
02978                             for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) {
02979                                    if ( (*ml)->sml_desc == dni.oldDesc ) {
02980                                           mod = *ml;
02981                                           if ( mod->sml_op == LDAP_MOD_REPLACE &&
02982                                                  dni.oldDesc != dni.newDesc ) {
02983                                                  /* This Replace is due to other Mods.
02984                                                   * Just let it ride.
02985                                                   */
02986                                                  continue;
02987                                           }
02988                                           if ( mod->sml_numvals <= 1 &&
02989                                                  dni.oldNcount == 1 &&
02990                                                  ( mod->sml_op == LDAP_MOD_DELETE ||
02991                                                    mod->sml_op == LDAP_MOD_REPLACE )) {
02992                                                  if ( mod->sml_op == LDAP_MOD_REPLACE )
02993                                                         got_replace = 1;
02994                                                  /* Drop this op */
02995                                                  *ml = mod->sml_next;
02996                                                  mod->sml_next = NULL;
02997                                                  slap_mods_free( mod, 1 );
02998                                                  break;
02999                                           }
03000                                           if ( mod->sml_op != LDAP_MOD_DELETE || mod->sml_numvals == 0 )
03001                                                  continue;
03002                                           for ( m2 = op->orr_modlist; m2; m2=m2->sml_next ) {
03003                                                  if ( m2->sml_desc == dni.oldDesc &&
03004                                                         m2->sml_op == LDAP_MOD_DELETE ) break;
03005                                           }
03006                                           for ( i=0; i<mod->sml_numvals; i++ ) {
03007                                                  if ( bvmatch( &mod->sml_values[i], &m2->sml_values[0] )) {
03008                                                         mod->sml_numvals--;
03009                                                         ch_free( mod->sml_values[i].bv_val );
03010                                                         mod->sml_values[i] = mod->sml_values[mod->sml_numvals];
03011                                                         BER_BVZERO( &mod->sml_values[mod->sml_numvals] );
03012                                                         if ( mod->sml_nvalues ) {
03013                                                                ch_free( mod->sml_nvalues[i].bv_val );
03014                                                                mod->sml_nvalues[i] = mod->sml_nvalues[mod->sml_numvals];
03015                                                                BER_BVZERO( &mod->sml_nvalues[mod->sml_numvals] );
03016                                                         }
03017                                                         break;
03018                                                  }
03019                                           }
03020                                           if ( !mod->sml_numvals ) {
03021                                                  /* Drop this op */
03022                                                  *ml = mod->sml_next;
03023                                                  mod->sml_next = NULL;
03024                                                  slap_mods_free( mod, 1 );
03025                                           }
03026                                           break;
03027                                    }
03028                             }
03029                      }
03030                      if ( !got_replace ) {
03031                             for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) {
03032                                    if ( (*ml)->sml_desc == dni.newDesc ) {
03033                                           mod = *ml;
03034                                           if ( mod->sml_op != LDAP_MOD_ADD )
03035                                                  continue;
03036                                           if ( mod->sml_numvals == 1 ) {
03037                                                  /* Drop this op */
03038                                                  *ml = mod->sml_next;
03039                                                  mod->sml_next = NULL;
03040                                                  slap_mods_free( mod, 1 );
03041                                                  break;
03042                                           }
03043                                           for ( m2 = op->orr_modlist; m2; m2=m2->sml_next ) {
03044                                                  if ( m2->sml_desc == dni.oldDesc &&
03045                                                         m2->sml_op == SLAP_MOD_SOFTADD ) break;
03046                                           }
03047                                           for ( i=0; i<mod->sml_numvals; i++ ) {
03048                                                  if ( bvmatch( &mod->sml_values[i], &m2->sml_values[0] )) {
03049                                                         mod->sml_numvals--;
03050                                                         ch_free( mod->sml_values[i].bv_val );
03051                                                         mod->sml_values[i] = mod->sml_values[mod->sml_numvals];
03052                                                         BER_BVZERO( &mod->sml_values[mod->sml_numvals] );
03053                                                         if ( mod->sml_nvalues ) {
03054                                                                ch_free( mod->sml_nvalues[i].bv_val );
03055                                                                mod->sml_nvalues[i] = mod->sml_nvalues[mod->sml_numvals];
03056                                                                BER_BVZERO( &mod->sml_nvalues[mod->sml_numvals] );
03057                                                         }
03058                                                         break;
03059                                                  }
03060                                           }
03061                                           break;
03062                                    }
03063                             }
03064                      }
03065 
03066                      /* RDNs must be NUL-terminated for back-ldap */
03067                      noldp = op->orr_newrdn;
03068                      ber_dupbv_x( &op->orr_newrdn, &noldp, op->o_tmpmemctx );
03069                      noldp = op->orr_nnewrdn;
03070                      ber_dupbv_x( &op->orr_nnewrdn, &noldp, op->o_tmpmemctx );
03071 
03072                      /* Setup opattrs too */
03073                      {
03074                             static AttributeDescription *nullattr = NULL;
03075                             static AttributeDescription **const opattrs[] = {
03076                                    &slap_schema.si_ad_entryCSN,
03077                                    &slap_schema.si_ad_modifiersName,
03078                                    &slap_schema.si_ad_modifyTimestamp,
03079                                    &nullattr
03080                             };
03081                             AttributeDescription *opattr;
03082                             int i;
03083 
03084                             modtail = &m2;
03085                             /* pull mod off incoming modlist */
03086                             for ( i = 0; (opattr = *opattrs[i]) != NULL; i++ ) {
03087                                    for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next )
03088                                    {
03089                                           if ( (*ml)->sml_desc == opattr ) {
03090                                                  mod = *ml;
03091                                                  *ml = mod->sml_next;
03092                                                  mod->sml_next = NULL;
03093                                                  *modtail = mod;
03094                                                  modtail = &mod->sml_next;
03095                                                  break;
03096                                           }
03097                                    }
03098                             }
03099                             /* If there are still Modifications left, put the opattrs
03100                              * back, and let be_modify run. Otherwise, append the opattrs
03101                              * to the orr_modlist.
03102                              */
03103                             if ( dni.mods ) {
03104                                    mod = dni.mods;
03105                                    /* don't set a CSN for the rename op */
03106                                    if ( syncCSN )
03107                                           slap_graduate_commit_csn( op );
03108                             } else {
03109                                    mod = op->orr_modlist;
03110                                    just_rename = 1;
03111                             }
03112                             for ( ; mod->sml_next; mod=mod->sml_next );
03113                             mod->sml_next = m2;
03114                      }
03115                      op->o_bd = si->si_wbe;
03116 retry_modrdn:;
03117                      rs_reinit( &rs_modify, REP_RESULT );
03118                      rc = op->o_bd->be_modrdn( op, &rs_modify );
03119 
03120                      /* NOTE: noSuchObject should result because the new superior
03121                       * has not been added yet (ITS#6472) */
03122                      if ( rc == LDAP_NO_SUCH_OBJECT && op->orr_nnewSup != NULL ) {
03123                             Operation op2 = *op;
03124                             rc = syncrepl_add_glue_ancestors( &op2, entry );
03125                             if ( rc == LDAP_SUCCESS ) {
03126                                    goto retry_modrdn;
03127                             }
03128                      }
03129               
03130                      op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx );
03131                      op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx );
03132 
03133                      slap_mods_free( op->orr_modlist, 1 );
03134                      Debug( LDAP_DEBUG_SYNC,
03135                                    "syncrepl_entry: %s be_modrdn %s (%d)\n", 
03136                                    si->si_ridtxt, op->o_req_dn.bv_val, rc );
03137                      op->o_bd = be;
03138                      /* Renamed entries may still have other mods so just fallthru */
03139                      op->o_req_dn = entry->e_name;
03140                      op->o_req_ndn = entry->e_nname;
03141                      /* Use CSN on the modify */
03142                      if ( just_rename )
03143                             syncCSN = NULL;
03144                      else if ( syncCSN )
03145                             slap_queue_csn( op, syncCSN );
03146               }
03147               if ( dni.mods ) {
03148                      SlapReply rs_modify = {REP_RESULT};
03149 
03150                      op->o_tag = LDAP_REQ_MODIFY;
03151                      op->orm_modlist = dni.mods;
03152                      op->orm_no_opattrs = 1;
03153                      op->o_bd = si->si_wbe;
03154 
03155                      rc = op->o_bd->be_modify( op, &rs_modify );
03156                      slap_mods_free( op->orm_modlist, 1 );
03157                      op->orm_no_opattrs = 0;
03158                      Debug( LDAP_DEBUG_SYNC,
03159                                    "syncrepl_entry: %s be_modify %s (%d)\n", 
03160                                    si->si_ridtxt, op->o_req_dn.bv_val, rc );
03161                      if ( rs_modify.sr_err != LDAP_SUCCESS ) {
03162                             Debug( LDAP_DEBUG_ANY,
03163                                    "syncrepl_entry: %s be_modify failed (%d)\n",
03164                                    si->si_ridtxt, rs_modify.sr_err, 0 );
03165                      }
03166                      syncCSN = NULL;
03167                      op->o_bd = be;
03168               } else if ( !dni.renamed ) {
03169                      Debug( LDAP_DEBUG_SYNC,
03170                                    "syncrepl_entry: %s entry unchanged, ignored (%s)\n", 
03171                                    si->si_ridtxt, op->o_req_dn.bv_val, 0 );
03172                      if ( syncCSN ) {
03173                             slap_graduate_commit_csn( op );
03174                             syncCSN = NULL;
03175                      }
03176               }
03177               goto done;
03178        case LDAP_SYNC_DELETE :
03179               if ( !BER_BVISNULL( &dni.dn ) ) {
03180                      SlapReply     rs_delete = {REP_RESULT};
03181                      op->o_req_dn = dni.dn;
03182                      op->o_req_ndn = dni.ndn;
03183                      op->o_tag = LDAP_REQ_DELETE;
03184                      op->o_bd = si->si_wbe;
03185                      if ( !syncCSN ) {
03186                             slap_queue_csn( op, si->si_syncCookie.ctxcsn );
03187                      }
03188                      rc = op->o_bd->be_delete( op, &rs_delete );
03189                      Debug( LDAP_DEBUG_SYNC,
03190                                    "syncrepl_entry: %s be_delete %s (%d)\n", 
03191                                    si->si_ridtxt, op->o_req_dn.bv_val, rc );
03192                      if ( rc == LDAP_NO_SUCH_OBJECT )
03193                             rc = LDAP_SUCCESS;
03194 
03195                      while ( rs_delete.sr_err == LDAP_SUCCESS
03196                             && op->o_delete_glue_parent ) {
03197                             op->o_delete_glue_parent = 0;
03198                             if ( !be_issuffix( be, &op->o_req_ndn ) ) {
03199                                    slap_callback cb = { NULL };
03200                                    cb.sc_response = slap_null_cb;
03201                                    dnParent( &op->o_req_ndn, &pdn );
03202                                    op->o_req_dn = pdn;
03203                                    op->o_req_ndn = pdn;
03204                                    op->o_callback = &cb;
03205                                    rs_reinit( &rs_delete, REP_RESULT );
03206                                    op->o_bd->be_delete( op, &rs_delete );
03207                             } else {
03208                                    break;
03209                             }
03210                      }
03211                      syncCSN = NULL;
03212                      op->o_bd = be;
03213               }
03214               goto done;
03215 
03216        default :
03217               Debug( LDAP_DEBUG_ANY,
03218                      "syncrepl_entry: %s unknown syncstate\n", si->si_ridtxt, 0, 0 );
03219               goto done;
03220        }
03221 
03222 done:
03223        slap_sl_free( syncUUID[1].bv_val, op->o_tmpmemctx );
03224        BER_BVZERO( &syncUUID[1] );
03225        if ( !BER_BVISNULL( &dni.ndn ) ) {
03226               op->o_tmpfree( dni.ndn.bv_val, op->o_tmpmemctx );
03227        }
03228        if ( !BER_BVISNULL( &dni.dn ) ) {
03229               op->o_tmpfree( dni.dn.bv_val, op->o_tmpmemctx );
03230        }
03231        if ( entry ) {
03232               entry_free( entry );
03233        }
03234        if ( syncCSN ) {
03235               slap_graduate_commit_csn( op );
03236        }
03237        if ( !BER_BVISNULL( &op->o_csn ) && freecsn ) {
03238               op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
03239        }
03240        BER_BVZERO( &op->o_csn );
03241        return rc;
03242 }
03243 
03244 static struct berval gcbva[] = {
03245        BER_BVC("top"),
03246        BER_BVC("glue"),
03247        BER_BVNULL
03248 };
03249 
03250 #define NP_DELETE_ONE       2
03251 
03252 static void
03253 syncrepl_del_nonpresent(
03254        Operation *op,
03255        syncinfo_t *si,
03256        BerVarray uuids,
03257        struct sync_cookie *sc,
03258        int m )
03259 {
03260        Backend* be = op->o_bd;
03261        slap_callback cb = { NULL };
03262        struct nonpresent_entry *np_list, *np_prev;
03263        int rc;
03264        AttributeName an[2];
03265 
03266        struct berval pdn = BER_BVNULL;
03267        struct berval csn;
03268 
03269 #ifdef ENABLE_REWRITE
03270        if ( si->si_rewrite ) {
03271               op->o_req_dn = si->si_suffixm;
03272               op->o_req_ndn = si->si_suffixm;
03273        } else
03274 #endif
03275        {
03276               op->o_req_dn = si->si_base;
03277               op->o_req_ndn = si->si_base;
03278        }
03279 
03280        cb.sc_response = nonpresent_callback;
03281        cb.sc_private = si;
03282 
03283        op->o_callback = &cb;
03284        op->o_tag = LDAP_REQ_SEARCH;
03285        op->ors_scope = si->si_scope;
03286        op->ors_deref = LDAP_DEREF_NEVER;
03287        op->o_time = slap_get_time();
03288        op->ors_tlimit = SLAP_NO_LIMIT;
03289 
03290 
03291        if ( uuids ) {
03292               Filter uf;
03293               AttributeAssertion eq = ATTRIBUTEASSERTION_INIT;
03294               int i;
03295 
03296               op->ors_attrsonly = 1;
03297               op->ors_attrs = slap_anlist_no_attrs;
03298               op->ors_limit = NULL;
03299               op->ors_filter = &uf;
03300 
03301               uf.f_ava = &eq;
03302               uf.f_av_desc = slap_schema.si_ad_entryUUID;
03303               uf.f_next = NULL;
03304               uf.f_choice = LDAP_FILTER_EQUALITY;
03305               si->si_refreshDelete |= NP_DELETE_ONE;
03306 
03307               for (i=0; uuids[i].bv_val; i++) {
03308                      SlapReply rs_search = {REP_RESULT};
03309 
03310                      op->ors_slimit = 1;
03311                      uf.f_av_value = uuids[i];
03312                      filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
03313                      rc = be->be_search( op, &rs_search );
03314                      op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
03315               }
03316               si->si_refreshDelete ^= NP_DELETE_ONE;
03317        } else {
03318               Filter *cf, *of;
03319               Filter mmf[2];
03320               AttributeAssertion mmaa;
03321               SlapReply rs_search = {REP_RESULT};
03322 
03323               memset( &an[0], 0, 2 * sizeof( AttributeName ) );
03324               an[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
03325               an[0].an_desc = slap_schema.si_ad_entryUUID;
03326               op->ors_attrs = an;
03327               op->ors_slimit = SLAP_NO_LIMIT;
03328               op->ors_tlimit = SLAP_NO_LIMIT;
03329               op->ors_limit = NULL;
03330               op->ors_attrsonly = 0;
03331               op->ors_filter = filter_dup( si->si_filter, op->o_tmpmemctx );
03332               /* In multimaster, updates can continue to arrive while
03333                * we're searching. Limit the search result to entries
03334                * older than our newest cookie CSN.
03335                */
03336               if ( SLAP_MULTIMASTER( op->o_bd )) {
03337                      Filter *f;
03338                      int i;
03339 
03340                      f = mmf;
03341                      f->f_choice = LDAP_FILTER_AND;
03342                      f->f_next = op->ors_filter;
03343                      f->f_and = f+1;
03344                      of = f->f_and;
03345                      f = of;
03346                      f->f_choice = LDAP_FILTER_LE;
03347                      f->f_ava = &mmaa;
03348                      f->f_av_desc = slap_schema.si_ad_entryCSN;
03349                      f->f_next = NULL;
03350                      BER_BVZERO( &f->f_av_value );
03351                      for ( i=0; i<sc->numcsns; i++ ) {
03352                             if ( ber_bvcmp( &sc->ctxcsn[i], &f->f_av_value ) > 0 )
03353                                    f->f_av_value = sc->ctxcsn[i];
03354                      }
03355                      of = op->ors_filter;
03356                      op->ors_filter = mmf;
03357                      filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
03358               } else {
03359                      cf = NULL;
03360                      op->ors_filterstr = si->si_filterstr;
03361               }
03362               op->o_nocaching = 1;
03363 
03364 
03365               rc = be->be_search( op, &rs_search );
03366               if ( SLAP_MULTIMASTER( op->o_bd )) {
03367                      op->ors_filter = of;
03368               }
03369               if ( op->ors_filter ) filter_free_x( op, op->ors_filter, 1 );
03370               if ( op->ors_filterstr.bv_val != si->si_filterstr.bv_val ) {
03371                      op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
03372               }
03373 
03374        }
03375 
03376        op->o_nocaching = 0;
03377 
03378        if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
03379 
03380               if ( sc->ctxcsn && !BER_BVISNULL( &sc->ctxcsn[m] ) ) {
03381                      csn = sc->ctxcsn[m];
03382               } else {
03383                      csn = si->si_syncCookie.ctxcsn[0];
03384               }
03385 
03386               op->o_bd = si->si_wbe;
03387               slap_queue_csn( op, &csn );
03388 
03389               np_list = LDAP_LIST_FIRST( &si->si_nonpresentlist );
03390               while ( np_list != NULL ) {
03391                      SlapReply rs_delete = {REP_RESULT};
03392 
03393                      LDAP_LIST_REMOVE( np_list, npe_link );
03394                      np_prev = np_list;
03395                      np_list = LDAP_LIST_NEXT( np_list, npe_link );
03396                      op->o_tag = LDAP_REQ_DELETE;
03397                      op->o_callback = &cb;
03398                      cb.sc_response = null_callback;
03399                      cb.sc_private = si;
03400                      op->o_req_dn = *np_prev->npe_name;
03401                      op->o_req_ndn = *np_prev->npe_nname;
03402                      rc = op->o_bd->be_delete( op, &rs_delete );
03403                      Debug( LDAP_DEBUG_SYNC,
03404                             "syncrepl_del_nonpresent: %s be_delete %s (%d)\n", 
03405                             si->si_ridtxt, op->o_req_dn.bv_val, rc );
03406 
03407                      if ( rs_delete.sr_err == LDAP_NOT_ALLOWED_ON_NONLEAF ) {
03408                             SlapReply rs_modify = {REP_RESULT};
03409                             Modifications mod1, mod2;
03410                             mod1.sml_op = LDAP_MOD_REPLACE;
03411                             mod1.sml_flags = 0;
03412                             mod1.sml_desc = slap_schema.si_ad_objectClass;
03413                             mod1.sml_type = mod1.sml_desc->ad_cname;
03414                             mod1.sml_numvals = 2;
03415                             mod1.sml_values = &gcbva[0];
03416                             mod1.sml_nvalues = NULL;
03417                             mod1.sml_next = &mod2;
03418 
03419                             mod2.sml_op = LDAP_MOD_REPLACE;
03420                             mod2.sml_flags = 0;
03421                             mod2.sml_desc = slap_schema.si_ad_structuralObjectClass;
03422                             mod2.sml_type = mod2.sml_desc->ad_cname;
03423                             mod2.sml_numvals = 1;
03424                             mod2.sml_values = &gcbva[1];
03425                             mod2.sml_nvalues = NULL;
03426                             mod2.sml_next = NULL;
03427 
03428                             op->o_tag = LDAP_REQ_MODIFY;
03429                             op->orm_modlist = &mod1;
03430 
03431                             rc = op->o_bd->be_modify( op, &rs_modify );
03432                             if ( mod2.sml_next ) slap_mods_free( mod2.sml_next, 1 );
03433                      }
03434 
03435                      while ( rs_delete.sr_err == LDAP_SUCCESS &&
03436                                    op->o_delete_glue_parent ) {
03437                             op->o_delete_glue_parent = 0;
03438                             if ( !be_issuffix( be, &op->o_req_ndn ) ) {
03439                                    slap_callback cb = { NULL };
03440                                    cb.sc_response = slap_null_cb;
03441                                    dnParent( &op->o_req_ndn, &pdn );
03442                                    op->o_req_dn = pdn;
03443                                    op->o_req_ndn = pdn;
03444                                    op->o_callback = &cb;
03445                                    rs_reinit( &rs_delete, REP_RESULT );
03446                                    /* give it a root privil ? */
03447                                    op->o_bd->be_delete( op, &rs_delete );
03448                             } else {
03449                                    break;
03450                             }
03451                      }
03452 
03453                      op->o_delete_glue_parent = 0;
03454 
03455                      ber_bvfree( np_prev->npe_name );
03456                      ber_bvfree( np_prev->npe_nname );
03457                      ch_free( np_prev );
03458 
03459                      if ( slapd_shutdown ) {
03460                             break;
03461                      }
03462               }
03463 
03464               slap_graduate_commit_csn( op );
03465               op->o_bd = be;
03466 
03467               op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
03468               BER_BVZERO( &op->o_csn );
03469        }
03470 
03471        return;
03472 }
03473 
03474 static int
03475 syncrepl_add_glue_ancestors(
03476        Operation* op,
03477        Entry *e )
03478 {
03479        Backend *be = op->o_bd;
03480        slap_callback cb = { NULL };
03481        Attribute     *a;
03482        int    rc = LDAP_SUCCESS;
03483        int suffrdns;
03484        int i;
03485        struct berval dn = BER_BVNULL;
03486        struct berval ndn = BER_BVNULL;
03487        Entry  *glue;
03488        struct berval ptr, nptr;
03489        char          *comma;
03490 
03491        op->o_tag = LDAP_REQ_ADD;
03492        op->o_callback = &cb;
03493        cb.sc_response = null_callback;
03494        cb.sc_private = NULL;
03495 
03496        dn = e->e_name;
03497        ndn = e->e_nname;
03498 
03499        /* count RDNs in suffix */
03500        if ( !BER_BVISEMPTY( &be->be_nsuffix[0] ) ) {
03501               for ( i = 0, ptr = be->be_nsuffix[0], comma = ptr.bv_val; comma != NULL; comma = ber_bvchr( &ptr, ',' ) ) {
03502                      comma++;
03503                      ptr.bv_len -= comma - ptr.bv_val;
03504                      ptr.bv_val = comma;
03505                      i++;
03506               }
03507               suffrdns = i;
03508        } else {
03509               /* suffix is "" */
03510               suffrdns = 0;
03511        }
03512 
03513        /* Start with BE suffix */
03514        ptr = dn;
03515        for ( i = 0; i < suffrdns; i++ ) {
03516               comma = ber_bvrchr( &ptr, ',' );
03517               if ( comma != NULL ) {
03518                      ptr.bv_len = comma - ptr.bv_val;
03519               } else {
03520                      ptr.bv_len = 0;
03521                      break;
03522               }
03523        }
03524        
03525        if ( !BER_BVISEMPTY( &ptr ) ) {
03526               dn.bv_len -= ptr.bv_len + ( suffrdns != 0 );
03527               dn.bv_val += ptr.bv_len + ( suffrdns != 0 );
03528        }
03529 
03530        /* the normalizedDNs are always the same length, no counting
03531         * required.
03532         */
03533        nptr = ndn;
03534        if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) {
03535               ndn.bv_val += ndn.bv_len - be->be_nsuffix[0].bv_len;
03536               ndn.bv_len = be->be_nsuffix[0].bv_len;
03537 
03538               nptr.bv_len = ndn.bv_val - nptr.bv_val - 1;
03539 
03540        } else {
03541               nptr.bv_len = 0;
03542        }
03543 
03544        while ( ndn.bv_val > e->e_nname.bv_val ) {
03545               SlapReply     rs_add = {REP_RESULT};
03546 
03547               glue = entry_alloc();
03548               ber_dupbv( &glue->e_name, &dn );
03549               ber_dupbv( &glue->e_nname, &ndn );
03550 
03551               a = attr_alloc( slap_schema.si_ad_objectClass );
03552 
03553               a->a_numvals = 2;
03554               a->a_vals = ch_calloc( 3, sizeof( struct berval ) );
03555               ber_dupbv( &a->a_vals[0], &gcbva[0] );
03556               ber_dupbv( &a->a_vals[1], &gcbva[1] );
03557               ber_dupbv( &a->a_vals[2], &gcbva[2] );
03558 
03559               a->a_nvals = a->a_vals;
03560 
03561               a->a_next = glue->e_attrs;
03562               glue->e_attrs = a;
03563 
03564               a = attr_alloc( slap_schema.si_ad_structuralObjectClass );
03565 
03566               a->a_numvals = 1;
03567               a->a_vals = ch_calloc( 2, sizeof( struct berval ) );
03568               ber_dupbv( &a->a_vals[0], &gcbva[1] );
03569               ber_dupbv( &a->a_vals[1], &gcbva[2] );
03570 
03571               a->a_nvals = a->a_vals;
03572 
03573               a->a_next = glue->e_attrs;
03574               glue->e_attrs = a;
03575 
03576               op->o_req_dn = glue->e_name;
03577               op->o_req_ndn = glue->e_nname;
03578               op->ora_e = glue;
03579               rc = be->be_add ( op, &rs_add );
03580               if ( rs_add.sr_err == LDAP_SUCCESS ) {
03581                      if ( op->ora_e == glue )
03582                             be_entry_release_w( op, glue );
03583               } else {
03584               /* incl. ALREADY EXIST */
03585                      entry_free( glue );
03586                      if ( rs_add.sr_err != LDAP_ALREADY_EXISTS ) {
03587                             entry_free( e );
03588                             return rc;
03589                      }
03590               }
03591 
03592               /* Move to next child */
03593               comma = ber_bvrchr( &ptr, ',' );
03594               if ( comma == NULL ) {
03595                      break;
03596               }
03597               ptr.bv_len = comma - ptr.bv_val;
03598               
03599               dn.bv_val = ++comma;
03600               dn.bv_len = e->e_name.bv_len - (dn.bv_val - e->e_name.bv_val);
03601 
03602               comma = ber_bvrchr( &nptr, ',' );
03603               assert( comma != NULL );
03604               nptr.bv_len = comma - nptr.bv_val;
03605 
03606               ndn.bv_val = ++comma;
03607               ndn.bv_len = e->e_nname.bv_len - (ndn.bv_val - e->e_nname.bv_val);
03608        }
03609 
03610        return rc;
03611 }
03612 
03613 int
03614 syncrepl_add_glue(
03615        Operation* op,
03616        Entry *e )
03617 {
03618        slap_callback cb = { NULL };
03619        int    rc;
03620        Backend *be = op->o_bd;
03621        SlapReply     rs_add = {REP_RESULT};
03622 
03623        rc = syncrepl_add_glue_ancestors( op, e );
03624        switch ( rc ) {
03625        case LDAP_SUCCESS:
03626        case LDAP_ALREADY_EXISTS:
03627               break;
03628 
03629        default:
03630               return rc;
03631        }
03632 
03633        op->o_tag = LDAP_REQ_ADD;
03634        op->o_callback = &cb;
03635        cb.sc_response = null_callback;
03636        cb.sc_private = NULL;
03637 
03638        op->o_req_dn = e->e_name;
03639        op->o_req_ndn = e->e_nname;
03640        op->ora_e = e;
03641        rc = be->be_add ( op, &rs_add );
03642        if ( rs_add.sr_err == LDAP_SUCCESS ) {
03643               if ( op->ora_e == e )
03644                      be_entry_release_w( op, e );
03645        } else {
03646               entry_free( e );
03647        }
03648 
03649        return rc;
03650 }
03651 
03652 static int
03653 syncrepl_updateCookie(
03654        syncinfo_t *si,
03655        Operation *op,
03656        struct sync_cookie *syncCookie )
03657 {
03658        Backend *be = op->o_bd;
03659        Modifications mod;
03660        struct berval first = BER_BVNULL;
03661        struct sync_cookie sc;
03662 #ifdef CHECK_CSN
03663        Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax;
03664 #endif
03665 
03666        int rc, i, j, changed = 0;
03667        ber_len_t len;
03668 
03669        slap_callback cb = { NULL };
03670        SlapReply     rs_modify = {REP_RESULT};
03671 
03672        mod.sml_op = LDAP_MOD_REPLACE;
03673        mod.sml_desc = slap_schema.si_ad_contextCSN;
03674        mod.sml_type = mod.sml_desc->ad_cname;
03675        mod.sml_flags = SLAP_MOD_INTERNAL;
03676        mod.sml_nvalues = NULL;
03677        mod.sml_next = NULL;
03678 
03679        ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
03680 
03681 #ifdef CHECK_CSN
03682        for ( i=0; i<syncCookie->numcsns; i++ ) {
03683               assert( !syn->ssyn_validate( syn, syncCookie->ctxcsn+i ));
03684        }
03685        for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
03686               assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i ));
03687        }
03688 #endif
03689 
03690        /* clone the cookieState CSNs so we can Replace the whole thing */
03691        sc.numcsns = si->si_cookieState->cs_num;
03692        if ( sc.numcsns ) {
03693               ber_bvarray_dup_x( &sc.ctxcsn, si->si_cookieState->cs_vals, NULL );
03694               sc.sids = ch_malloc( sc.numcsns * sizeof(int));
03695               for ( i=0; i<sc.numcsns; i++ )
03696                      sc.sids[i] = si->si_cookieState->cs_sids[i];
03697        } else {
03698               sc.ctxcsn = NULL;
03699               sc.sids = NULL;
03700        }
03701 
03702        /* find any CSNs in the syncCookie that are newer than the cookieState */
03703        for ( i=0; i<syncCookie->numcsns; i++ ) {
03704               for ( j=0; j<sc.numcsns; j++ ) {
03705                      if ( syncCookie->sids[i] < sc.sids[j] )
03706                             break;
03707                      if ( syncCookie->sids[i] != sc.sids[j] )
03708                             continue;
03709                      len = syncCookie->ctxcsn[i].bv_len;
03710                      if ( len > sc.ctxcsn[j].bv_len )
03711                             len = sc.ctxcsn[j].bv_len;
03712                      if ( memcmp( syncCookie->ctxcsn[i].bv_val,
03713                             sc.ctxcsn[j].bv_val, len ) > 0 ) {
03714                             ber_bvreplace( &sc.ctxcsn[j], &syncCookie->ctxcsn[i] );
03715                             changed = 1;
03716                             if ( BER_BVISNULL( &first ) ||
03717                                    memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
03718                                    first = syncCookie->ctxcsn[i];
03719                             }
03720                      }
03721                      break;
03722               }
03723               /* there was no match for this SID, it's a new CSN */
03724               if ( j == sc.numcsns ||
03725                      syncCookie->sids[i] != sc.sids[j] ) {
03726                      slap_insert_csn_sids( &sc, j, syncCookie->sids[i],
03727                             &syncCookie->ctxcsn[i] );
03728                      if ( BER_BVISNULL( &first ) ||
03729                             memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
03730                             first = syncCookie->ctxcsn[i];
03731                      }
03732                      changed = 1;
03733               }
03734        }
03735        /* Should never happen, ITS#5065 */
03736        if ( BER_BVISNULL( &first ) || !changed ) {
03737               ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
03738               ber_bvarray_free( sc.ctxcsn );
03739               ch_free( sc.sids );
03740               return 0;
03741        }
03742        op->o_bd = si->si_wbe;
03743        slap_queue_csn( op, &first );
03744 
03745        op->o_tag = LDAP_REQ_MODIFY;
03746 
03747        cb.sc_response = null_callback;
03748        cb.sc_private = si;
03749 
03750        op->o_callback = &cb;
03751        op->o_req_dn = si->si_contextdn;
03752        op->o_req_ndn = si->si_contextdn;
03753 
03754        /* update contextCSN */
03755        op->o_dont_replicate = 1;
03756 
03757        mod.sml_numvals = sc.numcsns;
03758        mod.sml_values = sc.ctxcsn;
03759 
03760        op->orm_modlist = &mod;
03761        op->orm_no_opattrs = 1;
03762        rc = op->o_bd->be_modify( op, &rs_modify );
03763 
03764        if ( rs_modify.sr_err == LDAP_NO_SUCH_OBJECT &&
03765               SLAP_SYNC_SUBENTRY( op->o_bd )) {
03766               const char    *text;
03767               char txtbuf[SLAP_TEXT_BUFLEN];
03768               size_t textlen = sizeof txtbuf;
03769               Entry *e = slap_create_context_csn_entry( op->o_bd, NULL );
03770               rs_reinit( &rs_modify, REP_RESULT );
03771               rc = slap_mods2entry( &mod, &e, 0, 1, &text, txtbuf, textlen);
03772               op->ora_e = e;
03773               rc = op->o_bd->be_add( op, &rs_modify );
03774               if ( e == op->ora_e )
03775                      be_entry_release_w( op, op->ora_e );
03776        }
03777 
03778        op->orm_no_opattrs = 0;
03779        op->o_dont_replicate = 0;
03780 
03781        if ( rs_modify.sr_err == LDAP_SUCCESS ) {
03782               slap_sync_cookie_free( &si->si_syncCookie, 0 );
03783               ber_bvarray_free( si->si_cookieState->cs_vals );
03784               ch_free( si->si_cookieState->cs_sids );
03785               si->si_cookieState->cs_vals = sc.ctxcsn;
03786               si->si_cookieState->cs_sids = sc.sids;
03787               si->si_cookieState->cs_num = sc.numcsns;
03788 
03789               /* Don't just dup the provider's cookie, recreate it */
03790               si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
03791               ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn, si->si_cookieState->cs_vals, NULL );
03792               si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num * sizeof(int) );
03793               for ( i=0; i<si->si_cookieState->cs_num; i++ )
03794                      si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i];
03795 
03796               si->si_cookieState->cs_age++;
03797               si->si_cookieAge = si->si_cookieState->cs_age;
03798        } else {
03799               Debug( LDAP_DEBUG_ANY,
03800                      "syncrepl_updateCookie: %s be_modify failed (%d)\n",
03801                      si->si_ridtxt, rs_modify.sr_err, 0 );
03802               ch_free( sc.sids );
03803               ber_bvarray_free( sc.ctxcsn );
03804        }
03805        ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
03806 
03807        op->o_bd = be;
03808        op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
03809        BER_BVZERO( &op->o_csn );
03810        if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
03811 
03812 #ifdef CHECK_CSN
03813        for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
03814               assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i ));
03815        }
03816 #endif
03817 
03818        return rc;
03819 }
03820 
03821 /* Compare the attribute from the old entry to the one in the new
03822  * entry. The Modifications from the new entry will either be left
03823  * in place, or changed to an Add or Delete as needed.
03824  */
03825 static void
03826 attr_cmp( Operation *op, Attribute *old, Attribute *new,
03827        Modifications ***mret, Modifications ***mcur )
03828 {
03829        int i, j;
03830        Modifications *mod, **modtail;
03831 
03832        modtail = *mret;
03833 
03834        if ( old ) {
03835               int n, o, nn, no;
03836               struct berval **adds, **dels;
03837               /* count old and new */
03838               for ( o=0; old->a_vals[o].bv_val; o++ ) ;
03839               for ( n=0; new->a_vals[n].bv_val; n++ ) ;
03840 
03841               /* there MUST be both old and new values */
03842               assert( o != 0 );
03843               assert( n != 0 );
03844               j = 0;
03845 
03846               adds = op->o_tmpalloc( sizeof(struct berval *) * n, op->o_tmpmemctx );
03847               dels = op->o_tmpalloc( sizeof(struct berval *) * o, op->o_tmpmemctx );
03848 
03849               for ( i=0; i<o; i++ ) dels[i] = &old->a_vals[i];
03850               for ( i=0; i<n; i++ ) adds[i] = &new->a_vals[i];
03851 
03852               nn = n; no = o;
03853 
03854               for ( i=0; i<o; i++ ) {
03855                      for ( j=0; j<n; j++ ) {
03856                             if ( !adds[j] )
03857                                    continue;
03858                             if ( bvmatch( dels[i], adds[j] ) ) {
03859                                    no--;
03860                                    nn--;
03861                                    adds[j] = NULL;
03862                                    dels[i] = NULL;
03863                                    break;
03864                             }
03865                      }
03866               }
03867 
03868               /* Don't delete/add an objectClass, always use the replace op.
03869                * Modify would fail if provider has replaced entry with a new,
03870                * and the new explicitly includes a superior of a class that was
03871                * only included implicitly in the old entry.  Ref ITS#5517.
03872                *
03873                * Also use replace op if attr has no equality matching rule.
03874                * (ITS#5781)
03875                */
03876               if ( ( nn || ( no > 0 && no < o ) ) &&
03877                      ( old->a_desc == slap_schema.si_ad_objectClass ||
03878                       !old->a_desc->ad_type->sat_equality ) )
03879               {
03880                      no = o;
03881               }
03882 
03883               i = j;
03884               /* all old values were deleted, just use the replace op */
03885               if ( no == o ) {
03886                      i = j-1;
03887               } else if ( no ) {
03888               /* delete some values */
03889                      mod = ch_malloc( sizeof( Modifications ) );
03890                      mod->sml_op = LDAP_MOD_DELETE;
03891                      mod->sml_flags = 0;
03892                      mod->sml_desc = old->a_desc;
03893                      mod->sml_type = mod->sml_desc->ad_cname;
03894                      mod->sml_numvals = no;
03895                      mod->sml_values = ch_malloc( ( no + 1 ) * sizeof(struct berval) );
03896                      if ( old->a_vals != old->a_nvals ) {
03897                             mod->sml_nvalues = ch_malloc( ( no + 1 ) * sizeof(struct berval) );
03898                      } else {
03899                             mod->sml_nvalues = NULL;
03900                      }
03901                      j = 0;
03902                      for ( i = 0; i < o; i++ ) {
03903                             if ( !dels[i] ) continue;
03904                             ber_dupbv( &mod->sml_values[j], &old->a_vals[i] );
03905                             if ( mod->sml_nvalues ) {
03906                                    ber_dupbv( &mod->sml_nvalues[j], &old->a_nvals[i] );
03907                             }
03908                             j++;
03909                      }
03910                      BER_BVZERO( &mod->sml_values[j] );
03911                      if ( mod->sml_nvalues ) {
03912                             BER_BVZERO( &mod->sml_nvalues[j] );
03913                      }
03914                      *modtail = mod;
03915                      modtail = &mod->sml_next;
03916                      i = j;
03917               }
03918               op->o_tmpfree( dels, op->o_tmpmemctx );
03919               /* some values were added */
03920               if ( nn && no < o ) {
03921                      mod = ch_malloc( sizeof( Modifications ) );
03922                      mod->sml_op = LDAP_MOD_ADD;
03923                      mod->sml_flags = 0;
03924                      mod->sml_desc = old->a_desc;
03925                      mod->sml_type = mod->sml_desc->ad_cname;
03926                      mod->sml_numvals = nn;
03927                      mod->sml_values = ch_malloc( ( nn + 1 ) * sizeof(struct berval) );
03928                      if ( old->a_vals != old->a_nvals ) {
03929                             mod->sml_nvalues = ch_malloc( ( nn + 1 ) * sizeof(struct berval) );
03930                      } else {
03931                             mod->sml_nvalues = NULL;
03932                      }
03933                      j = 0;
03934                      for ( i = 0; i < n; i++ ) {
03935                             if ( !adds[i] ) continue;
03936                             ber_dupbv( &mod->sml_values[j], &new->a_vals[i] );
03937                             if ( mod->sml_nvalues ) {
03938                                    ber_dupbv( &mod->sml_nvalues[j], &new->a_nvals[i] );
03939                             }
03940                             j++;
03941                      }
03942                      BER_BVZERO( &mod->sml_values[j] );
03943                      if ( mod->sml_nvalues ) {
03944                             BER_BVZERO( &mod->sml_nvalues[j] );
03945                      }
03946                      *modtail = mod;
03947                      modtail = &mod->sml_next;
03948                      i = j;
03949               }
03950               op->o_tmpfree( adds, op->o_tmpmemctx );
03951        } else {
03952               /* new attr, just use the new mod */
03953               i = 0;
03954               j = 1;
03955        }
03956        /* advance to next element */
03957        mod = **mcur;
03958        if ( mod ) {
03959               if ( i != j ) {
03960                      **mcur = mod->sml_next;
03961                      *modtail = mod;
03962                      modtail = &mod->sml_next;
03963               } else {
03964                      *mcur = &mod->sml_next;
03965               }
03966        }
03967        *mret = modtail;
03968 }
03969 
03970 /* Generate a set of modifications to change the old entry into the
03971  * new one. On input ml is a list of modifications equivalent to
03972  * the new entry. It will be massaged and the result will be stored
03973  * in mods.
03974  */
03975 void syncrepl_diff_entry( Operation *op, Attribute *old, Attribute *new,
03976        Modifications **mods, Modifications **ml, int is_ctx)
03977 {
03978        Modifications **modtail = mods;
03979 
03980        /* We assume that attributes are saved in the same order
03981         * in the remote and local databases. So if we walk through
03982         * the attributeDescriptions one by one they should match in
03983         * lock step. If not, look for an add or delete.
03984         */
03985        while ( old && new )
03986        {
03987               /* If we've seen this before, use its mod now */
03988               if ( new->a_flags & SLAP_ATTR_IXADD ) {
03989                      attr_cmp( op, NULL, new, &modtail, &ml );
03990                      new = new->a_next;
03991                      continue;
03992               }
03993               /* Skip contextCSN */
03994               if ( is_ctx && old->a_desc ==
03995                      slap_schema.si_ad_contextCSN ) {
03996                      old = old->a_next;
03997                      continue;
03998               }
03999 
04000               if ( old->a_desc != new->a_desc ) {
04001                      Modifications *mod;
04002                      Attribute *tmp;
04003 
04004                      /* If it's just been re-added later,
04005                       * remember that we've seen it.
04006                       */
04007                      tmp = attr_find( new, old->a_desc );
04008                      if ( tmp ) {
04009                             tmp->a_flags |= SLAP_ATTR_IXADD;
04010                      } else {
04011                             /* If it's a new attribute, pull it in.
04012                              */
04013                             tmp = attr_find( old, new->a_desc );
04014                             if ( !tmp ) {
04015                                    attr_cmp( op, NULL, new, &modtail, &ml );
04016                                    new = new->a_next;
04017                                    continue;
04018                             }
04019                             /* Delete old attr */
04020                             mod = ch_malloc( sizeof( Modifications ) );
04021                             mod->sml_op = LDAP_MOD_DELETE;
04022                             mod->sml_flags = 0;
04023                             mod->sml_desc = old->a_desc;
04024                             mod->sml_type = mod->sml_desc->ad_cname;
04025                             mod->sml_numvals = 0;
04026                             mod->sml_values = NULL;
04027                             mod->sml_nvalues = NULL;
04028                             *modtail = mod;
04029                             modtail = &mod->sml_next;
04030                      }
04031                      old = old->a_next;
04032                      continue;
04033               }
04034               /* kludge - always update modifiersName so that it
04035                * stays co-located with the other mod opattrs. But only
04036                * if we know there are other valid mods.
04037                */
04038               if ( *mods && ( old->a_desc == slap_schema.si_ad_modifiersName ||
04039                      old->a_desc == slap_schema.si_ad_modifyTimestamp ))
04040                      attr_cmp( op, NULL, new, &modtail, &ml );
04041               else
04042                      attr_cmp( op, old, new, &modtail, &ml );
04043               new = new->a_next;
04044               old = old->a_next;
04045        }
04046        *modtail = *ml;
04047        *ml = NULL;
04048 }
04049 
04050 static int
04051 dn_callback(
04052        Operation*    op,
04053        SlapReply*    rs )
04054 {
04055        dninfo *dni = op->o_callback->sc_private;
04056 
04057        if ( rs->sr_type == REP_SEARCH ) {
04058               if ( !BER_BVISNULL( &dni->dn ) ) {
04059                      Debug( LDAP_DEBUG_ANY,
04060                             "dn_callback : consistency error - "
04061                             "entryUUID is not unique\n", 0, 0, 0 );
04062               } else {
04063                      ber_dupbv_x( &dni->dn, &rs->sr_entry->e_name, op->o_tmpmemctx );
04064                      ber_dupbv_x( &dni->ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx );
04065                      /* If there is a new entry, see if it differs from the old.
04066                       * We compare the non-normalized values so that cosmetic changes
04067                       * in the provider are always propagated.
04068                       */
04069                      if ( dni->new_entry ) {
04070                             Attribute *old, *new;
04071                             struct berval old_rdn, new_rdn;
04072                             struct berval old_p, new_p;
04073                             int is_ctx, new_sup = 0;
04074 
04075                             /* If old entry is not a glue entry, make sure new entry
04076                              * is actually newer than old entry
04077                              */
04078                             if ( !is_entry_glue( rs->sr_entry )) {
04079                                    old = attr_find( rs->sr_entry->e_attrs,
04080                                           slap_schema.si_ad_entryCSN );
04081                                    new = attr_find( dni->new_entry->e_attrs,
04082                                           slap_schema.si_ad_entryCSN );
04083                                    if ( new && old ) {
04084                                           int rc;
04085                                           ber_len_t len = old->a_vals[0].bv_len;
04086                                           if ( len > new->a_vals[0].bv_len )
04087                                                  len = new->a_vals[0].bv_len;
04088                                           rc = memcmp( old->a_vals[0].bv_val,
04089                                                  new->a_vals[0].bv_val, len );
04090                                           if ( rc > 0 ) {
04091                                                  Debug( LDAP_DEBUG_SYNC,
04092                                                         "dn_callback : new entry is older than ours "
04093                                                         "%s ours %s, new %s\n",
04094                                                         rs->sr_entry->e_name.bv_val,
04095                                                         old->a_vals[0].bv_val,
04096                                                         new->a_vals[0].bv_val );
04097                                                  return LDAP_SUCCESS;
04098                                           } else if ( rc == 0 ) {
04099                                                  Debug( LDAP_DEBUG_SYNC,
04100                                                         "dn_callback : entries have identical CSN "
04101                                                         "%s %s\n",
04102                                                         rs->sr_entry->e_name.bv_val,
04103                                                         old->a_vals[0].bv_val, 0 );
04104                                                  return LDAP_SUCCESS;
04105                                           }
04106                                    }
04107                             }
04108 
04109                             is_ctx = dn_match( &rs->sr_entry->e_nname,
04110                                    &op->o_bd->be_nsuffix[0] );
04111 
04112                             /* Did the DN change?
04113                              * case changes in the parent are ignored,
04114                              * we only want to know if the RDN was
04115                              * actually changed.
04116                              */
04117                             dnRdn( &rs->sr_entry->e_name, &old_rdn );
04118                             dnRdn( &dni->new_entry->e_name, &new_rdn );
04119                             dnParent( &rs->sr_entry->e_nname, &old_p );
04120                             dnParent( &dni->new_entry->e_nname, &new_p );
04121 
04122                             new_sup = !dn_match( &old_p, &new_p );
04123                             if ( !dn_match( &old_rdn, &new_rdn ) || new_sup )
04124                             {
04125                                    struct berval oldRDN, oldVal;
04126                                    AttributeDescription *ad = NULL;
04127                                    int oldpos, newpos;
04128                                    Attribute *a;
04129 
04130                                    dni->renamed = 1;
04131                                    if ( new_sup )
04132                                           dni->nnewSup = new_p;
04133 
04134                                    /* See if the oldRDN was deleted */
04135                                    dnRdn( &rs->sr_entry->e_nname, &oldRDN );
04136                                    oldVal.bv_val = strchr(oldRDN.bv_val, '=') + 1;
04137                                    oldVal.bv_len = oldRDN.bv_len - ( oldVal.bv_val -
04138                                           oldRDN.bv_val );
04139                                    oldRDN.bv_len -= oldVal.bv_len + 1;
04140                                    slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
04141                                    dni->oldDesc = ad;
04142                                    for ( oldpos=0, a=rs->sr_entry->e_attrs;
04143                                           a && a->a_desc != ad; oldpos++, a=a->a_next );
04144                                    /* a should not be NULL but apparently it happens.
04145                                     * ITS#7144
04146                                     */
04147                                    dni->oldNcount = a ? a->a_numvals : 0;
04148                                    for ( newpos=0, a=dni->new_entry->e_attrs;
04149                                           a && a->a_desc != ad; newpos++, a=a->a_next );
04150                                    if ( !a || oldpos != newpos || attr_valfind( a,
04151                                           SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
04152                                           SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
04153                                           SLAP_MR_VALUE_OF_SYNTAX,
04154                                           &oldVal, NULL, op->o_tmpmemctx ) != LDAP_SUCCESS )
04155                                    {
04156                                           dni->delOldRDN = 1;
04157                                    }
04158                                    /* Get the newRDN's desc */
04159                                    dnRdn( &dni->new_entry->e_nname, &oldRDN );
04160                                    oldVal.bv_val = strchr(oldRDN.bv_val, '=');
04161                                    oldRDN.bv_len = oldVal.bv_val - oldRDN.bv_val;
04162                                    ad = NULL;
04163                                    slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
04164                                    dni->newDesc = ad;
04165 
04166                                    /* A ModDN has happened, but in Refresh mode other
04167                                     * changes may have occurred before we picked it up.
04168                                     * So fallthru to regular Modify processing.
04169                                     */
04170                             }
04171 
04172                             syncrepl_diff_entry( op, rs->sr_entry->e_attrs,
04173                                    dni->new_entry->e_attrs, &dni->mods, dni->modlist,
04174                                    is_ctx );
04175                      }
04176               }
04177        } else if ( rs->sr_type == REP_RESULT ) {
04178               if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) {
04179                      Debug( LDAP_DEBUG_ANY,
04180                             "dn_callback : consistency error - "
04181                             "entryUUID is not unique\n", 0, 0, 0 );
04182               }
04183        }
04184 
04185        return LDAP_SUCCESS;
04186 }
04187 
04188 static int
04189 nonpresent_callback(
04190        Operation*    op,
04191        SlapReply*    rs )
04192 {
04193        syncinfo_t *si = op->o_callback->sc_private;
04194        Attribute *a;
04195        int count = 0;
04196        struct berval* present_uuid = NULL;
04197        struct nonpresent_entry *np_entry;
04198 
04199        if ( rs->sr_type == REP_RESULT ) {
04200               count = avl_free( si->si_presentlist, ch_free );
04201               si->si_presentlist = NULL;
04202 
04203        } else if ( rs->sr_type == REP_SEARCH ) {
04204               if ( !( si->si_refreshDelete & NP_DELETE_ONE ) ) {
04205                      a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
04206 
04207                      if ( a ) {
04208                             present_uuid = avl_find( si->si_presentlist, &a->a_nvals[0],
04209                                    syncuuid_cmp );
04210                      }
04211 
04212                      if ( LogTest( LDAP_DEBUG_SYNC ) ) {
04213                             char buf[sizeof("rid=999 non")];
04214 
04215                             snprintf( buf, sizeof(buf), "%s %s", si->si_ridtxt,
04216                                    present_uuid ? "" : "non" );
04217 
04218                             Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %spresent UUID %s, dn %s\n",
04219                                    buf, a ? a->a_vals[0].bv_val : "<missing>", rs->sr_entry->e_name.bv_val );
04220                      }
04221 
04222                      if ( a == NULL ) return 0;
04223               }
04224 
04225               if ( present_uuid == NULL ) {
04226                      np_entry = (struct nonpresent_entry *)
04227                             ch_calloc( 1, sizeof( struct nonpresent_entry ) );
04228                      np_entry->npe_name = ber_dupbv( NULL, &rs->sr_entry->e_name );
04229                      np_entry->npe_nname = ber_dupbv( NULL, &rs->sr_entry->e_nname );
04230                      LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link );
04231 
04232               } else {
04233                      avl_delete( &si->si_presentlist,
04234                             &a->a_nvals[0], syncuuid_cmp );
04235                      ch_free( present_uuid );
04236               }
04237        }
04238        return LDAP_SUCCESS;
04239 }
04240 
04241 static int
04242 null_callback(
04243        Operation*    op,
04244        SlapReply*    rs )
04245 {
04246        if ( rs->sr_err != LDAP_SUCCESS &&
04247               rs->sr_err != LDAP_REFERRAL &&
04248               rs->sr_err != LDAP_ALREADY_EXISTS &&
04249               rs->sr_err != LDAP_NO_SUCH_OBJECT &&
04250               rs->sr_err != LDAP_NOT_ALLOWED_ON_NONLEAF )
04251        {
04252               Debug( LDAP_DEBUG_ANY,
04253                      "null_callback : error code 0x%x\n",
04254                      rs->sr_err, 0, 0 );
04255        }
04256        return LDAP_SUCCESS;
04257 }
04258 
04259 static struct berval *
04260 slap_uuidstr_from_normalized(
04261        struct berval* uuidstr,
04262        struct berval* normalized,
04263        void *ctx )
04264 {
04265 #if 0
04266        struct berval *new;
04267        unsigned char nibble;
04268        int i, d = 0;
04269 
04270        if ( normalized == NULL ) return NULL;
04271        if ( normalized->bv_len != 16 ) return NULL;
04272 
04273        if ( uuidstr ) {
04274               new = uuidstr;
04275        } else {
04276               new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx );
04277               if ( new == NULL ) {
04278                      return NULL;
04279               }
04280        }
04281 
04282        new->bv_len = 36;
04283 
04284        if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) {
04285               if ( new != uuidstr ) {
04286                      slap_sl_free( new, ctx );
04287               }
04288               return NULL;
04289        }
04290 
04291        for ( i = 0; i < 16; i++ ) {
04292               if ( i == 4 || i == 6 || i == 8 || i == 10 ) {
04293                      new->bv_val[(i<<1)+d] = '-';
04294                      d += 1;
04295               }
04296 
04297               nibble = (normalized->bv_val[i] >> 4) & 0xF;
04298               if ( nibble < 10 ) {
04299                      new->bv_val[(i<<1)+d] = nibble + '0';
04300               } else {
04301                      new->bv_val[(i<<1)+d] = nibble - 10 + 'a';
04302               }
04303 
04304               nibble = (normalized->bv_val[i]) & 0xF;
04305               if ( nibble < 10 ) {
04306                      new->bv_val[(i<<1)+d+1] = nibble + '0';
04307               } else {
04308                      new->bv_val[(i<<1)+d+1] = nibble - 10 + 'a';
04309               }
04310        }
04311 
04312        new->bv_val[new->bv_len] = '\0';
04313        return new;
04314 #endif
04315 
04316        struct berval *new;
04317        int           rc = 0;
04318 
04319        if ( normalized == NULL ) return NULL;
04320        if ( normalized->bv_len != 16 ) return NULL;
04321 
04322        if ( uuidstr ) {
04323               new = uuidstr;
04324 
04325        } else {
04326               new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx );
04327               if ( new == NULL ) {
04328                      return NULL;
04329               }
04330        }
04331 
04332        new->bv_len = 36;
04333 
04334        if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) {
04335               rc = 1;
04336               goto done;
04337        }
04338 
04339        rc = lutil_uuidstr_from_normalized( normalized->bv_val,
04340               normalized->bv_len, new->bv_val, new->bv_len + 1 );
04341 
04342 done:;
04343        if ( rc == -1 ) {
04344               if ( new != NULL ) {
04345                      if ( new->bv_val != NULL ) {
04346                             slap_sl_free( new->bv_val, ctx );
04347                      }
04348 
04349                      if ( new != uuidstr ) {
04350                             slap_sl_free( new, ctx );
04351                      }
04352               }
04353               new = NULL;
04354 
04355        } else {
04356               new->bv_len = rc;
04357        }
04358 
04359        return new;
04360 }
04361 
04362 static int
04363 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
04364 {
04365        const struct berval *uuid1 = v_uuid1;
04366        const struct berval *uuid2 = v_uuid2;
04367        int rc = uuid1->bv_len - uuid2->bv_len;
04368        if ( rc ) return rc;
04369        return ( memcmp( uuid1->bv_val, uuid2->bv_val, uuid1->bv_len ) );
04370 }
04371 
04372 void
04373 syncinfo_free( syncinfo_t *sie, int free_all )
04374 {
04375        syncinfo_t *si_next;
04376 
04377        Debug( LDAP_DEBUG_TRACE, "syncinfo_free: %s\n",
04378               sie->si_ridtxt, 0, 0 );
04379 
04380        do {
04381               si_next = sie->si_next;
04382 
04383               if ( sie->si_ld ) {
04384                      if ( sie->si_conn ) {
04385                             connection_client_stop( sie->si_conn );
04386                             sie->si_conn = NULL;
04387                      }
04388                      ldap_unbind_ext( sie->si_ld, NULL, NULL );
04389               }
04390        
04391               if ( sie->si_re ) {
04392                      struct re_s          *re = sie->si_re;
04393                      sie->si_re = NULL;
04394 
04395                      ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
04396                      if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
04397                             ldap_pvt_runqueue_stoptask( &slapd_rq, re );
04398                      ldap_pvt_runqueue_remove( &slapd_rq, re );
04399                      ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
04400               }
04401 
04402               ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
04403 
04404               bindconf_free( &sie->si_bindconf );
04405 
04406               if ( sie->si_filterstr.bv_val ) {
04407                      ch_free( sie->si_filterstr.bv_val );
04408               }
04409               if ( sie->si_filter ) {
04410                      filter_free( sie->si_filter );
04411               }
04412               if ( sie->si_logfilterstr.bv_val ) {
04413                      ch_free( sie->si_logfilterstr.bv_val );
04414               }
04415               if ( sie->si_base.bv_val ) {
04416                      ch_free( sie->si_base.bv_val );
04417               }
04418               if ( sie->si_logbase.bv_val ) {
04419                      ch_free( sie->si_logbase.bv_val );
04420               }
04421               if ( sie->si_be && SLAP_SYNC_SUBENTRY( sie->si_be )) {
04422                      ch_free( sie->si_contextdn.bv_val );
04423               }
04424               if ( sie->si_attrs ) {
04425                      int i = 0;
04426                      while ( sie->si_attrs[i] != NULL ) {
04427                             ch_free( sie->si_attrs[i] );
04428                             i++;
04429                      }
04430                      ch_free( sie->si_attrs );
04431               }
04432               if ( sie->si_exattrs ) {
04433                      int i = 0;
04434                      while ( sie->si_exattrs[i] != NULL ) {
04435                             ch_free( sie->si_exattrs[i] );
04436                             i++;
04437                      }
04438                      ch_free( sie->si_exattrs );
04439               }
04440               if ( sie->si_anlist ) {
04441                      int i = 0;
04442                      while ( sie->si_anlist[i].an_name.bv_val != NULL ) {
04443                             ch_free( sie->si_anlist[i].an_name.bv_val );
04444                             i++;
04445                      }
04446                      ch_free( sie->si_anlist );
04447               }
04448               if ( sie->si_exanlist ) {
04449                      int i = 0;
04450                      while ( sie->si_exanlist[i].an_name.bv_val != NULL ) {
04451                             ch_free( sie->si_exanlist[i].an_name.bv_val );
04452                             i++;
04453                      }
04454                      ch_free( sie->si_exanlist );
04455               }
04456               if ( sie->si_retryinterval ) {
04457                      ch_free( sie->si_retryinterval );
04458               }
04459               if ( sie->si_retrynum ) {
04460                      ch_free( sie->si_retrynum );
04461               }
04462               if ( sie->si_retrynum_init ) {
04463                      ch_free( sie->si_retrynum_init );
04464               }
04465               slap_sync_cookie_free( &sie->si_syncCookie, 0 );
04466               if ( sie->si_presentlist ) {
04467                   avl_free( sie->si_presentlist, ch_free );
04468               }
04469               while ( !LDAP_LIST_EMPTY( &sie->si_nonpresentlist ) ) {
04470                      struct nonpresent_entry* npe;
04471                      npe = LDAP_LIST_FIRST( &sie->si_nonpresentlist );
04472                      LDAP_LIST_REMOVE( npe, npe_link );
04473                      if ( npe->npe_name ) {
04474                             if ( npe->npe_name->bv_val ) {
04475                                    ch_free( npe->npe_name->bv_val );
04476                             }
04477                             ch_free( npe->npe_name );
04478                      }
04479                      if ( npe->npe_nname ) {
04480                             if ( npe->npe_nname->bv_val ) {
04481                                    ch_free( npe->npe_nname->bv_val );
04482                             }
04483                             ch_free( npe->npe_nname );
04484                      }
04485                      ch_free( npe );
04486               }
04487               if ( sie->si_cookieState ) {
04488                      sie->si_cookieState->cs_ref--;
04489                      if ( !sie->si_cookieState->cs_ref ) {
04490                             ch_free( sie->si_cookieState->cs_sids );
04491                             ber_bvarray_free( sie->si_cookieState->cs_vals );
04492                             ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
04493                             ch_free( sie->si_cookieState->cs_psids );
04494                             ber_bvarray_free( sie->si_cookieState->cs_pvals );
04495                             ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_pmutex );
04496                             ch_free( sie->si_cookieState );
04497                      }
04498               }
04499 #ifdef ENABLE_REWRITE
04500               if ( sie->si_rewrite )
04501                      rewrite_info_delete( &sie->si_rewrite );
04502               if ( sie->si_suffixm.bv_val )
04503                      ch_free( sie->si_suffixm.bv_val );
04504 #endif
04505               ch_free( sie );
04506               sie = si_next;
04507        } while ( free_all && si_next );
04508 }
04509 
04510 #ifdef ENABLE_REWRITE
04511 static int
04512 config_suffixm( ConfigArgs *c, syncinfo_t *si )
04513 {
04514        char *argvEngine[] = { "rewriteEngine", "on", NULL };
04515        char *argvContext[] = { "rewriteContext", SUFFIXM_CTX, NULL };
04516        char *argvRule[] = { "rewriteRule", NULL, NULL, ":", NULL };
04517        char *vnc, *rnc;
04518        int rc;
04519 
04520        if ( si->si_rewrite )
04521               rewrite_info_delete( &si->si_rewrite );
04522        si->si_rewrite = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
04523 
04524        rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvEngine );
04525        if ( rc != LDAP_SUCCESS )
04526               return rc;
04527 
04528        rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvContext );
04529        if ( rc != LDAP_SUCCESS )
04530               return rc;
04531 
04532        vnc = ch_malloc( si->si_base.bv_len + 6 );
04533        strcpy( vnc, "(.*)" );
04534        lutil_strcopy( lutil_strcopy( vnc+4, si->si_base.bv_val ), "$" );
04535        argvRule[1] = vnc;
04536 
04537        rnc = ch_malloc( si->si_suffixm.bv_len + 3 );
04538        strcpy( rnc, "%1" );
04539        strcpy( rnc+2, si->si_suffixm.bv_val );
04540        argvRule[2] = rnc;
04541 
04542        rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 4, argvRule );
04543        ch_free( vnc );
04544        ch_free( rnc );
04545        return rc;
04546 }
04547 #endif
04548 
04549 /* NOTE: used & documented in slapd.conf(5) */
04550 #define IDSTR               "rid"
04551 #define PROVIDERSTR         "provider"
04552 #define SCHEMASTR           "schemachecking"
04553 #define FILTERSTR           "filter"
04554 #define SEARCHBASESTR              "searchbase"
04555 #define SCOPESTR            "scope"
04556 #define ATTRSONLYSTR        "attrsonly"
04557 #define ATTRSSTR            "attrs"
04558 #define TYPESTR                    "type"
04559 #define INTERVALSTR         "interval"
04560 #define RETRYSTR            "retry"
04561 #define SLIMITSTR           "sizelimit"
04562 #define TLIMITSTR           "timelimit"
04563 #define SYNCDATASTR         "syncdata"
04564 #define LOGBASESTR          "logbase"
04565 #define LOGFILTERSTR "logfilter"
04566 #define SUFFIXMSTR          "suffixmassage"
04567 #define       STRICT_REFRESH       "strictrefresh"
04568 
04569 /* FIXME: undocumented */
04570 #define EXATTRSSTR          "exattrs"
04571 #define MANAGEDSAITSTR             "manageDSAit"
04572 
04573 /* mandatory */
04574 enum {
04575        GOT_RID                     = 0x00000001U,
04576        GOT_PROVIDER         = 0x00000002U,
04577        GOT_SCHEMACHECKING   = 0x00000004U,
04578        GOT_FILTER           = 0x00000008U,
04579        GOT_SEARCHBASE              = 0x00000010U,
04580        GOT_SCOPE            = 0x00000020U,
04581        GOT_ATTRSONLY        = 0x00000040U,
04582        GOT_ATTRS            = 0x00000080U,
04583        GOT_TYPE             = 0x00000100U,
04584        GOT_INTERVAL         = 0x00000200U,
04585        GOT_RETRY            = 0x00000400U,
04586        GOT_SLIMIT           = 0x00000800U,
04587        GOT_TLIMIT           = 0x00001000U,
04588        GOT_SYNCDATA         = 0x00002000U,
04589        GOT_LOGBASE          = 0x00004000U,
04590        GOT_LOGFILTER        = 0x00008000U,
04591        GOT_EXATTRS          = 0x00010000U,
04592        GOT_MANAGEDSAIT             = 0x00020000U,
04593        GOT_BINDCONF         = 0x00040000U,
04594        GOT_SUFFIXM          = 0x00080000U,
04595 
04596 /* check */
04597        GOT_REQUIRED         = (GOT_RID|GOT_PROVIDER|GOT_SEARCHBASE)
04598 };
04599 
04600 static slap_verbmasks datamodes[] = {
04601        { BER_BVC("default"), SYNCDATA_DEFAULT },
04602        { BER_BVC("accesslog"), SYNCDATA_ACCESSLOG },
04603        { BER_BVC("changelog"), SYNCDATA_CHANGELOG },
04604        { BER_BVNULL, 0 }
04605 };
04606 
04607 static int
04608 parse_syncrepl_retry(
04609        ConfigArgs    *c,
04610        char          *arg,
04611        syncinfo_t    *si )
04612 {
04613        char **retry_list;
04614        int j, k, n;
04615        int use_default = 0;
04616 
04617        char *val = arg + STRLENOF( RETRYSTR "=" );
04618        if ( strcasecmp( val, "undefined" ) == 0 ) {
04619               val = "3600 +";
04620               use_default = 1;
04621        }
04622 
04623        retry_list = (char **) ch_calloc( 1, sizeof( char * ) );
04624        retry_list[0] = NULL;
04625 
04626        slap_str2clist( &retry_list, val, " ,\t" );
04627 
04628        for ( k = 0; retry_list && retry_list[k]; k++ ) ;
04629        n = k / 2;
04630        if ( k % 2 ) {
04631               snprintf( c->cr_msg, sizeof( c->cr_msg ),
04632                      "Error: incomplete syncrepl retry list" );
04633               Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04634               for ( k = 0; retry_list && retry_list[k]; k++ ) {
04635                      ch_free( retry_list[k] );
04636               }
04637               ch_free( retry_list );
04638               return 1;
04639        }
04640        si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t ) );
04641        si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int ) );
04642        si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int ) );
04643        for ( j = 0; j < n; j++ ) {
04644               unsigned long t;
04645               if ( lutil_atoul( &t, retry_list[j*2] ) != 0 ) {
04646                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
04647                             "Error: invalid retry interval \"%s\" (#%d)",
04648                             retry_list[j*2], j );
04649                      Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04650                      /* do some cleanup */
04651                      return 1;
04652               }
04653               si->si_retryinterval[j] = (time_t)t;
04654               if ( *retry_list[j*2+1] == '+' ) {
04655                      si->si_retrynum_init[j] = RETRYNUM_FOREVER;
04656                      si->si_retrynum[j] = RETRYNUM_FOREVER;
04657                      j++;
04658                      break;
04659               } else {
04660                      if ( lutil_atoi( &si->si_retrynum_init[j], retry_list[j*2+1] ) != 0
04661                                    || si->si_retrynum_init[j] <= 0 )
04662                      {
04663                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
04664                                    "Error: invalid initial retry number \"%s\" (#%d)",
04665                                    retry_list[j*2+1], j );
04666                             Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04667                             /* do some cleanup */
04668                             return 1;
04669                      }
04670                      if ( lutil_atoi( &si->si_retrynum[j], retry_list[j*2+1] ) != 0
04671                                    || si->si_retrynum[j] <= 0 )
04672                      {
04673                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
04674                                    "Error: invalid retry number \"%s\" (#%d)",
04675                                    retry_list[j*2+1], j );
04676                             Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04677                             /* do some cleanup */
04678                             return 1;
04679                      }
04680               }
04681        }
04682        if ( j < 1 || si->si_retrynum_init[j-1] != RETRYNUM_FOREVER ) {
04683               Debug( LDAP_DEBUG_CONFIG,
04684                      "%s: syncrepl will eventually stop retrying; the \"retry\" parameter should end with a '+'.\n",
04685                      c->log, 0, 0 );
04686        }
04687 
04688        si->si_retrynum_init[j] = RETRYNUM_TAIL;
04689        si->si_retrynum[j] = RETRYNUM_TAIL;
04690        si->si_retryinterval[j] = 0;
04691        
04692        for ( k = 0; retry_list && retry_list[k]; k++ ) {
04693               ch_free( retry_list[k] );
04694        }
04695        ch_free( retry_list );
04696        if ( !use_default ) {
04697               si->si_got |= GOT_RETRY;
04698        }
04699 
04700        return 0;
04701 }
04702 
04703 static int
04704 parse_syncrepl_line(
04705        ConfigArgs    *c,
04706        syncinfo_t    *si )
04707 {
04708        int    i;
04709        char   *val;
04710 
04711        for ( i = 1; i < c->argc; i++ ) {
04712               if ( !strncasecmp( c->argv[ i ], IDSTR "=",
04713                                    STRLENOF( IDSTR "=" ) ) )
04714               {
04715                      int tmp;
04716                      /* '\0' string terminator accounts for '=' */
04717                      val = c->argv[ i ] + STRLENOF( IDSTR "=" );
04718                      if ( lutil_atoi( &tmp, val ) != 0 ) {
04719                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
04720                                    "Error: parse_syncrepl_line: "
04721                                    "unable to parse syncrepl id \"%s\"", val );
04722                             Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04723                             return -1;
04724                      }
04725                      if ( tmp > SLAP_SYNC_RID_MAX || tmp < 0 ) {
04726                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
04727                                    "Error: parse_syncrepl_line: "
04728                                    "syncrepl id %d is out of range [0..%d]", tmp, SLAP_SYNC_RID_MAX );
04729                             Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04730                             return -1;
04731                      }
04732                      si->si_rid = tmp;
04733                      sprintf( si->si_ridtxt, IDSTR "=%03d", si->si_rid );
04734                      si->si_got |= GOT_RID;
04735               } else if ( !strncasecmp( c->argv[ i ], PROVIDERSTR "=",
04736                                    STRLENOF( PROVIDERSTR "=" ) ) )
04737               {
04738                      val = c->argv[ i ] + STRLENOF( PROVIDERSTR "=" );
04739                      ber_str2bv( val, 0, 1, &si->si_bindconf.sb_uri );
04740 #ifdef HAVE_TLS
04741                      if ( ldap_is_ldaps_url( val ))
04742                             si->si_bindconf.sb_tls_do_init = 1;
04743 #endif
04744                      si->si_got |= GOT_PROVIDER;
04745               } else if ( !strncasecmp( c->argv[ i ], SCHEMASTR "=",
04746                                    STRLENOF( SCHEMASTR "=" ) ) )
04747               {
04748                      val = c->argv[ i ] + STRLENOF( SCHEMASTR "=" );
04749                      if ( !strncasecmp( val, "on", STRLENOF( "on" ) ) ) {
04750                             si->si_schemachecking = 1;
04751                      } else if ( !strncasecmp( val, "off", STRLENOF( "off" ) ) ) {
04752                             si->si_schemachecking = 0;
04753                      } else {
04754                             si->si_schemachecking = 1;
04755                      }
04756                      si->si_got |= GOT_SCHEMACHECKING;
04757               } else if ( !strncasecmp( c->argv[ i ], FILTERSTR "=",
04758                                    STRLENOF( FILTERSTR "=" ) ) )
04759               {
04760                      val = c->argv[ i ] + STRLENOF( FILTERSTR "=" );
04761                      if ( si->si_filterstr.bv_val )
04762                             ch_free( si->si_filterstr.bv_val );
04763                      ber_str2bv( val, 0, 1, &si->si_filterstr );
04764                      si->si_got |= GOT_FILTER;
04765               } else if ( !strncasecmp( c->argv[ i ], LOGFILTERSTR "=",
04766                                    STRLENOF( LOGFILTERSTR "=" ) ) )
04767               {
04768                      val = c->argv[ i ] + STRLENOF( LOGFILTERSTR "=" );
04769                      if ( si->si_logfilterstr.bv_val )
04770                             ch_free( si->si_logfilterstr.bv_val );
04771                      ber_str2bv( val, 0, 1, &si->si_logfilterstr );
04772                      si->si_got |= GOT_LOGFILTER;
04773               } else if ( !strncasecmp( c->argv[ i ], SEARCHBASESTR "=",
04774                                    STRLENOF( SEARCHBASESTR "=" ) ) )
04775               {
04776                      struct berval bv;
04777                      int           rc;
04778 
04779                      val = c->argv[ i ] + STRLENOF( SEARCHBASESTR "=" );
04780                      if ( si->si_base.bv_val ) {
04781                             ch_free( si->si_base.bv_val );
04782                      }
04783                      ber_str2bv( val, 0, 0, &bv );
04784                      rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_base, NULL );
04785                      if ( rc != LDAP_SUCCESS ) {
04786                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
04787                                    "Invalid base DN \"%s\": %d (%s)",
04788                                    val, rc, ldap_err2string( rc ) );
04789                             Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04790                             return -1;
04791                      }
04792                      si->si_got |= GOT_SEARCHBASE;
04793 #ifdef ENABLE_REWRITE
04794               } else if ( !strncasecmp( c->argv[ i ], SUFFIXMSTR "=",
04795                                    STRLENOF( SUFFIXMSTR "=" ) ) )
04796               {
04797                      struct berval bv;
04798                      int           rc;
04799 
04800                      val = c->argv[ i ] + STRLENOF( SUFFIXMSTR "=" );
04801                      if ( si->si_suffixm.bv_val ) {
04802                             ch_free( si->si_suffixm.bv_val );
04803                      }
04804                      ber_str2bv( val, 0, 0, &bv );
04805                      rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_suffixm, NULL );
04806                      if ( rc != LDAP_SUCCESS ) {
04807                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
04808                                    "Invalid massage DN \"%s\": %d (%s)",
04809                                    val, rc, ldap_err2string( rc ) );
04810                             Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04811                             return -1;
04812                      }
04813                      if ( !be_issubordinate( c->be, &si->si_suffixm )) {
04814                             ch_free( si->si_suffixm.bv_val );
04815                             BER_BVZERO( &si->si_suffixm );
04816                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
04817                                    "Massage DN \"%s\" is not within the database naming context",
04818                                    val );
04819                             Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04820                             return -1;
04821                      }
04822                      si->si_got |= GOT_SUFFIXM;
04823 #endif
04824               } else if ( !strncasecmp( c->argv[ i ], LOGBASESTR "=",
04825                                    STRLENOF( LOGBASESTR "=" ) ) )
04826               {
04827                      struct berval bv;
04828                      int           rc;
04829 
04830                      val = c->argv[ i ] + STRLENOF( LOGBASESTR "=" );
04831                      if ( si->si_logbase.bv_val ) {
04832                             ch_free( si->si_logbase.bv_val );
04833                      }
04834                      ber_str2bv( val, 0, 0, &bv );
04835                      rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_logbase, NULL );
04836                      if ( rc != LDAP_SUCCESS ) {
04837                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
04838                                    "Invalid logbase DN \"%s\": %d (%s)",
04839                                    val, rc, ldap_err2string( rc ) );
04840                             Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04841                             return -1;
04842                      }
04843                      si->si_got |= GOT_LOGBASE;
04844               } else if ( !strncasecmp( c->argv[ i ], SCOPESTR "=",
04845                                    STRLENOF( SCOPESTR "=" ) ) )
04846               {
04847                      int j;
04848                      val = c->argv[ i ] + STRLENOF( SCOPESTR "=" );
04849                      j = ldap_pvt_str2scope( val );
04850                      if ( j < 0 ) {
04851                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
04852                                    "Error: parse_syncrepl_line: "
04853                                    "unknown scope \"%s\"", val);
04854                             Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04855                             return -1;
04856                      }
04857                      si->si_scope = j;
04858                      si->si_got |= GOT_SCOPE;
04859               } else if ( !strncasecmp( c->argv[ i ], ATTRSONLYSTR,
04860                                    STRLENOF( ATTRSONLYSTR ) ) )
04861               {
04862                      si->si_attrsonly = 1;
04863                      si->si_got |= GOT_ATTRSONLY;
04864               } else if ( !strncasecmp( c->argv[ i ], ATTRSSTR "=",
04865                                    STRLENOF( ATTRSSTR "=" ) ) )
04866               {
04867                      val = c->argv[ i ] + STRLENOF( ATTRSSTR "=" );
04868                      if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) {
04869                             char *attr_fname;
04870                             attr_fname = ch_strdup( val + STRLENOF(":include:") );
04871                             si->si_anlist = file2anlist( si->si_anlist, attr_fname, " ,\t" );
04872                             if ( si->si_anlist == NULL ) {
04873                                    ch_free( attr_fname );
04874                                    return -1;
04875                             }
04876                             si->si_anfile = attr_fname;
04877                      } else {
04878                             char *str, *s, *next;
04879                             const char *delimstr = " ,\t";
04880                             str = ch_strdup( val );
04881                             for ( s = ldap_pvt_strtok( str, delimstr, &next );
04882                                           s != NULL;
04883                                           s = ldap_pvt_strtok( NULL, delimstr, &next ) )
04884                             {
04885                                    if ( strlen(s) == 1 && *s == '*' ) {
04886                                           si->si_allattrs = 1;
04887                                           val[ s - str ] = delimstr[0];
04888                                    }
04889                                    if ( strlen(s) == 1 && *s == '+' ) {
04890                                           si->si_allopattrs = 1;
04891                                           val [ s - str ] = delimstr[0];
04892                                    }
04893                             }
04894                             ch_free( str );
04895                             si->si_anlist = str2anlist( si->si_anlist, val, " ,\t" );
04896                             if ( si->si_anlist == NULL ) {
04897                                    return -1;
04898                             }
04899                      }
04900                      si->si_got |= GOT_ATTRS;
04901               } else if ( !strncasecmp( c->argv[ i ], EXATTRSSTR "=",
04902                                    STRLENOF( EXATTRSSTR "=" ) ) )
04903               {
04904                      val = c->argv[ i ] + STRLENOF( EXATTRSSTR "=" );
04905                      if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) {
04906                             char *attr_fname;
04907                             attr_fname = ch_strdup( val + STRLENOF(":include:") );
04908                             si->si_exanlist = file2anlist(
04909                                    si->si_exanlist, attr_fname, " ,\t" );
04910                             if ( si->si_exanlist == NULL ) {
04911                                    ch_free( attr_fname );
04912                                    return -1;
04913                             }
04914                             ch_free( attr_fname );
04915                      } else {
04916                             si->si_exanlist = str2anlist( si->si_exanlist, val, " ,\t" );
04917                             if ( si->si_exanlist == NULL ) {
04918                                    return -1;
04919                             }
04920                      }
04921                      si->si_got |= GOT_EXATTRS;
04922               } else if ( !strncasecmp( c->argv[ i ], TYPESTR "=",
04923                                    STRLENOF( TYPESTR "=" ) ) )
04924               {
04925                      val = c->argv[ i ] + STRLENOF( TYPESTR "=" );
04926                      if ( !strncasecmp( val, "refreshOnly",
04927                                           STRLENOF("refreshOnly") ) )
04928                      {
04929                             si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_ONLY;
04930                      } else if ( !strncasecmp( val, "refreshAndPersist",
04931                                           STRLENOF("refreshAndPersist") ) )
04932                      {
04933                             si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_AND_PERSIST;
04934                             si->si_interval = 60;
04935                      } else {
04936                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
04937                                    "Error: parse_syncrepl_line: "
04938                                    "unknown sync type \"%s\"", val);
04939                             Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04940                             return -1;
04941                      }
04942                      si->si_got |= GOT_TYPE;
04943               } else if ( !strncasecmp( c->argv[ i ], INTERVALSTR "=",
04944                                    STRLENOF( INTERVALSTR "=" ) ) )
04945               {
04946                      val = c->argv[ i ] + STRLENOF( INTERVALSTR "=" );
04947                      if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
04948                             si->si_interval = 0;
04949                      } else if ( strchr( val, ':' ) != NULL ) {
04950                             char *next, *ptr = val;
04951                             int dd, hh, mm, ss;
04952 
04953                             dd = strtol( ptr, &next, 10 );
04954                             if ( next == ptr || next[0] != ':' || dd < 0 ) {
04955                                    snprintf( c->cr_msg, sizeof( c->cr_msg ),
04956                                           "Error: parse_syncrepl_line: "
04957                                           "invalid interval \"%s\", unable to parse days", val );
04958                                    Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04959                                    return -1;
04960                             }
04961                             ptr = next + 1;
04962                             hh = strtol( ptr, &next, 10 );
04963                             if ( next == ptr || next[0] != ':' || hh < 0 || hh > 24 ) {
04964                                    snprintf( c->cr_msg, sizeof( c->cr_msg ),
04965                                           "Error: parse_syncrepl_line: "
04966                                           "invalid interval \"%s\", unable to parse hours", val );
04967                                    Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04968                                    return -1;
04969                             }
04970                             ptr = next + 1;
04971                             mm = strtol( ptr, &next, 10 );
04972                             if ( next == ptr || next[0] != ':' || mm < 0 || mm > 60 ) {
04973                                    snprintf( c->cr_msg, sizeof( c->cr_msg ),
04974                                           "Error: parse_syncrepl_line: "
04975                                           "invalid interval \"%s\", unable to parse minutes", val );
04976                                    Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04977                                    return -1;
04978                             }
04979                             ptr = next + 1;
04980                             ss = strtol( ptr, &next, 10 );
04981                             if ( next == ptr || next[0] != '\0' || ss < 0 || ss > 60 ) {
04982                                    snprintf( c->cr_msg, sizeof( c->cr_msg ),
04983                                           "Error: parse_syncrepl_line: "
04984                                           "invalid interval \"%s\", unable to parse seconds", val );
04985                                    Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04986                                    return -1;
04987                             }
04988                             si->si_interval = (( dd * 24 + hh ) * 60 + mm ) * 60 + ss;
04989                      } else {
04990                             unsigned long t;
04991 
04992                             if ( lutil_parse_time( val, &t ) != 0 ) {
04993                                    snprintf( c->cr_msg, sizeof( c->cr_msg ),
04994                                           "Error: parse_syncrepl_line: "
04995                                           "invalid interval \"%s\"", val );
04996                                    Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
04997                                    return -1;
04998                             }
04999                             si->si_interval = (time_t)t;
05000                      }
05001                      if ( si->si_interval < 0 ) {
05002                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
05003                                    "Error: parse_syncrepl_line: "
05004                                    "invalid interval \"%ld\"",
05005                                    (long) si->si_interval);
05006                             Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
05007                             return -1;
05008                      }
05009                      si->si_got |= GOT_INTERVAL;
05010               } else if ( !strncasecmp( c->argv[ i ], RETRYSTR "=",
05011                                    STRLENOF( RETRYSTR "=" ) ) )
05012               {
05013                      if ( parse_syncrepl_retry( c, c->argv[ i ], si ) ) {
05014                             return 1;
05015                      }
05016               } else if ( !strncasecmp( c->argv[ i ], MANAGEDSAITSTR "=",
05017                                    STRLENOF( MANAGEDSAITSTR "=" ) ) )
05018               {
05019                      val = c->argv[ i ] + STRLENOF( MANAGEDSAITSTR "=" );
05020                      if ( lutil_atoi( &si->si_manageDSAit, val ) != 0
05021                             || si->si_manageDSAit < 0 || si->si_manageDSAit > 1 )
05022                      {
05023                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
05024                                    "invalid manageDSAit value \"%s\".\n",
05025                                    val );
05026                             Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
05027                             return 1;
05028                      }
05029                      si->si_got |= GOT_MANAGEDSAIT;
05030               } else if ( !strncasecmp( c->argv[ i ], SLIMITSTR "=",
05031                                    STRLENOF( SLIMITSTR "=") ) )
05032               {
05033                      val = c->argv[ i ] + STRLENOF( SLIMITSTR "=" );
05034                      if ( strcasecmp( val, "unlimited" ) == 0 ) {
05035                             si->si_slimit = 0;
05036 
05037                      } else if ( lutil_atoi( &si->si_slimit, val ) != 0 || si->si_slimit < 0 ) {
05038                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
05039                                    "invalid size limit value \"%s\".\n",
05040                                    val );
05041                             Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
05042                             return 1;
05043                      }
05044                      si->si_got |= GOT_SLIMIT;
05045               } else if ( !strncasecmp( c->argv[ i ], TLIMITSTR "=",
05046                                    STRLENOF( TLIMITSTR "=" ) ) )
05047               {
05048                      val = c->argv[ i ] + STRLENOF( TLIMITSTR "=" );
05049                      if ( strcasecmp( val, "unlimited" ) == 0 ) {
05050                             si->si_tlimit = 0;
05051 
05052                      } else if ( lutil_atoi( &si->si_tlimit, val ) != 0 || si->si_tlimit < 0 ) {
05053                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
05054                                    "invalid time limit value \"%s\".\n",
05055                                    val );
05056                             Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
05057                             return 1;
05058                      }
05059                      si->si_got |= GOT_TLIMIT;
05060               } else if ( !strncasecmp( c->argv[ i ], SYNCDATASTR "=",
05061                                    STRLENOF( SYNCDATASTR "=" ) ) )
05062               {
05063                      val = c->argv[ i ] + STRLENOF( SYNCDATASTR "=" );
05064                      si->si_syncdata = verb_to_mask( val, datamodes );
05065                      si->si_got |= GOT_SYNCDATA;
05066               } else if ( !strncasecmp( c->argv[ i ], STRICT_REFRESH,
05067                                    STRLENOF( STRICT_REFRESH ) ) )
05068               {
05069                      si->si_strict_refresh = 1;
05070               } else if ( bindconf_parse( c->argv[i], &si->si_bindconf ) ) {
05071                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
05072                             "Error: parse_syncrepl_line: "
05073                             "unable to parse \"%s\"\n", c->argv[ i ] );
05074                      Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
05075                      return -1;
05076               }
05077               si->si_got |= GOT_BINDCONF;
05078        }
05079 
05080        if ( ( si->si_got & GOT_REQUIRED ) != GOT_REQUIRED ) {
05081               snprintf( c->cr_msg, sizeof( c->cr_msg ),
05082                      "Error: Malformed \"syncrepl\" line in slapd config file, missing%s%s%s",
05083                      si->si_got & GOT_RID ? "" : " "IDSTR,
05084                      si->si_got & GOT_PROVIDER ? "" : " "PROVIDERSTR,
05085                      si->si_got & GOT_SEARCHBASE ? "" : " "SEARCHBASESTR );
05086               Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
05087               return -1;
05088        }
05089 
05090        if ( !be_issubordinate( c->be, &si->si_base ) && !( si->si_got & GOT_SUFFIXM )) {
05091               ch_free( si->si_base.bv_val );
05092               BER_BVZERO( &si->si_base );
05093               snprintf( c->cr_msg, sizeof( c->cr_msg ),
05094                      "Base DN \"%s\" is not within the database naming context",
05095                      val );
05096               Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
05097               return -1;
05098        }
05099 
05100 #ifdef ENABLE_REWRITE
05101        if ( si->si_got & GOT_SUFFIXM ) {
05102               if (config_suffixm( c, si )) {
05103                      ch_free( si->si_suffixm.bv_val );
05104                      BER_BVZERO( &si->si_suffixm );
05105                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
05106                             "Error configuring rewrite engine" );
05107                      Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
05108                      return -1;
05109               }
05110        }
05111 #endif
05112 
05113        if ( !( si->si_got & GOT_RETRY ) ) {
05114               Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": no retry defined, using default\n", 
05115                      si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", 0 );
05116               if ( si->si_retryinterval == NULL ) {
05117                      if ( parse_syncrepl_retry( c, "retry=undefined", si ) ) {
05118                             return 1;
05119                      }
05120               }
05121        }
05122 
05123        si->si_filter = str2filter( si->si_filterstr.bv_val );
05124        if ( si->si_filter == NULL ) {
05125               Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse filter=\"%s\"\n", 
05126                      si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_filterstr.bv_val );
05127               return 1;
05128        }
05129 
05130        return 0;
05131 }
05132 
05133 static int
05134 add_syncrepl(
05135        ConfigArgs *c )
05136 {
05137        syncinfo_t *si;
05138        int    rc = 0;
05139 
05140        if ( !( c->be->be_search && c->be->be_add && c->be->be_modify && c->be->be_delete ) ) {
05141               snprintf( c->cr_msg, sizeof(c->cr_msg), "database %s does not support "
05142                      "operations required for syncrepl", c->be->be_type );
05143               Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg, 0 );
05144               return 1;
05145        }
05146        if ( BER_BVISEMPTY( &c->be->be_rootdn ) ) {
05147               strcpy( c->cr_msg, "rootDN must be defined before syncrepl may be used" );
05148               Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg, 0 );
05149               return 1;
05150        }
05151        si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) );
05152 
05153        if ( si == NULL ) {
05154               Debug( LDAP_DEBUG_ANY, "out of memory in add_syncrepl\n", 0, 0, 0 );
05155               return 1;
05156        }
05157 
05158        si->si_bindconf.sb_tls = SB_TLS_OFF;
05159        si->si_bindconf.sb_method = LDAP_AUTH_SIMPLE;
05160        si->si_schemachecking = 0;
05161        ber_str2bv( "(objectclass=*)", STRLENOF("(objectclass=*)"), 1,
05162               &si->si_filterstr );
05163        si->si_base.bv_val = NULL;
05164        si->si_scope = LDAP_SCOPE_SUBTREE;
05165        si->si_attrsonly = 0;
05166        si->si_anlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ) );
05167        si->si_exanlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ) );
05168        si->si_attrs = NULL;
05169        si->si_allattrs = 0;
05170        si->si_allopattrs = 0;
05171        si->si_exattrs = NULL;
05172        si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_ONLY;
05173        si->si_interval = 86400;
05174        si->si_retryinterval = NULL;
05175        si->si_retrynum_init = NULL;
05176        si->si_retrynum = NULL;
05177        si->si_manageDSAit = 0;
05178        si->si_tlimit = 0;
05179        si->si_slimit = 0;
05180 
05181        si->si_presentlist = NULL;
05182        LDAP_LIST_INIT( &si->si_nonpresentlist );
05183        ldap_pvt_thread_mutex_init( &si->si_mutex );
05184 
05185        rc = parse_syncrepl_line( c, si );
05186 
05187        if ( rc == 0 ) {
05188               LDAPURLDesc *lud;
05189 
05190               /* Must be LDAPv3 because we need controls */
05191               switch ( si->si_bindconf.sb_version ) {
05192               case 0:
05193                      /* not explicitly set */
05194                      si->si_bindconf.sb_version = LDAP_VERSION3;
05195                      break;
05196               case 3:
05197                      /* explicitly set */
05198                      break;
05199               default:
05200                      Debug( LDAP_DEBUG_ANY,
05201                             "version %d incompatible with syncrepl\n",
05202                             si->si_bindconf.sb_version, 0, 0 );
05203                      syncinfo_free( si, 0 );     
05204                      return 1;
05205               }
05206 
05207               if ( ldap_url_parse( si->si_bindconf.sb_uri.bv_val, &lud )) {
05208                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
05209                             "<%s> invalid URL", c->argv[0] );
05210                      Debug( LDAP_DEBUG_ANY, "%s: %s %s\n",
05211                             c->log, c->cr_msg, si->si_bindconf.sb_uri.bv_val );
05212                      return 1;
05213               }
05214 
05215               si->si_be = c->be;
05216               if ( slapMode & SLAP_SERVER_MODE ) {
05217                      int isMe = 0;
05218                      /* check if consumer points to current server and database.
05219                       * If so, ignore this configuration.
05220                       */
05221                      if ( !SLAP_DBHIDDEN( c->be ) ) {
05222                             int i;
05223                             /* if searchbase doesn't match current DB suffix,
05224                              * assume it's different
05225                              */
05226                             for ( i=0; !BER_BVISNULL( &c->be->be_nsuffix[i] ); i++ ) {
05227                                    if ( bvmatch( &si->si_base, &c->be->be_nsuffix[i] )) {
05228                                           isMe = 1;
05229                                           break;
05230                                    }
05231                             }
05232                             /* if searchbase matches, see if URLs match */
05233                             if ( isMe && config_check_my_url( si->si_bindconf.sb_uri.bv_val,
05234                                           lud ) == NULL )
05235                                    isMe = 0;
05236                      }
05237 
05238                      if ( !isMe ) {
05239                             init_syncrepl( si );
05240                             ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
05241                             si->si_re = ldap_pvt_runqueue_insert( &slapd_rq,
05242                                    si->si_interval, do_syncrepl, si, "do_syncrepl",
05243                                    si->si_ridtxt );
05244                             ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
05245                             if ( si->si_re )
05246                                    rc = config_sync_shadow( c ) ? -1 : 0;
05247                             else
05248                                    rc = -1;
05249                      }
05250               } else {
05251                      /* mirrormode still needs to see this flag in tool mode */
05252                      rc = config_sync_shadow( c ) ? -1 : 0;
05253               }
05254               ldap_free_urldesc( lud );
05255        }
05256 
05257 #ifdef HAVE_TLS
05258        /* Use main slapd defaults */
05259        bindconf_tls_defaults( &si->si_bindconf );
05260 #endif
05261        if ( rc < 0 ) {
05262               Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n", 0, 0, 0 );
05263               syncinfo_free( si, 0 );     
05264               return 1;
05265        } else {
05266               Debug( LDAP_DEBUG_CONFIG,
05267                      "Config: ** successfully added syncrepl %s \"%s\"\n",
05268                      si->si_ridtxt,
05269                      BER_BVISNULL( &si->si_bindconf.sb_uri ) ?
05270                      "(null)" : si->si_bindconf.sb_uri.bv_val, 0 );
05271               if ( c->be->be_syncinfo ) {
05272                      syncinfo_t *sip;
05273 
05274                      si->si_cookieState = c->be->be_syncinfo->si_cookieState;
05275 
05276                      /* add new syncrepl to end of list (same order as when deleting) */
05277                      for ( sip = c->be->be_syncinfo; sip->si_next; sip = sip->si_next );
05278                      sip->si_next = si;
05279               } else {
05280                      si->si_cookieState = ch_calloc( 1, sizeof( cookie_state ));
05281                      ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_mutex );
05282                      ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_pmutex );
05283 
05284                      c->be->be_syncinfo = si;
05285               }
05286               si->si_cookieState->cs_ref++;
05287 
05288               si->si_next = NULL;
05289 
05290               return 0;
05291        }
05292 }
05293 
05294 static void
05295 syncrepl_unparse( syncinfo_t *si, struct berval *bv )
05296 {
05297        struct berval bc, uri, bs;
05298        char buf[BUFSIZ*2], *ptr;
05299        ber_len_t len;
05300        int i;
05301 #      define WHATSLEFT     ((ber_len_t) (&buf[sizeof( buf )] - ptr))
05302 
05303        BER_BVZERO( bv );
05304 
05305        /* temporarily inhibit bindconf from printing URI */
05306        uri = si->si_bindconf.sb_uri;
05307        BER_BVZERO( &si->si_bindconf.sb_uri );
05308        si->si_bindconf.sb_version = 0;
05309        bindconf_unparse( &si->si_bindconf, &bc );
05310        si->si_bindconf.sb_uri = uri;
05311        si->si_bindconf.sb_version = LDAP_VERSION3;
05312 
05313        ptr = buf;
05314        assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_RID_MAX );
05315        len = snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
05316               si->si_rid, si->si_bindconf.sb_uri.bv_val );
05317        if ( len >= sizeof( buf ) ) return;
05318        ptr += len;
05319        if ( !BER_BVISNULL( &bc ) ) {
05320               if ( WHATSLEFT <= bc.bv_len ) {
05321                      free( bc.bv_val );
05322                      return;
05323               }
05324               ptr = lutil_strcopy( ptr, bc.bv_val );
05325               free( bc.bv_val );
05326        }
05327        if ( !BER_BVISEMPTY( &si->si_filterstr ) ) {
05328               if ( WHATSLEFT <= STRLENOF( " " FILTERSTR "=\"" "\"" ) + si->si_filterstr.bv_len ) return;
05329               ptr = lutil_strcopy( ptr, " " FILTERSTR "=\"" );
05330               ptr = lutil_strcopy( ptr, si->si_filterstr.bv_val );
05331               *ptr++ = '"';
05332        }
05333        if ( !BER_BVISNULL( &si->si_base ) ) {
05334               if ( WHATSLEFT <= STRLENOF( " " SEARCHBASESTR "=\"" "\"" ) + si->si_base.bv_len ) return;
05335               ptr = lutil_strcopy( ptr, " " SEARCHBASESTR "=\"" );
05336               ptr = lutil_strcopy( ptr, si->si_base.bv_val );
05337               *ptr++ = '"';
05338        }
05339 #ifdef ENABLE_REWRITE
05340        if ( !BER_BVISNULL( &si->si_suffixm ) ) {
05341               if ( WHATSLEFT <= STRLENOF( " " SUFFIXMSTR "=\"" "\"" ) + si->si_suffixm.bv_len ) return;
05342               ptr = lutil_strcopy( ptr, " " SUFFIXMSTR "=\"" );
05343               ptr = lutil_strcopy( ptr, si->si_suffixm.bv_val );
05344               *ptr++ = '"';
05345        }
05346 #endif
05347        if ( !BER_BVISEMPTY( &si->si_logfilterstr ) ) {
05348               if ( WHATSLEFT <= STRLENOF( " " LOGFILTERSTR "=\"" "\"" ) + si->si_logfilterstr.bv_len ) return;
05349               ptr = lutil_strcopy( ptr, " " LOGFILTERSTR "=\"" );
05350               ptr = lutil_strcopy( ptr, si->si_logfilterstr.bv_val );
05351               *ptr++ = '"';
05352        }
05353        if ( !BER_BVISNULL( &si->si_logbase ) ) {
05354               if ( WHATSLEFT <= STRLENOF( " " LOGBASESTR "=\"" "\"" ) + si->si_logbase.bv_len ) return;
05355               ptr = lutil_strcopy( ptr, " " LOGBASESTR "=\"" );
05356               ptr = lutil_strcopy( ptr, si->si_logbase.bv_val );
05357               *ptr++ = '"';
05358        }
05359        if ( ldap_pvt_scope2bv( si->si_scope, &bs ) == LDAP_SUCCESS ) {
05360               if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + bs.bv_len ) return;
05361               ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
05362               ptr = lutil_strcopy( ptr, bs.bv_val );
05363        }
05364        if ( si->si_attrsonly ) {
05365               if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
05366               ptr = lutil_strcopy( ptr, " " ATTRSONLYSTR );
05367        }
05368        if ( si->si_anfile ) {
05369               if ( WHATSLEFT <= STRLENOF( " " ATTRSSTR "=\":include:" "\"" ) + strlen( si->si_anfile ) ) return;
05370               ptr = lutil_strcopy( ptr, " " ATTRSSTR "=:include:\"" );
05371               ptr = lutil_strcopy( ptr, si->si_anfile );
05372               *ptr++ = '"';
05373        } else if ( si->si_allattrs || si->si_allopattrs ||
05374               ( si->si_anlist && !BER_BVISNULL(&si->si_anlist[0].an_name) ) )
05375        {
05376               char *old;
05377 
05378               if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
05379               ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" );
05380               old = ptr;
05381               ptr = anlist_unparse( si->si_anlist, ptr, WHATSLEFT );
05382               if ( ptr == NULL ) return;
05383               if ( si->si_allattrs ) {
05384                      if ( WHATSLEFT <= STRLENOF( ",*\"" ) ) return;
05385                      if ( old != ptr ) *ptr++ = ',';
05386                      *ptr++ = '*';
05387               }
05388               if ( si->si_allopattrs ) {
05389                      if ( WHATSLEFT <= STRLENOF( ",+\"" ) ) return;
05390                      if ( old != ptr ) *ptr++ = ',';
05391                      *ptr++ = '+';
05392               }
05393               *ptr++ = '"';
05394        }
05395        if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) {
05396               if ( WHATSLEFT <= STRLENOF( " " EXATTRSSTR "=" ) ) return;
05397               ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" );
05398               ptr = anlist_unparse( si->si_exanlist, ptr, WHATSLEFT );
05399               if ( ptr == NULL ) return;
05400        }
05401        if ( WHATSLEFT <= STRLENOF( " " SCHEMASTR "=" ) + STRLENOF( "off" ) ) return;
05402        ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" );
05403        ptr = lutil_strcopy( ptr, si->si_schemachecking ? "on" : "off" );
05404        
05405        if ( WHATSLEFT <= STRLENOF( " " TYPESTR "=" ) + STRLENOF( "refreshAndPersist" ) ) return;
05406        ptr = lutil_strcopy( ptr, " " TYPESTR "=" );
05407        ptr = lutil_strcopy( ptr, si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ?
05408               "refreshAndPersist" : "refreshOnly" );
05409 
05410        if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
05411               int dd, hh, mm, ss;
05412 
05413               dd = si->si_interval;
05414               ss = dd % 60;
05415               dd /= 60;
05416               mm = dd % 60;
05417               dd /= 60;
05418               hh = dd % 24;
05419               dd /= 24;
05420               len = snprintf( ptr, WHATSLEFT, " %s=%02d:%02d:%02d:%02d",
05421                      INTERVALSTR, dd, hh, mm, ss );
05422               if ( len >= WHATSLEFT ) return;
05423               ptr += len;
05424        }
05425 
05426        if ( si->si_got & GOT_RETRY ) {
05427               const char *space = "";
05428               if ( WHATSLEFT <= STRLENOF( " " RETRYSTR "=\"" "\"" ) ) return;
05429               ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" );
05430               for (i=0; si->si_retryinterval[i]; i++) {
05431                      len = snprintf( ptr, WHATSLEFT, "%s%ld ", space,
05432                             (long) si->si_retryinterval[i] );
05433                      space = " ";
05434                      if ( WHATSLEFT - 1 <= len ) return;
05435                      ptr += len;
05436                      if ( si->si_retrynum_init[i] == RETRYNUM_FOREVER )
05437                             *ptr++ = '+';
05438                      else {
05439                             len = snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] );
05440                             if ( WHATSLEFT <= len ) return;
05441                             ptr += len;
05442                      }
05443               }
05444               if ( WHATSLEFT <= STRLENOF( "\"" ) ) return;
05445               *ptr++ = '"';
05446        } else {
05447               ptr = lutil_strcopy( ptr, " " RETRYSTR "=undefined" );
05448        }
05449 
05450        if ( si->si_slimit ) {
05451               len = snprintf( ptr, WHATSLEFT, " " SLIMITSTR "=%d", si->si_slimit );
05452               if ( WHATSLEFT <= len ) return;
05453               ptr += len;
05454        }
05455 
05456        if ( si->si_tlimit ) {
05457               len = snprintf( ptr, WHATSLEFT, " " TLIMITSTR "=%d", si->si_tlimit );
05458               if ( WHATSLEFT <= len ) return;
05459               ptr += len;
05460        }
05461 
05462        if ( si->si_syncdata ) {
05463               if ( enum_to_verb( datamodes, si->si_syncdata, &bc ) >= 0 ) {
05464                      if ( WHATSLEFT <= STRLENOF( " " SYNCDATASTR "=" ) + bc.bv_len ) return;
05465                      ptr = lutil_strcopy( ptr, " " SYNCDATASTR "=" );
05466                      ptr = lutil_strcopy( ptr, bc.bv_val );
05467               }
05468        }
05469        bc.bv_len = ptr - buf;
05470        bc.bv_val = buf;
05471        ber_dupbv( bv, &bc );
05472 }
05473 
05474 int
05475 syncrepl_config( ConfigArgs *c )
05476 {
05477        if (c->op == SLAP_CONFIG_EMIT) {
05478               if ( c->be->be_syncinfo ) {
05479                      struct berval bv;
05480                      syncinfo_t *si;
05481 
05482                      for ( si = c->be->be_syncinfo; si; si=si->si_next ) {
05483                             syncrepl_unparse( si, &bv ); 
05484                             ber_bvarray_add( &c->rvalue_vals, &bv );
05485                      }
05486                      return 0;
05487               }
05488               return 1;
05489        } else if ( c->op == LDAP_MOD_DELETE ) {
05490               int isrunning = 0;
05491               if ( c->be->be_syncinfo ) {
05492                      syncinfo_t *si, **sip;
05493                      int i;
05494 
05495                      for ( sip = &c->be->be_syncinfo, i=0; *sip; i++ ) {
05496                             si = *sip;
05497                             if ( c->valx == -1 || i == c->valx ) {
05498                                    *sip = si->si_next;
05499                                    si->si_ctype = -1;
05500                                    si->si_next = NULL;
05501                                    /* If the task is currently active, we have to leave
05502                                     * it running. It will exit on its own. This will only
05503                                     * happen when running on the cn=config DB.
05504                                     */
05505                                    if ( si->si_re ) {
05506                                           if ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
05507                                                  isrunning = 1;
05508                                           } else {
05509                                                  /* There is no active thread, but we must still
05510                                                   * ensure that no thread is (or will be) queued
05511                                                   * while we removes the task.
05512                                                   */
05513                                                  struct re_s *re = si->si_re;
05514                                                  si->si_re = NULL;
05515 
05516                                                  if ( si->si_conn ) {
05517                                                         connection_client_stop( si->si_conn );
05518                                                         si->si_conn = NULL;
05519                                                  }
05520 
05521                                                  ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
05522                                                  if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) ) {
05523                                                         ldap_pvt_runqueue_stoptask( &slapd_rq, re );
05524                                                         isrunning = 1;
05525                                                  }
05526                                                  if ( ldap_pvt_thread_pool_retract( &connection_pool,
05527                                                                re->routine, re ) > 0 )
05528                                                         isrunning = 0;
05529 
05530                                                  ldap_pvt_runqueue_remove( &slapd_rq, re );
05531                                                  ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
05532 
05533                                                  ldap_pvt_thread_mutex_unlock( &si->si_mutex );
05534                                           }
05535                                    }
05536                                    if ( !isrunning ) {
05537                                           syncinfo_free( si, 0 );
05538                                    }
05539                                    if ( i == c->valx )
05540                                           break;
05541                             } else {
05542                                    sip = &si->si_next;
05543                             }
05544                      }
05545               }
05546               if ( !c->be->be_syncinfo ) {
05547                      SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_SHADOW_MASK;
05548               }
05549               return 0;
05550        }
05551        if ( SLAP_SLURP_SHADOW( c->be ) ) {
05552               Debug(LDAP_DEBUG_ANY, "%s: "
05553                      "syncrepl: database already shadowed.\n",
05554                      c->log, 0, 0);
05555               return(1);
05556        } else {
05557               return add_syncrepl( c );
05558        }
05559 }