]> git.sur5r.net Git - openldap/blob - servers/slapd/syncrepl.c
ITS#8789 avoid unnecessary writes of context entry
[openldap] / servers / slapd / syncrepl.c
1 /* syncrepl.c -- Replication Engine which uses the LDAP Sync protocol */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2017 The OpenLDAP Foundation.
6  * Portions Copyright 2003 by IBM Corporation.
7  * Portions Copyright 2003-2008 by Howard Chu, Symas Corporation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18
19 #include "portable.h"
20
21 #include <stdio.h>
22
23 #include <ac/string.h>
24 #include <ac/socket.h>
25
26 #include "lutil.h"
27 #include "slap.h"
28 #include "lutil_ldap.h"
29
30 #include "config.h"
31
32 #include "ldap_rq.h"
33
34 #ifdef ENABLE_REWRITE
35 #include "rewrite.h"
36 #define SUFFIXM_CTX     "<suffix massage>"
37 #endif
38
39 #define UUIDLEN 16
40
41 struct nonpresent_entry {
42         struct berval *npe_name;
43         struct berval *npe_nname;
44         LDAP_LIST_ENTRY(nonpresent_entry) npe_link;
45 };
46
47 typedef struct cookie_state {
48         ldap_pvt_thread_mutex_t cs_mutex;
49         ldap_pvt_thread_cond_t cs_cond;
50         struct berval *cs_vals;
51         int *cs_sids;
52         int     cs_num;
53         int cs_age;
54         int cs_ref;
55         int cs_updating;
56
57         /* pending changes, not yet committed */
58         ldap_pvt_thread_mutex_t cs_pmutex;
59         struct berval *cs_pvals;
60         int *cs_psids;
61         int     cs_pnum;
62 } cookie_state;
63
64 #define SYNCDATA_DEFAULT        0       /* entries are plain LDAP entries */
65 #define SYNCDATA_ACCESSLOG      1       /* entries are accesslog format */
66 #define SYNCDATA_CHANGELOG      2       /* entries are changelog format */
67
68 #define SYNCLOG_LOGGING         0       /* doing a log-based update */
69 #define SYNCLOG_FALLBACK        1       /* doing a full refresh */
70
71 #define RETRYNUM_FOREVER        (-1)    /* retry forever */
72 #define RETRYNUM_TAIL           (-2)    /* end of retrynum array */
73 #define RETRYNUM_VALID(n)       ((n) >= RETRYNUM_FOREVER)       /* valid retrynum */
74 #define RETRYNUM_FINITE(n)      ((n) > RETRYNUM_FOREVER)        /* not forever */
75
76 typedef struct syncinfo_s {
77         struct syncinfo_s       *si_next;
78         BackendDB               *si_be;
79         BackendDB               *si_wbe;
80         struct re_s             *si_re;
81         int                     si_rid;
82         char                    si_ridtxt[ STRLENOF("rid=999") + 1 ];
83         slap_bindconf           si_bindconf;
84         struct berval           si_base;
85         struct berval           si_logbase;
86         struct berval           si_filterstr;
87         struct berval           si_logfilterstr;
88         Filter                  *si_filter;
89         Filter                  *si_logfilter;
90         struct berval           si_contextdn;
91         int                     si_scope;
92         int                     si_attrsonly;
93         char                    *si_anfile;
94         AttributeName           *si_anlist;
95         AttributeName           *si_exanlist;
96         char                    **si_attrs;
97         char                    **si_exattrs;
98         int                     si_allattrs;
99         int                     si_allopattrs;
100         int                     si_schemachecking;
101         int                     si_type;        /* the active type */
102         int                     si_ctype;       /* the configured type */
103         time_t                  si_interval;
104         time_t                  *si_retryinterval;
105         int                     *si_retrynum_init;
106         int                     *si_retrynum;
107         struct sync_cookie      si_syncCookie;
108         cookie_state            *si_cookieState;
109         int                     si_cookieAge;
110         int                     si_manageDSAit;
111         int                     si_slimit;
112         int                     si_tlimit;
113         int                     si_refreshDelete;
114         int                     si_refreshPresent;
115         int                     si_refreshDone;
116         int                     si_refreshCount;
117         time_t          si_refreshBeg;
118         time_t          si_refreshEnd;
119         OpExtra         *si_refreshTxn;
120         int                     si_syncdata;
121         int                     si_logstate;
122         int                     si_lazyCommit;
123         int                     si_got;
124         int                     si_strict_refresh;      /* stop listening during fallback refresh */
125         int                     si_too_old;
126         int                     si_has_syncprov;
127         ber_int_t       si_msgid;
128         Avlnode                 *si_presentlist;
129         LDAP                    *si_ld;
130         Connection              *si_conn;
131         LDAP_LIST_HEAD(np, nonpresent_entry)    si_nonpresentlist;
132 #ifdef ENABLE_REWRITE
133         struct rewrite_info *si_rewrite;
134         struct berval   si_suffixm;
135 #endif
136         ldap_pvt_thread_mutex_t si_mutex;
137 } syncinfo_t;
138
139 static int syncuuid_cmp( const void *, const void * );
140 static int presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
141 static void presentlist_delete( Avlnode **av, struct berval *syncUUID );
142 static char *presentlist_find( Avlnode *av, struct berval *syncUUID );
143 static int presentlist_free( Avlnode *av );
144 static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
145 static int syncrepl_message_to_op(
146                                         syncinfo_t *, Operation *, LDAPMessage * );
147 static int syncrepl_message_to_entry(
148                                         syncinfo_t *, Operation *, LDAPMessage *,
149                                         Modifications **, Entry **, int, struct berval* );
150 static int syncrepl_entry(
151                                         syncinfo_t *, Operation*, Entry*,
152                                         Modifications**,int, struct berval*,
153                                         struct berval *cookieCSN );
154 static int syncrepl_updateCookie(
155                                         syncinfo_t *, Operation *,
156                                         struct sync_cookie *, int save );
157 static struct berval * slap_uuidstr_from_normalized(
158                                         struct berval *, struct berval *, void * );
159 static int syncrepl_add_glue_ancestors(
160         Operation* op, Entry *e );
161
162 /* delta-mmr overlay handler */
163 static int syncrepl_op_modify( Operation *op, SlapReply *rs );
164
165 /* callback functions */
166 static int dn_callback( Operation *, SlapReply * );
167 static int nonpresent_callback( Operation *, SlapReply * );
168
169 static AttributeDescription *sync_descs[4];
170
171 /* delta-mmr */
172 static AttributeDescription *ad_reqMod, *ad_reqDN;
173
174 typedef struct logschema {
175         struct berval ls_dn;
176         struct berval ls_req;
177         struct berval ls_mod;
178         struct berval ls_newRdn;
179         struct berval ls_delRdn;
180         struct berval ls_newSup;
181         struct berval ls_controls;
182 } logschema;
183
184 static logschema changelog_sc = {
185         BER_BVC("targetDN"),
186         BER_BVC("changeType"),
187         BER_BVC("changes"),
188         BER_BVC("newRDN"),
189         BER_BVC("deleteOldRDN"),
190         BER_BVC("newSuperior"),
191         BER_BVC("controls")
192 };
193
194 static logschema accesslog_sc = {
195         BER_BVC("reqDN"),
196         BER_BVC("reqType"),
197         BER_BVC("reqMod"),
198         BER_BVC("reqNewRDN"),
199         BER_BVC("reqDeleteOldRDN"),
200         BER_BVC("reqNewSuperior"),
201         BER_BVC("reqControls")
202 };
203
204 static const char *
205 syncrepl_state2str( int state )
206 {
207         switch ( state ) {
208         case LDAP_SYNC_PRESENT:
209                 return "PRESENT";
210
211         case LDAP_SYNC_ADD:
212                 return "ADD";
213
214         case LDAP_SYNC_MODIFY:
215                 return "MODIFY";
216
217         case LDAP_SYNC_DELETE:
218                 return "DELETE";
219         }
220
221         return "UNKNOWN";
222 }
223
224 static slap_overinst syncrepl_ov;
225
226 static void
227 init_syncrepl(syncinfo_t *si)
228 {
229         int i, j, k, l, n;
230         char **attrs, **exattrs;
231
232         if ( !syncrepl_ov.on_bi.bi_type ) {
233                 syncrepl_ov.on_bi.bi_type = "syncrepl";
234                 syncrepl_ov.on_bi.bi_op_modify = syncrepl_op_modify;
235                 overlay_register( &syncrepl_ov );
236         }
237
238         /* delta-MMR needs the overlay, nothing else does.
239          * This must happen before accesslog overlay is configured.
240          */
241         if ( si->si_syncdata &&
242                 !overlay_is_inst( si->si_be, syncrepl_ov.on_bi.bi_type )) {
243                 overlay_config( si->si_be, syncrepl_ov.on_bi.bi_type, -1, NULL, NULL );
244                 if ( !ad_reqMod ) {
245                         const char *text;
246                         logschema *ls = &accesslog_sc;
247
248                         slap_bv2ad( &ls->ls_mod, &ad_reqMod, &text );
249                         slap_bv2ad( &ls->ls_dn, &ad_reqDN, &text );
250                 }
251         }
252
253         if ( !sync_descs[0] ) {
254                 sync_descs[0] = slap_schema.si_ad_objectClass;
255                 sync_descs[1] = slap_schema.si_ad_structuralObjectClass;
256                 sync_descs[2] = slap_schema.si_ad_entryCSN;
257                 sync_descs[3] = NULL;
258         }
259
260         if ( si->si_allattrs && si->si_allopattrs )
261                 attrs = NULL;
262         else
263                 attrs = anlist2attrs( si->si_anlist );
264
265         if ( attrs ) {
266                 if ( si->si_allattrs ) {
267                         i = 0;
268                         while ( attrs[i] ) {
269                                 if ( !is_at_operational( at_find( attrs[i] ) ) ) {
270                                         for ( j = i; attrs[j] != NULL; j++ ) {
271                                                 if ( j == i )
272                                                         ch_free( attrs[i] );
273                                                 attrs[j] = attrs[j+1];
274                                         }
275                                 } else {
276                                         i++;
277                                 }
278                         }
279                         attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
280                         attrs[i] = ch_strdup("*");
281                         attrs[i + 1] = NULL;
282
283                 } else if ( si->si_allopattrs ) {
284                         i = 0;
285                         while ( attrs[i] ) {
286                                 if ( is_at_operational( at_find( attrs[i] ) ) ) {
287                                         for ( j = i; attrs[j] != NULL; j++ ) {
288                                                 if ( j == i )
289                                                         ch_free( attrs[i] );
290                                                 attrs[j] = attrs[j+1];
291                                         }
292                                 } else {
293                                         i++;
294                                 }
295                         }
296                         attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
297                         attrs[i] = ch_strdup("+");
298                         attrs[i + 1] = NULL;
299                 }
300
301                 for ( i = 0; sync_descs[i] != NULL; i++ ) {
302                         j = 0;
303                         while ( attrs[j] ) {
304                                 if ( !strcmp( attrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
305                                         for ( k = j; attrs[k] != NULL; k++ ) {
306                                                 if ( k == j )
307                                                         ch_free( attrs[k] );
308                                                 attrs[k] = attrs[k+1];
309                                         }
310                                 } else {
311                                         j++;
312                                 }
313                         }
314                 }
315
316                 for ( n = 0; attrs[ n ] != NULL; n++ ) /* empty */;
317
318                 if ( si->si_allopattrs ) {
319                         attrs = ( char ** ) ch_realloc( attrs, (n + 2)*sizeof( char * ) );
320                 } else {
321                         attrs = ( char ** ) ch_realloc( attrs, (n + 4)*sizeof( char * ) );
322                 }
323
324                 /* Add Attributes */
325                 if ( si->si_allopattrs ) {
326                         attrs[n++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
327                 } else {
328                         for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
329                                 attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
330                         }
331                 }
332                 attrs[ n ] = NULL;
333
334         } else {
335
336                 i = 0;
337                 if ( si->si_allattrs == si->si_allopattrs ) {
338                         attrs = (char**) ch_malloc( 3 * sizeof(char*) );
339                         attrs[i++] = ch_strdup( "*" );
340                         attrs[i++] = ch_strdup( "+" );
341                 } else if ( si->si_allattrs && !si->si_allopattrs ) {
342                         for ( n = 0; sync_descs[ n ] != NULL; n++ ) ;
343                         attrs = (char**) ch_malloc( (n+1)* sizeof(char*) );
344                         attrs[i++] = ch_strdup( "*" );
345                         for ( j = 1; sync_descs[ j ] != NULL; j++ ) {
346                                 attrs[i++] = ch_strdup ( sync_descs[j]->ad_cname.bv_val );
347                         }
348                 } else if ( !si->si_allattrs && si->si_allopattrs ) {
349                         attrs = (char**) ch_malloc( 3 * sizeof(char*) );
350                         attrs[i++] = ch_strdup( "+" );
351                         attrs[i++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
352                 }
353                 attrs[i] = NULL;
354         }
355         
356         si->si_attrs = attrs;
357
358         exattrs = anlist2attrs( si->si_exanlist );
359
360         if ( exattrs ) {
361                 for ( n = 0; exattrs[n] != NULL; n++ ) ;
362
363                 for ( i = 0; sync_descs[i] != NULL; i++ ) {
364                         j = 0;
365                         while ( exattrs[j] != NULL ) {
366                                 if ( !strcmp( exattrs[j], sync_descs[i]->ad_cname.bv_val ) ) {
367                                         ch_free( exattrs[j] );
368                                         for ( k = j; exattrs[k] != NULL; k++ ) {
369                                                 exattrs[k] = exattrs[k+1];
370                                         }
371                                 } else {
372                                         j++;
373                                 }
374                         }
375                 }
376
377                 for ( i = 0; exattrs[i] != NULL; i++ ) {
378                         for ( j = 0; si->si_anlist[j].an_name.bv_val; j++ ) {
379                                 ObjectClass     *oc;
380                                 if ( ( oc = si->si_anlist[j].an_oc ) ) {
381                                         k = 0;
382                                         while ( oc->soc_required[k] ) {
383                                                 if ( !strcmp( exattrs[i],
384                                                          oc->soc_required[k]->sat_cname.bv_val ) ) {
385                                                         ch_free( exattrs[i] );
386                                                         for ( l = i; exattrs[l]; l++ ) {
387                                                                 exattrs[l] = exattrs[l+1];
388                                                         }
389                                                 } else {
390                                                         k++;
391                                                 }
392                                         }
393                                 }
394                         }
395                 }
396
397                 for ( i = 0; exattrs[i] != NULL; i++ ) ;
398
399                 if ( i != n )
400                         exattrs = (char **) ch_realloc( exattrs, (i + 1)*sizeof(char *) );
401         }
402
403         si->si_exattrs = exattrs;       
404 }
405
406 static int
407 ldap_sync_search(
408         syncinfo_t *si,
409         void *ctx )
410 {
411         BerElementBuffer berbuf;
412         BerElement *ber = (BerElement *)&berbuf;
413         LDAPControl c[3], *ctrls[4];
414         int rc;
415         int rhint;
416         char *base;
417         char **attrs, *lattrs[9];
418         char *filter;
419         int attrsonly;
420         int scope;
421
422         /* setup LDAP SYNC control */
423         ber_init2( ber, NULL, LBER_USE_DER );
424         ber_set_option( ber, LBER_OPT_BER_MEMCTX, &ctx );
425
426         /* If we're using a log but we have no state, then fallback to
427          * normal mode for a full refresh.
428          */
429         if ( si->si_syncdata && !si->si_syncCookie.numcsns ) {
430                 si->si_logstate = SYNCLOG_FALLBACK;
431         }
432
433         /* Use the log parameters if we're in log mode */
434         if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
435                 logschema *ls;
436                 if ( si->si_syncdata == SYNCDATA_ACCESSLOG )
437                         ls = &accesslog_sc;
438                 else
439                         ls = &changelog_sc;
440                 lattrs[0] = ls->ls_dn.bv_val;
441                 lattrs[1] = ls->ls_req.bv_val;
442                 lattrs[2] = ls->ls_mod.bv_val;
443                 lattrs[3] = ls->ls_newRdn.bv_val;
444                 lattrs[4] = ls->ls_delRdn.bv_val;
445                 lattrs[5] = ls->ls_newSup.bv_val;
446                 lattrs[6] = ls->ls_controls.bv_val;
447                 lattrs[7] = slap_schema.si_ad_entryCSN->ad_cname.bv_val;
448                 lattrs[8] = NULL;
449
450                 rhint = 0;
451                 base = si->si_logbase.bv_val;
452                 filter = si->si_logfilterstr.bv_val;
453                 attrs = lattrs;
454                 attrsonly = 0;
455                 scope = LDAP_SCOPE_SUBTREE;
456         } else {
457                 rhint = 1;
458                 base = si->si_base.bv_val;
459                 filter = si->si_filterstr.bv_val;
460                 attrs = si->si_attrs;
461                 attrsonly = si->si_attrsonly;
462                 scope = si->si_scope;
463         }
464         if ( si->si_syncdata && si->si_logstate == SYNCLOG_FALLBACK ) {
465                 si->si_type = LDAP_SYNC_REFRESH_ONLY;
466         } else {
467                 si->si_type = si->si_ctype;
468         }
469
470         if ( !BER_BVISNULL( &si->si_syncCookie.octet_str ) )
471         {
472                 ber_printf( ber, "{eOb}",
473                         abs(si->si_type), &si->si_syncCookie.octet_str, rhint );
474         } else {
475                 ber_printf( ber, "{eb}",
476                         abs(si->si_type), rhint );
477         }
478
479         if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
480                 ber_free_buf( ber );
481                 return rc;
482         }
483
484         c[0].ldctl_oid = LDAP_CONTROL_SYNC;
485         c[0].ldctl_iscritical = si->si_type < 0;
486         ctrls[0] = &c[0];
487
488         c[1].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
489         BER_BVZERO( &c[1].ldctl_value );
490         c[1].ldctl_iscritical = 1;
491         ctrls[1] = &c[1];
492
493         if ( !BER_BVISNULL( &si->si_bindconf.sb_authzId ) ) {
494                 c[2].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
495                 c[2].ldctl_value = si->si_bindconf.sb_authzId;
496                 c[2].ldctl_iscritical = 1;
497                 ctrls[2] = &c[2];
498                 ctrls[3] = NULL;
499         } else {
500                 ctrls[2] = NULL;
501         }
502
503         rc = ldap_search_ext( si->si_ld, base, scope, filter, attrs, attrsonly,
504                 ctrls, NULL, NULL, si->si_slimit, &si->si_msgid );
505         ber_free_buf( ber );
506         return rc;
507 }
508
509 static int
510 check_syncprov(
511         Operation *op,
512         syncinfo_t *si )
513 {
514         AttributeName at[2];
515         Attribute a = {0};
516         Entry e = {0};
517         SlapReply rs = {REP_SEARCH};
518         int i, j, changed = 0;
519
520         /* Look for contextCSN from syncprov overlay. If
521          * there's no overlay, this will be a no-op. That means
522          * this is a pure consumer, so local changes will not be
523          * allowed, and all changes will already be reflected in
524          * the cookieState.
525          */
526         a.a_desc = slap_schema.si_ad_contextCSN;
527         e.e_attrs = &a;
528         e.e_name = si->si_contextdn;
529         e.e_nname = si->si_contextdn;
530         at[0].an_name = a.a_desc->ad_cname;
531         at[0].an_desc = a.a_desc;
532         BER_BVZERO( &at[1].an_name );
533         rs.sr_entry = &e;
534         rs.sr_flags = REP_ENTRY_MODIFIABLE;
535         rs.sr_attrs = at;
536         op->o_req_dn = e.e_name;
537         op->o_req_ndn = e.e_nname;
538
539         ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
540         i = backend_operational( op, &rs );
541         if ( i == LDAP_SUCCESS && a.a_nvals ) {
542                 int num = a.a_numvals;
543                 /* check for differences */
544                 if ( num != si->si_cookieState->cs_num ) {
545                         changed = 1;
546                 } else {
547                         for ( i=0; i<num; i++ ) {
548                                 if ( ber_bvcmp( &a.a_nvals[i],
549                                         &si->si_cookieState->cs_vals[i] )) {
550                                         changed = 1;
551                                         break;
552                                 }
553                         }
554                 }
555                 if ( changed ) {
556                         ber_bvarray_free( si->si_cookieState->cs_vals );
557                         ch_free( si->si_cookieState->cs_sids );
558                         si->si_cookieState->cs_num = num;
559                         si->si_cookieState->cs_vals = a.a_nvals;
560                         si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_nvals,
561                                 num, NULL );
562                         si->si_cookieState->cs_age++;
563                 } else {
564                         ber_bvarray_free( a.a_nvals );
565                 }
566                 ber_bvarray_free( a.a_vals );
567                 si->si_has_syncprov = 1;
568         }
569         /* See if the cookieState has changed due to anything outside
570          * this particular consumer. That includes other consumers in
571          * the same context, or local changes detected above.
572          */
573         if ( si->si_cookieState->cs_num > 0 && si->si_cookieAge !=
574                 si->si_cookieState->cs_age ) {
575                 if ( !si->si_syncCookie.numcsns ) {
576                         ber_bvarray_free( si->si_syncCookie.ctxcsn );
577                         ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
578                                 si->si_cookieState->cs_vals, NULL );
579                         changed = 1;
580                 } else {
581                         for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) {
582                                 /* bogus, just dup everything */
583                                 if ( si->si_syncCookie.sids[i] == -1 ) {
584                                         ber_bvarray_free( si->si_syncCookie.ctxcsn );
585                                         ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
586                                                 si->si_cookieState->cs_vals, NULL );
587                                         changed = 1;
588                                         break;
589                                 }
590                                 for (j=0; j<si->si_cookieState->cs_num; j++) {
591                                         if ( si->si_syncCookie.sids[i] !=
592                                                 si->si_cookieState->cs_sids[j] )
593                                                 continue;
594                                         if ( bvmatch( &si->si_syncCookie.ctxcsn[i],
595                                                 &si->si_cookieState->cs_vals[j] ))
596                                                 break;
597                                         ber_bvreplace( &si->si_syncCookie.ctxcsn[i],
598                                                 &si->si_cookieState->cs_vals[j] );
599                                         changed = 1;
600                                         break;
601                                 }
602                         }
603                 }
604         }
605         if ( changed ) {
606                 si->si_cookieAge = si->si_cookieState->cs_age;
607                 ch_free( si->si_syncCookie.octet_str.bv_val );
608                 slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
609                         si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
610                         si->si_syncCookie.sid );
611                 ch_free( si->si_syncCookie.sids );
612                 slap_reparse_sync_cookie( &si->si_syncCookie, op->o_tmpmemctx );
613         }
614         ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
615         return changed;
616 }
617
618 static int
619 do_syncrep1(
620         Operation *op,
621         syncinfo_t *si )
622 {
623         int     rc;
624         int cmdline_cookie_found = 0;
625
626         struct sync_cookie      *sc = NULL;
627 #ifdef HAVE_TLS
628         void    *ssl;
629 #endif
630
631         rc = slap_client_connect( &si->si_ld, &si->si_bindconf );
632         if ( rc != LDAP_SUCCESS ) {
633                 goto done;
634         }
635         op->o_protocol = LDAP_VERSION3;
636
637         /* Set SSF to strongest of TLS, SASL SSFs */
638         op->o_sasl_ssf = 0;
639         op->o_tls_ssf = 0;
640         op->o_transport_ssf = 0;
641 #ifdef HAVE_TLS
642         if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl )
643                 == LDAP_SUCCESS && ssl != NULL )
644         {
645                 op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
646         }
647 #endif /* HAVE_TLS */
648         {
649                 ber_len_t ssf; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought
650                                                   to use sasl_ssf_t but currently uses ber_len_t */
651                 if ( ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf )
652                         == LDAP_SUCCESS )
653                         op->o_sasl_ssf = ssf;
654         }
655         op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
656                 ?  op->o_sasl_ssf : op->o_tls_ssf;
657
658         ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );
659
660         rc = LDAP_DEREF_NEVER;  /* actually could allow DEREF_FINDING */
661         ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc );
662
663         ldap_set_option( si->si_ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );
664
665         si->si_syncCookie.rid = si->si_rid;
666
667         /* whenever there are multiple data sources possible, advertise sid */
668         si->si_syncCookie.sid = ( SLAP_MULTIMASTER( si->si_be ) || si->si_be != si->si_wbe ) ?
669                 slap_serverID : -1;
670
671         /* We've just started up, or the remote server hasn't sent us
672          * any meaningful state.
673          */
674         if ( !si->si_syncCookie.ctxcsn ) {
675                 int i;
676
677                 LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) {
678                         if ( si->si_rid == sc->rid ) {
679                                 cmdline_cookie_found = 1;
680                                 break;
681                         }
682                 }
683
684                 if ( cmdline_cookie_found ) {
685                         /* cookie is supplied in the command line */
686
687                         LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );
688
689                         slap_sync_cookie_free( &si->si_syncCookie, 0 );
690                         si->si_syncCookie.octet_str = sc->octet_str;
691                         ch_free( sc );
692                         /* ctxcsn wasn't parsed yet, do it now */
693                         slap_parse_sync_cookie( &si->si_syncCookie, NULL );
694                 } else {
695                         ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
696                         if ( !si->si_cookieState->cs_num ) {
697                                 /* get contextCSN shadow replica from database */
698                                 BerVarray csn = NULL;
699                                 void *ctx = op->o_tmpmemctx;
700
701                                 op->o_req_ndn = si->si_contextdn;
702                                 op->o_req_dn = op->o_req_ndn;
703
704                                 /* try to read stored contextCSN */
705                                 op->o_tmpmemctx = NULL;
706                                 backend_attribute( op, NULL, &op->o_req_ndn,
707                                         slap_schema.si_ad_contextCSN, &csn, ACL_READ );
708                                 op->o_tmpmemctx = ctx;
709                                 if ( csn ) {
710                                         si->si_cookieState->cs_vals = csn;
711                                         for (i=0; !BER_BVISNULL( &csn[i] ); i++);
712                                         si->si_cookieState->cs_num = i;
713                                         si->si_cookieState->cs_sids = slap_parse_csn_sids( csn, i, NULL );
714                                         slap_sort_csn_sids( csn, si->si_cookieState->cs_sids, i, NULL );
715                                 }
716                         }
717                         if ( si->si_cookieState->cs_num ) {
718                                 ber_bvarray_free( si->si_syncCookie.ctxcsn );
719                                 if ( ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
720                                         si->si_cookieState->cs_vals, NULL )) {
721                                         rc = LDAP_NO_MEMORY;
722                                         ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
723                                         goto done;
724                                 }
725                                 si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
726                                 si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num *
727                                         sizeof(int) );
728                                 for ( i=0; i<si->si_syncCookie.numcsns; i++ )
729                                         si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i];
730                         }
731                         ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
732                         /* Also look in syncprov overlay, if it was already active */
733                         check_syncprov( op, si );
734                 }
735
736                 ch_free( si->si_syncCookie.octet_str.bv_val );
737                 slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
738                         si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
739                         si->si_syncCookie.sid );
740         } else {
741                 /* ITS#6367: recreate the cookie so it has our SID, not our peer's */
742                 ch_free( si->si_syncCookie.octet_str.bv_val );
743                 BER_BVZERO( &si->si_syncCookie.octet_str );
744                 /* Look for contextCSN from syncprov overlay. */
745                 check_syncprov( op, si );
746                 if ( BER_BVISNULL( &si->si_syncCookie.octet_str ))
747                         slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
748                                 si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
749                                 si->si_syncCookie.sid );
750         }
751
752         si->si_refreshDone = 0;
753         si->si_refreshBeg = slap_get_time();
754         si->si_refreshCount = 0;
755         si->si_refreshTxn = NULL;
756         Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s starting refresh\n",
757                 si->si_ridtxt, 0, 0 );
758
759         rc = ldap_sync_search( si, op->o_tmpmemctx );
760
761         if( rc != LDAP_SUCCESS ) {
762                 Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s "
763                         "ldap_search_ext: %s (%d)\n",
764                         si->si_ridtxt, ldap_err2string( rc ), rc );
765         }
766
767 done:
768         if ( rc ) {
769                 if ( si->si_ld ) {
770                         ldap_unbind_ext( si->si_ld, NULL, NULL );
771                         si->si_ld = NULL;
772                 }
773         }
774
775         return rc;
776 }
777
778 static int
779 compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
780 {
781         int i, j, match = 0;
782         const char *text;
783
784         *which = 0;
785
786         if ( sc1->numcsns < sc2->numcsns ) {
787                 *which = sc1->numcsns;
788                 return -1;
789         }
790
791         for (j=0; j<sc2->numcsns; j++) {
792                 for (i=0; i<sc1->numcsns; i++) {
793                         if ( sc1->sids[i] != sc2->sids[j] )
794                                 continue;
795                         value_match( &match, slap_schema.si_ad_entryCSN,
796                                 slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
797                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
798                                 &sc1->ctxcsn[i], &sc2->ctxcsn[j], &text );
799                         if ( match < 0 ) {
800                                 *which = j;
801                                 return match;
802                         }
803                         break;
804                 }
805                 if ( i == sc1->numcsns ) {
806                         /* sc2 has a sid sc1 lacks */
807                         *which = j;
808                         return -1;
809                 }
810         }
811         return match;
812 }
813
814 #define SYNC_PAUSED     -3
815
816 static int
817 do_syncrep2(
818         Operation *op,
819         syncinfo_t *si )
820 {
821         BerElementBuffer berbuf;
822         BerElement      *ber = (BerElement *)&berbuf;
823
824         LDAPMessage     *msg = NULL;
825
826         struct sync_cookie      syncCookie = { NULL };
827         struct sync_cookie      syncCookie_req = { NULL };
828
829         int             rc,
830                         err = LDAP_SUCCESS;
831
832         Modifications   *modlist = NULL;
833
834         int                             m;
835
836         struct timeval *tout_p = NULL;
837         struct timeval tout = { 0, 0 };
838
839         int             refreshDeletes = 0;
840         char empty[6] = "empty";
841
842         if ( slapd_shutdown ) {
843                 rc = -2;
844                 goto done;
845         }
846
847         ber_init2( ber, NULL, LBER_USE_DER );
848         ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
849
850         Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2 %s\n", si->si_ridtxt, 0, 0 );
851
852         slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
853
854         if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST && si->si_refreshDone ) {
855                 tout_p = &tout;
856         } else {
857                 tout_p = NULL;
858         }
859
860         while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
861                 tout_p, &msg ) ) > 0 )
862         {
863                 int                             match, punlock, syncstate;
864                 struct berval   *retdata, syncUUID[2], cookie = BER_BVNULL;
865                 char                    *retoid;
866                 LDAPControl             **rctrls = NULL, *rctrlp = NULL;
867                 BerVarray               syncUUIDs;
868                 ber_len_t               len;
869                 ber_tag_t               si_tag;
870                 Entry                   *entry;
871                 struct berval   bdn;
872
873                 if ( slapd_shutdown ) {
874                         rc = -2;
875                         goto done;
876                 }
877                 switch( ldap_msgtype( msg ) ) {
878                 case LDAP_RES_SEARCH_ENTRY:
879                         ldap_get_entry_controls( si->si_ld, msg, &rctrls );
880                         ldap_get_dn_ber( si->si_ld, msg, NULL, &bdn );
881                         if (!bdn.bv_len) {
882                                 bdn.bv_val = empty;
883                                 bdn.bv_len = sizeof(empty)-1;
884                         }
885                         /* we can't work without the control */
886                         if ( rctrls ) {
887                                 LDAPControl **next = NULL;
888                                 /* NOTE: make sure we use the right one;
889                                  * a better approach would be to run thru
890                                  * the whole list and take care of all */
891                                 /* NOTE: since we issue the search request,
892                                  * we should know what controls to expect,
893                                  * and there should be none apart from the
894                                  * sync-related control */
895                                 rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_STATE, rctrls, &next );
896                                 if ( next && ldap_control_find( LDAP_CONTROL_SYNC_STATE, next, NULL ) )
897                                 {
898                                         bdn.bv_val[bdn.bv_len] = '\0';
899                                         Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
900                                                 "got search entry with multiple "
901                                                 "Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
902                                         ldap_controls_free( rctrls );
903                                         rc = -1;
904                                         goto done;
905                                 }
906                         }
907                         if ( rctrlp == NULL ) {
908                                 bdn.bv_val[bdn.bv_len] = '\0';
909                                 Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
910                                         "got search entry without "
911                                         "Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
912                                 rc = -1;
913                                 goto done;
914                         }
915                         ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
916                         if ( ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID[0] )
917                                         == LBER_ERROR ) {
918                                 bdn.bv_val[bdn.bv_len] = '\0';
919                                 Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s malformed message (%s)\n",
920                                         si->si_ridtxt, bdn.bv_val, 0 );
921                                 ldap_controls_free( rctrls );
922                                 rc = -1;
923                                 goto done;
924                         }
925                         /* FIXME: what if syncUUID is NULL or empty?
926                          * (happens with back-sql...) */
927                         if ( syncUUID[0].bv_len != UUIDLEN ) {
928                                 bdn.bv_val[bdn.bv_len] = '\0';
929                                 Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
930                                         "got empty or invalid syncUUID with LDAP_SYNC_%s (%s)\n",
931                                         si->si_ridtxt,
932                                         syncrepl_state2str( syncstate ), bdn.bv_val );
933                                 ldap_controls_free( rctrls );
934                                 rc = -1;
935                                 goto done;
936                         }
937                         punlock = -1;
938                         if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
939                                 if ( ber_scanf( ber, /*"{"*/ "m}", &cookie ) != LBER_ERROR ) {
940
941                                 Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
942                                         si->si_ridtxt,
943                                         BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
944
945                                 if ( !BER_BVISNULL( &cookie ) ) {
946                                         ch_free( syncCookie.octet_str.bv_val );
947                                         ber_dupbv( &syncCookie.octet_str, &cookie );
948                                 }
949                                 if ( !BER_BVISNULL( &syncCookie.octet_str ) )
950                                 {
951                                         slap_parse_sync_cookie( &syncCookie, NULL );
952                                         if ( syncCookie.ctxcsn ) {
953                                                 int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
954                                                 check_syncprov( op, si );
955                                                 ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
956                                                 for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
957 #ifdef CHATTY_SYNCLOG
958                                                         Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN for sid %d: %s\n",
959                                                                 si->si_ridtxt, i, si->si_cookieState->cs_vals[i].bv_val );
960 #endif
961                                                         /* new SID */
962                                                         if ( sid < si->si_cookieState->cs_sids[i] )
963                                                                 break;
964                                                         if ( si->si_cookieState->cs_sids[i] == sid ) {
965                                                                 if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
966                                                                         bdn.bv_val[bdn.bv_len] = '\0';
967                                                                         Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s (%s)\n",
968                                                                                 si->si_ridtxt, syncCookie.ctxcsn->bv_val, bdn.bv_val );
969                                                                         si->si_too_old = 1;
970                                                                         ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
971                                                                         ldap_controls_free( rctrls );
972                                                                         rc = 0;
973                                                                         goto done;
974                                                                 }
975                                                                 si->si_too_old = 0;
976                                                                 break;
977                                                         }
978                                                 }
979                                                 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
980
981                                                 /* check pending CSNs too */
982                                                 while ( ldap_pvt_thread_mutex_trylock( &si->si_cookieState->cs_pmutex )) {
983                                                         if ( slapd_shutdown ) {
984                                                                 rc = -2;
985                                                                 goto done;
986                                                         }
987                                                         if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
988                                                                 ldap_pvt_thread_yield();
989                                                 }
990
991                                                 for ( i =0; i<si->si_cookieState->cs_pnum; i++ ) {
992                                                         if ( sid < si->si_cookieState->cs_psids[i] )
993                                                                 break;
994                                                         if ( si->si_cookieState->cs_psids[i] == sid ) {
995                                                                 if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_pvals[i] ) <= 0 ) {
996                                                                         ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
997                                                                         bdn.bv_val[bdn.bv_len] = '\0';
998                                                                         Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN pending, ignoring %s (%s)\n",
999                                                                                 si->si_ridtxt, syncCookie.ctxcsn->bv_val, bdn.bv_val );
1000                                                                         ldap_controls_free( rctrls );
1001                                                                         rc = 0;
1002                                                                         goto done;
1003                                                                 }
1004                                                                 ber_bvreplace( &si->si_cookieState->cs_pvals[i],
1005                                                                         syncCookie.ctxcsn );
1006                                                                 break;
1007                                                         }
1008                                                 }
1009                                                 /* new SID, add it */
1010                                                 if ( i == si->si_cookieState->cs_pnum ||
1011                                                         sid != si->si_cookieState->cs_psids[i] ) {
1012                                                         slap_insert_csn_sids(
1013                                                                 (struct sync_cookie *)&si->si_cookieState->cs_pvals,
1014                                                                 i, sid, syncCookie.ctxcsn );
1015                                                 }
1016                                                 assert( punlock < 0 );
1017                                                 punlock = i;
1018                                         } else if (si->si_too_old) {
1019                                                 bdn.bv_val[bdn.bv_len] = '\0';
1020                                                 Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring (%s)\n",
1021                                                         si->si_ridtxt, bdn.bv_val, 0 );
1022                                                 ldap_controls_free( rctrls );
1023                                                 rc = 0;
1024                                                 goto done;
1025                                         }
1026                                         op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
1027                                 }
1028                                 }
1029                         }
1030                         rc = 0;
1031                         if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
1032                                 modlist = NULL;
1033                                 if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
1034                                         syncCookie.ctxcsn )
1035                                 {
1036                                         rc = syncrepl_updateCookie( si, op, &syncCookie, 0 );
1037                                 } else switch ( rc ) {
1038                                         case LDAP_ALREADY_EXISTS:
1039                                         case LDAP_NO_SUCH_OBJECT:
1040                                         case LDAP_NO_SUCH_ATTRIBUTE:
1041                                         case LDAP_TYPE_OR_VALUE_EXISTS:
1042                                         case LDAP_NOT_ALLOWED_ON_NONLEAF:
1043                                                 rc = LDAP_SYNC_REFRESH_REQUIRED;
1044                                                 si->si_logstate = SYNCLOG_FALLBACK;
1045                                                 ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
1046                                                 bdn.bv_val[bdn.bv_len] = '\0';
1047                                                 Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync on (%s), switching to REFRESH\n",
1048                                                         si->si_ridtxt, bdn.bv_val, 0 );
1049                                                 if (si->si_strict_refresh) {
1050                                                         slap_suspend_listeners();
1051                                                         connections_drop();
1052                                                 }
1053                                                 break;
1054                                         default:
1055                                                 break;
1056                                 }
1057                         } else if ( ( rc = syncrepl_message_to_entry( si, op, msg,
1058                                 &modlist, &entry, syncstate, syncUUID ) ) == LDAP_SUCCESS )
1059                         {
1060                                 if ( ( rc = syncrepl_entry( si, op, entry, &modlist,
1061                                         syncstate, syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
1062                                         syncCookie.ctxcsn )
1063                                 {
1064                                         rc = syncrepl_updateCookie( si, op, &syncCookie, 0 );
1065                                 }
1066                         }
1067                         if ( punlock >= 0 ) {
1068                                 /* on failure, revert pending CSN */
1069                                 if ( rc != LDAP_SUCCESS ) {
1070                                         int i;
1071                                         ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
1072                                         for ( i = 0; i<si->si_cookieState->cs_num; i++ ) {
1073                                                 if ( si->si_cookieState->cs_sids[i] == si->si_cookieState->cs_psids[punlock] ) {
1074                                                         ber_bvreplace( &si->si_cookieState->cs_pvals[punlock],
1075                                                                 &si->si_cookieState->cs_vals[i] );
1076                                                         break;
1077                                                 }
1078                                         }
1079                                         if ( i == si->si_cookieState->cs_num )
1080                                                 si->si_cookieState->cs_pvals[punlock].bv_val[0] = '\0';
1081                                         ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
1082                                 }
1083                                 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
1084                         }
1085                         ldap_controls_free( rctrls );
1086                         if ( modlist ) {
1087                                 slap_mods_free( modlist, 1 );
1088                         }
1089                         if ( rc )
1090                                 goto done;
1091                         break;
1092
1093                 case LDAP_RES_SEARCH_REFERENCE:
1094                         Debug( LDAP_DEBUG_ANY,
1095                                 "do_syncrep2: %s reference received error\n",
1096                                 si->si_ridtxt, 0, 0 );
1097                         break;
1098
1099                 case LDAP_RES_SEARCH_RESULT:
1100                         Debug( LDAP_DEBUG_SYNC,
1101                                 "do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
1102                                 si->si_ridtxt, 0, 0 );
1103                         err = LDAP_OTHER; /* FIXME check parse result properly */
1104                         ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
1105                                 &rctrls, 0 );
1106 #ifdef LDAP_X_SYNC_REFRESH_REQUIRED
1107                         if ( err == LDAP_X_SYNC_REFRESH_REQUIRED ) {
1108                                 /* map old result code to registered code */
1109                                 err = LDAP_SYNC_REFRESH_REQUIRED;
1110                         }
1111 #endif
1112                         if ( err == LDAP_SYNC_REFRESH_REQUIRED ) {
1113                                 if ( si->si_logstate == SYNCLOG_LOGGING ) {
1114                                         si->si_logstate = SYNCLOG_FALLBACK;
1115                                         Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync, switching to REFRESH\n",
1116                                                 si->si_ridtxt, 0, 0 );
1117                                         if (si->si_strict_refresh) {
1118                                                 slap_suspend_listeners();
1119                                                 connections_drop();
1120                                         }
1121                                 }
1122                                 rc = err;
1123                                 goto done;
1124                         }
1125                         if ( err ) {
1126                                 Debug( LDAP_DEBUG_ANY,
1127                                         "do_syncrep2: %s LDAP_RES_SEARCH_RESULT (%d) %s\n",
1128                                         si->si_ridtxt, err, ldap_err2string( err ) );
1129                         }
1130                         if ( rctrls ) {
1131                                 LDAPControl **next = NULL;
1132                                 /* NOTE: make sure we use the right one;
1133                                  * a better approach would be to run thru
1134                                  * the whole list and take care of all */
1135                                 /* NOTE: since we issue the search request,
1136                                  * we should know what controls to expect,
1137                                  * and there should be none apart from the
1138                                  * sync-related control */
1139                                 rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_DONE, rctrls, &next );
1140                                 if ( next && ldap_control_find( LDAP_CONTROL_SYNC_DONE, next, NULL ) )
1141                                 {
1142                                         Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
1143                                                 "got search result with multiple "
1144                                                 "Sync State control\n", si->si_ridtxt, 0, 0 );
1145                                         ldap_controls_free( rctrls );
1146                                         rc = -1;
1147                                         goto done;
1148                                 }
1149                         }
1150                         if ( rctrlp ) {
1151                                 ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
1152
1153                                 ber_scanf( ber, "{" /*"}"*/);
1154                                 if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
1155                                         ber_scanf( ber, "m", &cookie );
1156
1157                                         Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
1158                                                 si->si_ridtxt, 
1159                                                 BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
1160
1161                                         if ( !BER_BVISNULL( &cookie ) ) {
1162                                                 ch_free( syncCookie.octet_str.bv_val );
1163                                                 ber_dupbv( &syncCookie.octet_str, &cookie);
1164                                         }
1165                                         if ( !BER_BVISNULL( &syncCookie.octet_str ) )
1166                                         {
1167                                                 slap_parse_sync_cookie( &syncCookie, NULL );
1168                                                 op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
1169                                         }
1170                                 }
1171                                 if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
1172                                 {
1173                                         ber_scanf( ber, "b", &refreshDeletes );
1174                                 }
1175                                 ber_scanf( ber, /*"{"*/ "}" );
1176                         }
1177                         if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
1178                                 slap_sync_cookie_free( &syncCookie_req, 0 );
1179                                 slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
1180                         }
1181                         if ( !syncCookie.ctxcsn ) {
1182                                 match = 1;
1183                         } else if ( !syncCookie_req.ctxcsn ) {
1184                                 match = -1;
1185                                 m = 0;
1186                         } else {
1187                                 match = compare_csns( &syncCookie_req, &syncCookie, &m );
1188                         }
1189                         if ( rctrls ) {
1190                                 ldap_controls_free( rctrls );
1191                         }
1192                         if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
1193                                 /* FIXME : different error behaviors according to
1194                                  *      1) err code : LDAP_BUSY ...
1195                                  *      2) on err policy : stop service, stop sync, retry
1196                                  */
1197                                 if ( refreshDeletes == 0 && match < 0 &&
1198                                         err == LDAP_SUCCESS &&
1199                                         syncCookie_req.numcsns == syncCookie.numcsns )
1200                                 {
1201                                         syncrepl_del_nonpresent( op, si, NULL,
1202                                                 &syncCookie, m );
1203                                 } else if ( si->si_presentlist ) {
1204                                         presentlist_free( si->si_presentlist );
1205                                         si->si_presentlist = NULL;
1206                                 }
1207                         }
1208                         if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
1209                         {
1210                                 rc = syncrepl_updateCookie( si, op, &syncCookie, 1 );
1211                         }
1212                         if ( si->si_refreshCount ) {
1213                                 LDAP_SLIST_REMOVE( &op->o_extra, si->si_refreshTxn, OpExtra, oe_next );
1214                                 op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_COMMIT, &si->si_refreshTxn );
1215                                 si->si_refreshCount = 0;
1216                                 si->si_refreshTxn = NULL;
1217                         }
1218                         si->si_refreshEnd = slap_get_time();
1219                         if ( err == LDAP_SUCCESS
1220                                 && si->si_logstate == SYNCLOG_FALLBACK ) {
1221                                 si->si_logstate = SYNCLOG_LOGGING;
1222                                 rc = LDAP_SYNC_REFRESH_REQUIRED;
1223                                 slap_resume_listeners();
1224                         } else {
1225                                 rc = -2;
1226                         }
1227                         goto done;
1228
1229                 case LDAP_RES_INTERMEDIATE:
1230                         retoid = NULL;
1231                         retdata = NULL;
1232                         rc = ldap_parse_intermediate( si->si_ld, msg,
1233                                 &retoid, &retdata, NULL, 0 );
1234                         if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
1235                                 ber_init2( ber, retdata, LBER_USE_DER );
1236
1237                                 switch ( si_tag = ber_peek_tag( ber, &len ) ) {
1238                                 ber_tag_t tag;
1239                                 case LDAP_TAG_SYNC_NEW_COOKIE:
1240                                         Debug( LDAP_DEBUG_SYNC,
1241                                                 "do_syncrep2: %s %s - %s\n", 
1242                                                 si->si_ridtxt,
1243                                                 "LDAP_RES_INTERMEDIATE", 
1244                                                 "NEW_COOKIE" );
1245                                         ber_scanf( ber, "tm", &tag, &cookie );
1246                                         Debug( LDAP_DEBUG_SYNC,
1247                                                 "do_syncrep2: %s NEW_COOKIE: %s\n",
1248                                                 si->si_ridtxt,
1249                                                 cookie.bv_val, 0);
1250                                         if ( !BER_BVISNULL( &cookie ) ) {
1251                                                 ch_free( syncCookie.octet_str.bv_val );
1252                                                 ber_dupbv( &syncCookie.octet_str, &cookie );
1253                                         }
1254                                         if (!BER_BVISNULL( &syncCookie.octet_str ) ) {
1255                                                 slap_parse_sync_cookie( &syncCookie, NULL );
1256                                                 op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
1257                                         }
1258                                         break;
1259                                 case LDAP_TAG_SYNC_REFRESH_DELETE:
1260                                 case LDAP_TAG_SYNC_REFRESH_PRESENT:
1261                                         Debug( LDAP_DEBUG_SYNC,
1262                                                 "do_syncrep2: %s %s - %s\n", 
1263                                                 si->si_ridtxt,
1264                                                 "LDAP_RES_INTERMEDIATE", 
1265                                                 si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ?
1266                                                 "REFRESH_PRESENT" : "REFRESH_DELETE" );
1267                                         if ( si_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
1268                                                 si->si_refreshDelete = 1;
1269                                         } else {
1270                                                 si->si_refreshPresent = 1;
1271                                         }
1272                                         ber_scanf( ber, "t{" /*"}"*/, &tag );
1273                                         if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
1274                                         {
1275                                                 ber_scanf( ber, "m", &cookie );
1276
1277                                                 Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
1278                                                         si->si_ridtxt, 
1279                                                         BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
1280
1281                                                 if ( !BER_BVISNULL( &cookie ) ) {
1282                                                         ch_free( syncCookie.octet_str.bv_val );
1283                                                         ber_dupbv( &syncCookie.octet_str, &cookie );
1284                                                 }
1285                                                 if ( !BER_BVISNULL( &syncCookie.octet_str ) )
1286                                                 {
1287                                                         slap_parse_sync_cookie( &syncCookie, NULL );
1288                                                         op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
1289                                                 }
1290                                         }
1291                                         /* Defaults to TRUE */
1292                                         if ( ber_peek_tag( ber, &len ) ==
1293                                                 LDAP_TAG_REFRESHDONE )
1294                                         {
1295                                                 ber_scanf( ber, "b", &si->si_refreshDone );
1296                                         } else
1297                                         {
1298                                                 si->si_refreshDone = 1;
1299                                         }
1300                                         if ( si->si_refreshDone ) {
1301                                                 if ( si->si_refreshCount ) {
1302                                                         LDAP_SLIST_REMOVE( &op->o_extra, si->si_refreshTxn, OpExtra, oe_next );
1303                                                         op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_COMMIT, &si->si_refreshTxn );
1304                                                         si->si_refreshCount = 0;
1305                                                         si->si_refreshTxn = NULL;
1306                                                 }
1307                                                 si->si_refreshEnd = slap_get_time();
1308         Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s finished refresh\n",
1309                 si->si_ridtxt, 0, 0 );
1310                                         }
1311                                         ber_scanf( ber, /*"{"*/ "}" );
1312                                         if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
1313                                                 si->si_refreshDone )
1314                                                 tout_p = &tout;
1315                                         break;
1316                                 case LDAP_TAG_SYNC_ID_SET:
1317                                         Debug( LDAP_DEBUG_SYNC,
1318                                                 "do_syncrep2: %s %s - %s\n", 
1319                                                 si->si_ridtxt,
1320                                                 "LDAP_RES_INTERMEDIATE", 
1321                                                 "SYNC_ID_SET" );
1322                                         ber_scanf( ber, "t{" /*"}"*/, &tag );
1323                                         if ( ber_peek_tag( ber, &len ) ==
1324                                                 LDAP_TAG_SYNC_COOKIE )
1325                                         {
1326                                                 ber_scanf( ber, "m", &cookie );
1327
1328                                                 Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
1329                                                         si->si_ridtxt,
1330                                                         BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
1331
1332                                                 if ( !BER_BVISNULL( &cookie ) ) {
1333                                                         ch_free( syncCookie.octet_str.bv_val );
1334                                                         ber_dupbv( &syncCookie.octet_str, &cookie );
1335                                                 }
1336                                                 if ( !BER_BVISNULL( &syncCookie.octet_str ) )
1337                                                 {
1338                                                         slap_parse_sync_cookie( &syncCookie, NULL );
1339                                                         op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
1340                                                         compare_csns( &syncCookie_req, &syncCookie, &m );
1341                                                 }
1342                                         }
1343                                         if ( ber_peek_tag( ber, &len ) ==
1344                                                 LDAP_TAG_REFRESHDELETES )
1345                                         {
1346                                                 ber_scanf( ber, "b", &refreshDeletes );
1347                                         }
1348                                         syncUUIDs = NULL;
1349                                         rc = ber_scanf( ber, "[W]", &syncUUIDs );
1350                                         ber_scanf( ber, /*"{"*/ "}" );
1351                                         if ( rc != LBER_ERROR ) {
1352                                                 if ( refreshDeletes ) {
1353                                                         syncrepl_del_nonpresent( op, si, syncUUIDs,
1354                                                                 &syncCookie, m );
1355                                                         ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
1356                                                 } else {
1357                                                         int i;
1358                                                         for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
1359                                                                 (void)presentlist_insert( si, &syncUUIDs[i] );
1360                                                                 slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx );
1361                                                         }
1362                                                         slap_sl_free( syncUUIDs, op->o_tmpmemctx );
1363                                                 }
1364                                         }
1365                                         rc = 0;
1366                                         slap_sync_cookie_free( &syncCookie, 0 );
1367                                         break;
1368                                 default:
1369                                         Debug( LDAP_DEBUG_ANY,
1370                                                 "do_syncrep2: %s unknown syncinfo tag (%ld)\n",
1371                                                 si->si_ridtxt, (long) si_tag, 0 );
1372                                         ldap_memfree( retoid );
1373                                         ber_bvfree( retdata );
1374                                         continue;
1375                                 }
1376
1377                                 if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
1378                                         slap_sync_cookie_free( &syncCookie_req, 0 );
1379                                         slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
1380                                 }
1381                                 if ( !syncCookie.ctxcsn ) {
1382                                         match = 1;
1383                                 } else if ( !syncCookie_req.ctxcsn ) {
1384                                         match = -1;
1385                                         m = 0;
1386                                 } else {
1387                                         match = compare_csns( &syncCookie_req, &syncCookie, &m );
1388                                 }
1389
1390                                 if ( match < 0 ) {
1391                                         if ( si->si_refreshPresent == 1 &&
1392                                                 si_tag != LDAP_TAG_SYNC_NEW_COOKIE &&
1393                                                 syncCookie_req.numcsns == syncCookie.numcsns ) {
1394                                                 syncrepl_del_nonpresent( op, si, NULL,
1395                                                         &syncCookie, m );
1396                                         }
1397
1398                                         if ( syncCookie.ctxcsn )
1399                                         {
1400                                                 rc = syncrepl_updateCookie( si, op, &syncCookie, 1 );
1401                                         }
1402                                         if ( si->si_presentlist ) {
1403                                                 presentlist_free( si->si_presentlist );
1404                                                 si->si_presentlist = NULL;
1405                                         }
1406                                 } 
1407
1408                                 ldap_memfree( retoid );
1409                                 ber_bvfree( retdata );
1410
1411                                 if ( rc )
1412                                         goto done;
1413
1414                         } else {
1415                                 Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
1416                                         "unknown intermediate response (%d)\n",
1417                                         si->si_ridtxt, rc, 0 );
1418                                 ldap_memfree( retoid );
1419                                 ber_bvfree( retdata );
1420                         }
1421                         break;
1422
1423                 default:
1424                         Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
1425                                 "unknown message (0x%02lx)\n",
1426                                 si->si_ridtxt,
1427                                 (unsigned long)ldap_msgtype( msg ), 0 );
1428                         break;
1429
1430                 }
1431                 if ( !BER_BVISNULL( &syncCookie.octet_str ) ) {
1432                         slap_sync_cookie_free( &syncCookie_req, 0 );
1433                         syncCookie_req = syncCookie;
1434                         memset( &syncCookie, 0, sizeof( syncCookie ));
1435                 }
1436                 ldap_msgfree( msg );
1437                 msg = NULL;
1438                 if ( ldap_pvt_thread_pool_pausing( &connection_pool )) {
1439                         slap_sync_cookie_free( &syncCookie, 0 );
1440                         slap_sync_cookie_free( &syncCookie_req, 0 );
1441                         if ( si->si_refreshCount ) {
1442                                 LDAP_SLIST_REMOVE( &op->o_extra, si->si_refreshTxn, OpExtra, oe_next );
1443                                 op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_COMMIT, &si->si_refreshTxn );
1444                                 si->si_refreshCount = 0;
1445                                 si->si_refreshTxn = NULL;
1446                         }
1447                         return SYNC_PAUSED;
1448                 }
1449         }
1450
1451         if ( rc == -1 ) {
1452                 rc = LDAP_OTHER;
1453                 ldap_get_option( si->si_ld, LDAP_OPT_ERROR_NUMBER, &rc );
1454                 err = rc;
1455         }
1456
1457 done:
1458         if ( err != LDAP_SUCCESS ) {
1459                 Debug( LDAP_DEBUG_ANY,
1460                         "do_syncrep2: %s (%d) %s\n",
1461                         si->si_ridtxt, err, ldap_err2string( err ) );
1462         }
1463
1464         slap_sync_cookie_free( &syncCookie, 0 );
1465         slap_sync_cookie_free( &syncCookie_req, 0 );
1466
1467         if ( msg ) ldap_msgfree( msg );
1468
1469         if ( rc && rc != LDAP_SYNC_REFRESH_REQUIRED && si->si_ld ) {
1470                 if ( si->si_conn ) {
1471                         connection_client_stop( si->si_conn );
1472                         si->si_conn = NULL;
1473                 }
1474                 ldap_unbind_ext( si->si_ld, NULL, NULL );
1475                 si->si_ld = NULL;
1476         }
1477
1478         return rc;
1479 }
1480
1481 static void *
1482 do_syncrepl(
1483         void    *ctx,
1484         void    *arg )
1485 {
1486         struct re_s* rtask = arg;
1487         syncinfo_t *si = ( syncinfo_t * ) rtask->arg;
1488         Connection conn = {0};
1489         OperationBuffer opbuf;
1490         Operation *op;
1491         int rc = LDAP_SUCCESS;
1492         int dostop = 0;
1493         ber_socket_t s;
1494         int i, defer = 1, fail = 0, freeinfo = 0;
1495         Backend *be;
1496
1497         if ( si == NULL )
1498                 return NULL;
1499         if ( slapd_shutdown )
1500                 return NULL;
1501
1502         Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt, 0, 0 );
1503
1504         /* Don't get stuck here while a pause is initiated */
1505         while ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
1506                 if ( slapd_shutdown )
1507                         return NULL;
1508                 if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
1509                         ldap_pvt_thread_yield();
1510         }
1511
1512         si->si_too_old = 0;
1513
1514         if ( si->si_ctype < 1 ) {
1515                 goto deleted;
1516         }
1517
1518         switch( abs( si->si_type ) ) {
1519         case LDAP_SYNC_REFRESH_ONLY:
1520         case LDAP_SYNC_REFRESH_AND_PERSIST:
1521                 break;
1522         default:
1523                 ldap_pvt_thread_mutex_unlock( &si->si_mutex );
1524                 return NULL;
1525         }
1526
1527         if ( slapd_shutdown ) {
1528                 if ( si->si_ld ) {
1529                         if ( si->si_conn ) {
1530                                 connection_client_stop( si->si_conn );
1531                                 si->si_conn = NULL;
1532                         }
1533                         ldap_unbind_ext( si->si_ld, NULL, NULL );
1534                         si->si_ld = NULL;
1535                 }
1536                 ldap_pvt_thread_mutex_unlock( &si->si_mutex );
1537                 return NULL;
1538         }
1539
1540         connection_fake_init( &conn, &opbuf, ctx );
1541         op = &opbuf.ob_op;
1542         /* o_connids must be unique for slap_graduate_commit_csn */
1543         op->o_connid = SLAPD_SYNC_RID2SYNCCONN(si->si_rid);
1544
1545         op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
1546         be = si->si_be;
1547
1548         /* Coordinate contextCSN updates with any syncprov overlays
1549          * in use. This may be complicated by the use of the glue
1550          * overlay.
1551          *
1552          * Typically there is a single syncprov mastering the entire
1553          * glued tree. In that case, our contextCSN updates should
1554          * go to the master DB. But if there is no syncprov on the
1555          * master DB, then nothing special is needed here.
1556          *
1557          * Alternatively, there may be individual syncprov overlays
1558          * on each glued branch. In that case, each syncprov only
1559          * knows about changes within its own branch. And so our
1560          * contextCSN updates should only go to the local DB.
1561          */
1562         if ( !si->si_wbe ) {
1563                 if ( SLAP_GLUE_SUBORDINATE( be ) && !overlay_is_inst( be, "syncprov" )) {
1564                         BackendDB * top_be = select_backend( &be->be_nsuffix[0], 1 );
1565                         if ( overlay_is_inst( top_be, "syncprov" ))
1566                                 si->si_wbe = top_be;
1567                         else
1568                                 si->si_wbe = be;
1569                 } else {
1570                         si->si_wbe = be;
1571                 }
1572                 if ( SLAP_SYNC_SUBENTRY( si->si_wbe )) {
1573                         build_new_dn( &si->si_contextdn, &si->si_wbe->be_nsuffix[0],
1574                                 (struct berval *)&slap_ldapsync_cn_bv, NULL );
1575                 } else {
1576                         si->si_contextdn = si->si_wbe->be_nsuffix[0];
1577                 }
1578         }
1579         if ( !si->si_schemachecking )
1580                 op->o_no_schema_check = 1;
1581
1582         /* Establish session, do search */
1583         if ( !si->si_ld ) {
1584                 si->si_refreshDelete = 0;
1585                 si->si_refreshPresent = 0;
1586
1587                 if ( si->si_presentlist ) {
1588                     presentlist_free( si->si_presentlist );
1589                     si->si_presentlist = NULL;
1590                 }
1591
1592                 /* use main DB when retrieving contextCSN */
1593                 op->o_bd = si->si_wbe;
1594                 op->o_dn = op->o_bd->be_rootdn;
1595                 op->o_ndn = op->o_bd->be_rootndn;
1596                 rc = do_syncrep1( op, si );
1597         }
1598
1599 reload:
1600         /* Process results */
1601         if ( rc == LDAP_SUCCESS ) {
1602                 ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
1603
1604                 /* use current DB */
1605                 op->o_bd = be;
1606                 op->o_dn = op->o_bd->be_rootdn;
1607                 op->o_ndn = op->o_bd->be_rootndn;
1608                 rc = do_syncrep2( op, si );
1609                 if ( rc == LDAP_SYNC_REFRESH_REQUIRED ) {
1610                         if ( BER_BVISNULL( &si->si_syncCookie.octet_str ))
1611                                 slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
1612                                         si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
1613                                         si->si_syncCookie.sid );
1614                         rc = ldap_sync_search( si, op->o_tmpmemctx );
1615                         goto reload;
1616                 }
1617
1618 deleted:
1619                 /* We got deleted while running on cn=config */
1620                 if ( si->si_ctype < 1 ) {
1621                         if ( si->si_ctype == -1 ) {
1622                                 si->si_ctype = 0;
1623                                 freeinfo = 1;
1624                         }
1625                         if ( si->si_conn )
1626                                 dostop = 1;
1627                         rc = -1;
1628                 }
1629
1630                 if ( rc != SYNC_PAUSED ) {
1631                         if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
1632                                 /* If we succeeded, enable the connection for further listening.
1633                                  * If we failed, tear down the connection and reschedule.
1634                                  */
1635                                 if ( rc == LDAP_SUCCESS ) {
1636                                         if ( si->si_conn ) {
1637                                                 connection_client_enable( si->si_conn );
1638                                         } else {
1639                                                 si->si_conn = connection_client_setup( s, do_syncrepl, arg );
1640                                         } 
1641                                 } else if ( si->si_conn ) {
1642                                         dostop = 1;
1643                                 }
1644                         } else {
1645                                 if ( rc == -2 ) rc = 0;
1646                         }
1647                 }
1648         }
1649
1650         /* At this point, we have 5 cases:
1651          * 1) for any hard failure, give up and remove this task
1652          * 2) for ServerDown, reschedule this task to run later
1653          * 3) for threadpool pause, reschedule to run immediately
1654          * 4) for Refresh and Success, reschedule to run
1655          * 5) for Persist and Success, reschedule to defer
1656          */
1657         ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
1658
1659         if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask ) ) {
1660                 ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
1661         }
1662
1663         if ( dostop ) {
1664                 connection_client_stop( si->si_conn );
1665                 si->si_conn = NULL;
1666         }
1667
1668         if ( rc == SYNC_PAUSED ) {
1669                 rtask->interval.tv_sec = 0;
1670                 ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
1671                 rtask->interval.tv_sec = si->si_interval;
1672                 rc = 0;
1673         } else if ( rc == LDAP_SUCCESS ) {
1674                 if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
1675                         defer = 0;
1676                 }
1677                 rtask->interval.tv_sec = si->si_interval;
1678                 ldap_pvt_runqueue_resched( &slapd_rq, rtask, defer );
1679                 if ( si->si_retrynum ) {
1680                         for ( i = 0; si->si_retrynum_init[i] != RETRYNUM_TAIL; i++ ) {
1681                                 si->si_retrynum[i] = si->si_retrynum_init[i];
1682                         }
1683                         si->si_retrynum[i] = RETRYNUM_TAIL;
1684                 }
1685         } else {
1686                 for ( i = 0; si->si_retrynum && si->si_retrynum[i] <= 0; i++ ) {
1687                         if ( si->si_retrynum[i] == RETRYNUM_FOREVER || si->si_retrynum[i] == RETRYNUM_TAIL )
1688                                 break;
1689                 }
1690
1691                 if ( si->si_ctype < 1
1692                         || !si->si_retrynum || si->si_retrynum[i] == RETRYNUM_TAIL ) {
1693                         if ( si->si_re ) {
1694                                 ldap_pvt_runqueue_remove( &slapd_rq, rtask );
1695                                 si->si_re = NULL;
1696                         }
1697                         fail = RETRYNUM_TAIL;
1698                 } else if ( RETRYNUM_VALID( si->si_retrynum[i] ) ) {
1699                         if ( si->si_retrynum[i] > 0 )
1700                                 si->si_retrynum[i]--;
1701                         fail = si->si_retrynum[i];
1702                         rtask->interval.tv_sec = si->si_retryinterval[i];
1703                         ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
1704                         slap_wake_listener();
1705                 }
1706         }
1707
1708         ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
1709         ldap_pvt_thread_mutex_unlock( &si->si_mutex );
1710
1711         if ( rc ) {
1712                 if ( fail == RETRYNUM_TAIL ) {
1713                         Debug( LDAP_DEBUG_ANY,
1714                                 "do_syncrepl: %s rc %d quitting\n",
1715                                 si->si_ridtxt, rc, 0 );
1716                 } else if ( fail > 0 ) {
1717                         Debug( LDAP_DEBUG_ANY,
1718                                 "do_syncrepl: %s rc %d retrying (%d retries left)\n",
1719                                 si->si_ridtxt, rc, fail );
1720                 } else {
1721                         Debug( LDAP_DEBUG_ANY,
1722                                 "do_syncrepl: %s rc %d retrying\n",
1723                                 si->si_ridtxt, rc, 0 );
1724                 }
1725         }
1726
1727         /* Do final delete cleanup */
1728         if ( freeinfo ) {
1729                 syncinfo_free( si, 0 );
1730         }
1731         return NULL;
1732 }
1733
1734 #ifdef ENABLE_REWRITE
1735 static int
1736 syncrepl_rewrite_dn(
1737         syncinfo_t *si,
1738         struct berval *dn,
1739         struct berval *sdn )
1740 {
1741         char nul;
1742         int rc;
1743
1744         nul = dn->bv_val[dn->bv_len];
1745         dn->bv_val[dn->bv_len] = 0;
1746         rc = rewrite( si->si_rewrite, SUFFIXM_CTX, dn->bv_val, &sdn->bv_val );
1747         dn->bv_val[dn->bv_len] = nul;
1748
1749         if ( sdn->bv_val == dn->bv_val )
1750                 sdn->bv_val = NULL;
1751         else if ( rc == REWRITE_REGEXEC_OK && sdn->bv_val )
1752                 sdn->bv_len = strlen( sdn->bv_val );
1753         return rc;
1754 }
1755 #define REWRITE_VAL(si, ad, bv, bv2)    \
1756         BER_BVZERO( &bv2 );     \
1757         if ( si->si_rewrite && ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName) \
1758                 syncrepl_rewrite_dn( si, &bv, &bv2); \
1759         if ( BER_BVISNULL( &bv2 ))  \
1760                 ber_dupbv( &bv2, &bv )
1761 #define REWRITE_DN(si, bv, bv2, dn, ndn) \
1762         BER_BVZERO( &bv2 );     \
1763         if (si->si_rewrite) \
1764                 syncrepl_rewrite_dn(si, &bv, &bv2); \
1765         rc = dnPrettyNormal( NULL, bv2.bv_val ? &bv2 : &bv, &dn, &ndn, op->o_tmpmemctx ); \
1766         ch_free(bv2.bv_val)
1767 #else
1768 #define REWRITE_VAL(si, ad, bv, bv2)    ber_dupbv(&bv2, &bv)
1769 #define REWRITE_DN(si, bv, bv2, dn, ndn) \
1770         rc = dnPrettyNormal( NULL, &bv, &dn, &ndn, op->o_tmpmemctx )
1771 #endif
1772
1773
1774 static slap_verbmasks modops[] = {
1775         { BER_BVC("add"), LDAP_REQ_ADD },
1776         { BER_BVC("delete"), LDAP_REQ_DELETE },
1777         { BER_BVC("modify"), LDAP_REQ_MODIFY },
1778         { BER_BVC("modrdn"), LDAP_REQ_MODRDN},
1779         { BER_BVNULL, 0 }
1780 };
1781
1782 static int
1783 syncrepl_accesslog_mods(
1784         syncinfo_t *si,
1785         struct berval *vals,
1786         struct Modifications **modres
1787 )
1788 {
1789         char *colon;
1790         const char *text;
1791         AttributeDescription *ad;
1792         struct berval bv, bv2;
1793         short op;
1794         Modifications *mod = NULL, *modlist = NULL, **modtail;
1795         int i, rc = 0;
1796
1797         modtail = &modlist;
1798
1799         for (i=0; !BER_BVISNULL( &vals[i] ); i++) {
1800                 ad = NULL;
1801                 bv = vals[i];
1802
1803                 colon = ber_bvchr( &bv, ':' );
1804                 if ( !colon ) {
1805                         /* Invalid */
1806                         continue;
1807                 } else if ( colon == bv.bv_val ) {
1808                         /* ITS#6545: An empty attribute signals that a new mod
1809                          * is about to start */
1810                         mod = NULL;
1811                         continue;
1812                 }
1813
1814                 bv.bv_len = colon - bv.bv_val;
1815                 if ( slap_bv2ad( &bv, &ad, &text ) ) {
1816                         /* Invalid */
1817                         Debug( LDAP_DEBUG_ANY, "syncrepl_accesslog_mods: %s "
1818                                 "Invalid attribute %s, %s\n",
1819                                 si->si_ridtxt, bv.bv_val, text );
1820                         slap_mods_free( modlist, 1 );
1821                         modlist = NULL;
1822                         rc = -1;
1823                         break;
1824                 }
1825
1826                 /* Ignore dynamically generated attrs */
1827                 if ( ad->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
1828                         continue;
1829                 }
1830
1831                 /* Ignore excluded attrs */
1832                 if ( ldap_charray_inlist( si->si_exattrs,
1833                         ad->ad_type->sat_cname.bv_val ) )
1834                 {
1835                         continue;
1836                 }
1837
1838                 switch(colon[1]) {
1839                 case '+':       op = LDAP_MOD_ADD; break;
1840                 case '-':       op = LDAP_MOD_DELETE; break;
1841                 case '=':       op = LDAP_MOD_REPLACE; break;
1842                 case '#':       op = LDAP_MOD_INCREMENT; break;
1843                 default:        continue;
1844                 }
1845
1846                 if ( !mod || ad != mod->sml_desc || op != mod->sml_op ) {
1847                         mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
1848                         mod->sml_flags = 0;
1849                         mod->sml_op = op;
1850                         mod->sml_next = NULL;
1851                         mod->sml_desc = ad;
1852                         mod->sml_type = ad->ad_cname;
1853                         mod->sml_values = NULL;
1854                         mod->sml_nvalues = NULL;
1855                         mod->sml_numvals = 0;
1856
1857                         *modtail = mod;
1858                         modtail = &mod->sml_next;
1859                 }
1860                 if ( colon[2] == ' ' ) {
1861                         bv.bv_val = colon + 3;
1862                         bv.bv_len = vals[i].bv_len - ( bv.bv_val - vals[i].bv_val );
1863                         REWRITE_VAL( si, ad, bv, bv2 );
1864                         ber_bvarray_add( &mod->sml_values, &bv2 );
1865                         mod->sml_numvals++;
1866                 }
1867         }
1868         *modres = modlist;
1869         return rc;
1870 }
1871
1872 static int
1873 syncrepl_changelog_mods(
1874         syncinfo_t *si,
1875         struct berval *vals,
1876         struct Modifications **modres
1877 )
1878 {
1879         return -1;      /* FIXME */
1880 }
1881
1882 typedef struct OpExtraSync {
1883         OpExtra oe;
1884         syncinfo_t *oe_si;
1885 } OpExtraSync;
1886
1887 /* Copy the original modlist, split Replace ops into Delete/Add,
1888  * and drop mod opattrs since this modification is in the past.
1889  */
1890 static Modifications *mods_dup( Operation *op, Modifications *modlist, int match )
1891 {
1892         Modifications *mod, *modnew = NULL, *modtail = NULL;
1893         int size;
1894         for ( ; modlist; modlist = modlist->sml_next ) {
1895                 /* older ops */
1896                 if ( match < 0 ) {
1897                         if ( modlist->sml_desc == slap_schema.si_ad_modifiersName ||
1898                                 modlist->sml_desc == slap_schema.si_ad_modifyTimestamp ||
1899                                 modlist->sml_desc == slap_schema.si_ad_entryCSN )
1900                                 continue;
1901                         if ( modlist->sml_op == LDAP_MOD_REPLACE ) {
1902                                 mod = op->o_tmpalloc( sizeof(Modifications), op->o_tmpmemctx );
1903                                 mod->sml_desc = modlist->sml_desc;
1904                                 mod->sml_values = NULL;
1905                                 mod->sml_nvalues = NULL;
1906                                 mod->sml_op = LDAP_MOD_DELETE;
1907                                 mod->sml_numvals = 0;
1908                                 mod->sml_flags = 0;
1909                                 if ( !modnew )
1910                                         modnew = mod;
1911                                 if ( modtail )
1912                                         modtail->sml_next = mod;
1913                                 modtail = mod;
1914                         }
1915                 }
1916                 if ( modlist->sml_numvals ) {
1917                         size = (modlist->sml_numvals+1) * sizeof(struct berval);
1918                         if ( modlist->sml_nvalues ) size *= 2;
1919                 } else {
1920                         size = 0;
1921                 }
1922                 size += sizeof(Modifications);
1923                 mod = op->o_tmpalloc( size, op->o_tmpmemctx );
1924                 if ( !modnew )
1925                         modnew = mod;
1926                 if ( modtail )
1927                         modtail->sml_next = mod;
1928                 modtail = mod;
1929                 mod->sml_desc = modlist->sml_desc;
1930                 mod->sml_numvals = modlist->sml_numvals;
1931                 mod->sml_flags = 0;
1932                 if ( modlist->sml_numvals ) {
1933                         int i;
1934                         mod->sml_values = (BerVarray)(mod+1);
1935                         for (i=0; i<mod->sml_numvals; i++)
1936                                 mod->sml_values[i] = modlist->sml_values[i];
1937                         BER_BVZERO(&mod->sml_values[i]);
1938                         if ( modlist->sml_nvalues ) {
1939                                 mod->sml_nvalues = mod->sml_values + mod->sml_numvals + 1;
1940                                 for (i=0; i<mod->sml_numvals; i++)
1941                                         mod->sml_nvalues[i] = modlist->sml_nvalues[i];
1942                                 BER_BVZERO(&mod->sml_nvalues[i]);
1943                         } else {
1944                                 mod->sml_nvalues = NULL;
1945                         }
1946                 } else {
1947                         mod->sml_values = NULL;
1948                         mod->sml_nvalues = NULL;
1949                 }
1950                 if ( match < 0 && modlist->sml_op == LDAP_MOD_REPLACE )
1951                         mod->sml_op = LDAP_MOD_ADD;
1952                 else
1953                         mod->sml_op = modlist->sml_op;
1954                 mod->sml_next = NULL;
1955         }
1956         return modnew;
1957 }
1958
1959 typedef struct resolve_ctxt {
1960         syncinfo_t *rx_si;
1961         Modifications *rx_mods;
1962 } resolve_ctxt;
1963
1964 static void
1965 compare_vals( Modifications *m1, Modifications *m2 )
1966 {
1967         int i, j;
1968         struct berval *bv1, *bv2;
1969
1970         if ( m2->sml_nvalues ) {
1971                 bv2 = m2->sml_nvalues;
1972                 bv1 = m1->sml_nvalues;
1973         } else {
1974                 bv2 = m2->sml_values;
1975                 bv1 = m1->sml_values;
1976         }
1977         for ( j=0; j<m2->sml_numvals; j++ ) {
1978                 for ( i=0; i<m1->sml_numvals; i++ ) {
1979                         if ( !ber_bvcmp( &bv1[i], &bv2[j] )) {
1980                                 int k;
1981                                 for ( k=i; k<m1->sml_numvals-1; k++ ) {
1982                                         m1->sml_values[k] = m1->sml_values[k+1];
1983                                         if ( m1->sml_nvalues )
1984                                                 m1->sml_nvalues[k] = m1->sml_nvalues[k+1];
1985                                 }
1986                                 BER_BVZERO(&m1->sml_values[k]);
1987                                 if ( m1->sml_nvalues ) {
1988                                         BER_BVZERO(&m1->sml_nvalues[k]);
1989                                 }
1990                                 m1->sml_numvals--;
1991                                 i--;
1992                         }
1993                 }
1994         }
1995 }
1996
1997 static int
1998 syncrepl_resolve_cb( Operation *op, SlapReply *rs )
1999 {
2000         if ( rs->sr_type == REP_SEARCH ) {
2001                 resolve_ctxt *rx = op->o_callback->sc_private;
2002                 Attribute *a = attr_find( rs->sr_entry->e_attrs, ad_reqMod );
2003                 if ( a ) {
2004                         Modifications *oldmods, *newmods, *m1, *m2, **prev;
2005                         oldmods = rx->rx_mods;
2006                         syncrepl_accesslog_mods( rx->rx_si, a->a_vals, &newmods );
2007                         for ( m2 = newmods; m2; m2=m2->sml_next ) {
2008                                 for ( prev = &oldmods, m1 = *prev; m1; m1 = *prev ) {
2009                                         if ( m1->sml_desc != m2->sml_desc ) {
2010                                                 prev = &m1->sml_next;
2011                                                 continue;
2012                                         }
2013                                         if ( m2->sml_op == LDAP_MOD_DELETE ||
2014                                                 m2->sml_op == LDAP_MOD_REPLACE ) {
2015                                                 int numvals = m2->sml_numvals;
2016                                                 if ( m2->sml_op == LDAP_MOD_REPLACE )
2017                                                         numvals = 0;
2018                                                 /* New delete All cancels everything */
2019                                                 if ( numvals == 0 ) {
2020 drop:
2021                                                         *prev = m1->sml_next;
2022                                                         op->o_tmpfree( m1, op->o_tmpmemctx );
2023                                                         continue;
2024                                                 }
2025                                                 if ( m1->sml_op == LDAP_MOD_DELETE ) {
2026                                                         if ( m1->sml_numvals == 0 ) {
2027                                                                 /* turn this to SOFTDEL later */
2028                                                                 m1->sml_flags = SLAP_MOD_INTERNAL;
2029                                                         } else {
2030                                                                 compare_vals( m1, m2 );
2031                                                                 if ( !m1->sml_numvals )
2032                                                                         goto drop;
2033                                                         }
2034                                                 } else if ( m1->sml_op == LDAP_MOD_ADD ) {
2035                                                         compare_vals( m1, m2 );
2036                                                         if ( !m1->sml_numvals )
2037                                                                 goto drop;
2038                                                 }
2039                                         }
2040
2041                                         if ( m2->sml_op == LDAP_MOD_ADD ||
2042                                                 m2->sml_op == LDAP_MOD_REPLACE ) {
2043                                                 if ( m1->sml_op == LDAP_MOD_DELETE ) {
2044                                                         if ( !m1->sml_numvals ) goto drop;
2045                                                         compare_vals( m1, m2 );
2046                                                         if ( !m1->sml_numvals )
2047                                                                 goto drop;
2048                                                 }
2049                                                 if ( m2->sml_desc->ad_type->sat_atype.at_single_value )
2050                                                         goto drop;
2051                                                 compare_vals( m1, m2 );
2052                                                 if ( !m1->sml_numvals )
2053                                                         goto drop;
2054                                         }
2055                                         prev = &m1->sml_next;
2056                                 }
2057                         }
2058                         slap_mods_free( newmods, 1 );
2059                         rx->rx_mods = oldmods;
2060                 }
2061         }
2062         return LDAP_SUCCESS;
2063 }
2064
2065 typedef struct modify_ctxt {
2066         Modifications *mx_orig;
2067         Modifications *mx_free;
2068 } modify_ctxt;
2069
2070 static int
2071 syncrepl_modify_cb( Operation *op, SlapReply *rs )
2072 {
2073         slap_callback *sc = op->o_callback;
2074         modify_ctxt *mx = sc->sc_private;
2075         Modifications *ml;
2076
2077         op->orm_no_opattrs = 0;
2078         op->orm_modlist = mx->mx_orig;
2079         for ( ml = mx->mx_free; ml; ml = mx->mx_free ) {
2080                 mx->mx_free = ml->sml_next;
2081                 op->o_tmpfree( ml, op->o_tmpmemctx );
2082         }
2083         op->o_callback = sc->sc_next;
2084         op->o_tmpfree( sc, op->o_tmpmemctx );
2085         return SLAP_CB_CONTINUE;
2086 }
2087
2088 static int
2089 syncrepl_op_modify( Operation *op, SlapReply *rs )
2090 {
2091         slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
2092         OpExtra *oex;
2093         syncinfo_t *si;
2094         Entry *e;
2095         int rc, match = 0;
2096         Modifications *mod, *newlist;
2097
2098         LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
2099                 if ( oex->oe_key == (void *)syncrepl_message_to_op )
2100                         break;
2101         }
2102         if ( !oex )
2103                 return SLAP_CB_CONTINUE;
2104
2105         si = ((OpExtraSync *)oex)->oe_si;
2106
2107         /* Check if entryCSN in modlist is newer than entryCSN in entry.
2108          * We do it here because the op has been serialized by accesslog
2109          * by the time we get here. If the CSN is new enough, just do the
2110          * mod. If not, we need to resolve conflicts.
2111          */
2112
2113         for ( mod = op->orm_modlist; mod; mod=mod->sml_next ) {
2114                 if ( mod->sml_desc == slap_schema.si_ad_entryCSN ) break;
2115         }
2116         /* FIXME: what should we do if entryCSN is missing from the mod? */
2117         if ( !mod )
2118                 return SLAP_CB_CONTINUE;
2119
2120         {
2121                 int i, sid;
2122                 sid = slap_parse_csn_sid( &mod->sml_nvalues[0] );
2123                 ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
2124                 for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
2125 #ifdef CHATTY_SYNCLOG
2126                         Debug( LDAP_DEBUG_SYNC, "syncrepl_op_modify: %s CSN for sid %d: %s\n",
2127                                 si->si_ridtxt, i, si->si_cookieState->cs_vals[i].bv_val );
2128 #endif
2129                         /* new SID */
2130                         if ( sid < si->si_cookieState->cs_sids[i] )
2131                                 break;
2132                         if ( si->si_cookieState->cs_sids[i] == sid ) {
2133                                 if ( ber_bvcmp( &mod->sml_nvalues[0], &si->si_cookieState->cs_vals[i] ) <= 0 ) {
2134                                         Debug( LDAP_DEBUG_SYNC, "syncrepl_op_modify: %s entryCSN too old, ignoring %s (%s)\n",
2135                                                 si->si_ridtxt, mod->sml_nvalues[0].bv_val, op->o_req_dn.bv_val );
2136                                         ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
2137                                         slap_graduate_commit_csn( op );
2138                                         /* tell accesslog this was a failure */
2139                                         rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS;
2140                                         return LDAP_SUCCESS;
2141                                 }
2142                         }
2143                 }
2144                 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
2145         }
2146
2147         rc = overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on );
2148         if ( rc == 0 ) {
2149                 Attribute *a;
2150                 const char *text;
2151                 a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
2152                 value_match( &match, slap_schema.si_ad_entryCSN,
2153                         slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
2154                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
2155                         &mod->sml_nvalues[0], &a->a_nvals[0], &text );
2156                 overlay_entry_release_ov( op, e, 0, on );
2157         }
2158         /* equal? Should never happen */
2159         if ( match == 0 ) {
2160                 slap_graduate_commit_csn( op );
2161                 /* tell accesslog this was a failure */
2162                 rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS;
2163                 return LDAP_SUCCESS;
2164         }
2165
2166         /* mod is older: resolve conflicts...
2167          * 1. Save/copy original modlist. Split Replace to Del/Add.
2168          * 2. Find all mods to this reqDN newer than the mod stamp.
2169          * 3. Resolve any mods in this request that affect attributes
2170          *    touched by newer mods.
2171          *    old         new
2172          *    delete all  delete all  drop
2173          *    delete all  delete X    SOFTDEL
2174          *    delete X    delete all  drop
2175          *    delete X    delete X    drop
2176          *    delete X    delete Y    OK
2177          *    delete all  add X       drop
2178          *    delete X    add X       drop
2179          *    delete X    add Y       OK
2180          *    add X       delete all  drop
2181          *    add X       delete X    drop
2182          *    add X       add X       drop
2183          *    add X       add Y       if SV, drop else OK
2184          *
2185          * 4. Swap original modlist back in response callback so
2186          *    that accesslog logs the original mod.
2187          *
2188          * Even if the mod is newer, other out-of-order changes may
2189          * have been committed, forcing us to tweak the modlist:
2190          * 1. Save/copy original modlist.
2191          * 2. Change deletes to soft deletes.
2192          * 3. Change Adds of single-valued attrs to Replace.
2193          */
2194
2195         newlist = mods_dup( op, op->orm_modlist, match );
2196
2197         /* mod is older */
2198         if ( match < 0 ) {
2199                 Operation op2 = *op;
2200                 AttributeName an[2];
2201                 struct berval bv;
2202                 int size;
2203                 SlapReply rs1 = {0};
2204                 resolve_ctxt rx;
2205                 slap_callback cb = { NULL, syncrepl_resolve_cb, NULL, NULL };
2206         Filter lf[3] = {0};
2207         AttributeAssertion aa[2] = {0};
2208
2209                 rx.rx_si = si;
2210                 rx.rx_mods = newlist;
2211                 cb.sc_private = &rx;
2212
2213                 op2.o_tag = LDAP_REQ_SEARCH;
2214                 op2.ors_scope = LDAP_SCOPE_SUBTREE;
2215                 op2.ors_deref = LDAP_DEREF_NEVER;
2216                 op2.o_req_dn = si->si_logbase;
2217                 op2.o_req_ndn = si->si_logbase;
2218                 op2.ors_tlimit = SLAP_NO_LIMIT;
2219                 op2.ors_slimit = SLAP_NO_LIMIT;
2220                 op2.ors_limit = NULL;
2221                 memset( an, 0, sizeof(an));
2222                 an[0].an_desc = ad_reqMod;
2223                 an[0].an_name = ad_reqMod->ad_cname;
2224                 op2.ors_attrs = an;
2225                 op2.ors_attrsonly = 0;
2226
2227                 bv = mod->sml_nvalues[0];
2228
2229                 size = sizeof("(&(entryCSN>=)(reqDN=))");
2230                 size += bv.bv_len + op->o_req_ndn.bv_len + si->si_logfilterstr.bv_len;
2231                 op2.ors_filterstr.bv_val = op->o_tmpalloc( size, op->o_tmpmemctx );
2232                 op2.ors_filterstr.bv_len = sprintf(op2.ors_filterstr.bv_val,
2233                         "(&(entryCSN>=%s)(reqDN=%s)%s)",
2234                         bv.bv_val, op->o_req_ndn.bv_val, si->si_logfilterstr.bv_val );
2235
2236         lf[0].f_choice = LDAP_FILTER_AND;
2237         lf[0].f_and = lf+1;
2238         lf[1].f_choice = LDAP_FILTER_GE;
2239         lf[1].f_ava = aa;
2240         lf[1].f_av_desc = slap_schema.si_ad_entryCSN;
2241         lf[1].f_av_value = bv;
2242         lf[1].f_next = lf+2;
2243         lf[2].f_choice = LDAP_FILTER_EQUALITY;
2244         lf[2].f_ava = aa+1;
2245         lf[2].f_av_desc = ad_reqDN;
2246         lf[2].f_av_value = op->o_req_ndn;
2247         lf[2].f_next = si->si_logfilter;
2248
2249                 op2.ors_filter = lf;
2250
2251                 op2.o_callback = &cb;
2252                 op2.o_bd = select_backend( &op2.o_req_ndn, 1 );
2253                 op2.o_bd->be_search( &op2, &rs1 );
2254                 newlist = rx.rx_mods;
2255         }
2256
2257         {
2258                 slap_callback *sc = op->o_tmpalloc( sizeof(slap_callback) +
2259                         sizeof(modify_ctxt), op->o_tmpmemctx );
2260                 modify_ctxt *mx = (modify_ctxt *)(sc+1);
2261                 Modifications *ml;
2262
2263                 sc->sc_response = syncrepl_modify_cb;
2264                 sc->sc_private = mx;
2265                 sc->sc_next = op->o_callback;
2266                 sc->sc_cleanup = NULL;
2267                 sc->sc_writewait = NULL;
2268                 op->o_callback = sc;
2269                 op->orm_no_opattrs = 1;
2270                 mx->mx_orig = op->orm_modlist;
2271                 mx->mx_free = newlist;
2272                 for ( ml = newlist; ml; ml=ml->sml_next ) {
2273                         if ( ml->sml_flags == SLAP_MOD_INTERNAL ) {
2274                                 ml->sml_flags = 0;
2275                                 ml->sml_op = SLAP_MOD_SOFTDEL;
2276                         }
2277                         else if ( ml->sml_op == LDAP_MOD_DELETE )
2278                                 ml->sml_op = SLAP_MOD_SOFTDEL;
2279                         else if ( ml->sml_op == LDAP_MOD_ADD &&
2280                                 ml->sml_desc->ad_type->sat_atype.at_single_value )
2281                                 ml->sml_op = LDAP_MOD_REPLACE;
2282                 }
2283                 op->orm_modlist = newlist;
2284                 op->o_csn = mod->sml_nvalues[0];
2285         }
2286         return SLAP_CB_CONTINUE;
2287 }
2288
2289 static int
2290 syncrepl_null_callback(
2291         Operation *op,
2292         SlapReply *rs )
2293 {
2294         /* If we're not the last callback in the chain, move to the end */
2295         if ( op->o_callback->sc_next ) {
2296                 slap_callback **sc, *s1;
2297                 s1 = op->o_callback;
2298                 op->o_callback = op->o_callback->sc_next;
2299                 for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) ;
2300                 *sc = s1;
2301                 s1->sc_next = NULL;
2302                 return SLAP_CB_CONTINUE;
2303         }
2304         if ( rs->sr_err != LDAP_SUCCESS &&
2305                 rs->sr_err != LDAP_REFERRAL &&
2306                 rs->sr_err != LDAP_ALREADY_EXISTS &&
2307                 rs->sr_err != LDAP_NO_SUCH_OBJECT &&
2308                 rs->sr_err != LDAP_NOT_ALLOWED_ON_NONLEAF )
2309         {
2310                 Debug( LDAP_DEBUG_ANY,
2311                         "syncrepl_null_callback : error code 0x%x\n",
2312                         rs->sr_err, 0, 0 );
2313         }
2314         return LDAP_SUCCESS;
2315 }
2316
2317 static int
2318 syncrepl_message_to_op(
2319         syncinfo_t      *si,
2320         Operation       *op,
2321         LDAPMessage     *msg
2322 )
2323 {
2324         BerElement      *ber = NULL;
2325         Modifications   *modlist = NULL;
2326         logschema *ls;
2327         SlapReply rs = { REP_RESULT };
2328         slap_callback cb = { NULL, syncrepl_null_callback, NULL, NULL };
2329
2330         const char      *text;
2331         char txtbuf[SLAP_TEXT_BUFLEN];
2332         size_t textlen = sizeof txtbuf;
2333
2334         struct berval   bdn, dn = BER_BVNULL, ndn;
2335         struct berval   bv, bv2, *bvals = NULL;
2336         struct berval   rdn = BER_BVNULL, sup = BER_BVNULL,
2337                 prdn = BER_BVNULL, nrdn = BER_BVNULL,
2338                 psup = BER_BVNULL, nsup = BER_BVNULL;
2339         int             rc, deleteOldRdn = 0, freeReqDn = 0;
2340         int             do_graduate = 0;
2341
2342         if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
2343                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
2344                         "Message type should be entry (%d)",
2345                         si->si_ridtxt, ldap_msgtype( msg ), 0 );
2346                 return -1;
2347         }
2348
2349         if ( si->si_syncdata == SYNCDATA_ACCESSLOG )
2350                 ls = &accesslog_sc;
2351         else
2352                 ls = &changelog_sc;
2353
2354         rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
2355
2356         if ( rc != LDAP_SUCCESS ) {
2357                 Debug( LDAP_DEBUG_ANY,
2358                         "syncrepl_message_to_op: %s dn get failed (%d)",
2359                         si->si_ridtxt, rc, 0 );
2360                 return rc;
2361         }
2362
2363         op->o_tag = LBER_DEFAULT;
2364         op->o_bd = si->si_wbe;
2365
2366         if ( BER_BVISEMPTY( &bdn )) {
2367                 Debug( LDAP_DEBUG_ANY,
2368                         "syncrepl_message_to_op: %s got empty dn",
2369                         si->si_ridtxt, 0, 0 );
2370                 return LDAP_OTHER;
2371         }
2372
2373         while (( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, &bvals ) )
2374                 == LDAP_SUCCESS ) {
2375                 if ( bv.bv_val == NULL )
2376                         break;
2377
2378                 if ( !ber_bvstrcasecmp( &bv, &ls->ls_dn ) ) {
2379                         bdn = bvals[0];
2380                         REWRITE_DN( si, bdn, bv2, dn, ndn );
2381                         if ( rc != LDAP_SUCCESS ) {
2382                                 Debug( LDAP_DEBUG_ANY,
2383                                         "syncrepl_message_to_op: %s "
2384                                         "dn \"%s\" normalization failed (%d)",
2385                                         si->si_ridtxt, bdn.bv_val, rc );
2386                                 rc = -1;
2387                                 ch_free( bvals );
2388                                 goto done;
2389                         }
2390                         ber_dupbv( &op->o_req_dn, &dn );
2391                         ber_dupbv( &op->o_req_ndn, &ndn );
2392                         slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
2393                         slap_sl_free( dn.bv_val, op->o_tmpmemctx );
2394                         freeReqDn = 1;
2395                 } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_req ) ) {
2396                         int i = verb_to_mask( bvals[0].bv_val, modops );
2397                         if ( i < 0 ) {
2398                                 Debug( LDAP_DEBUG_ANY,
2399                                         "syncrepl_message_to_op: %s unknown op %s",
2400                                         si->si_ridtxt, bvals[0].bv_val, 0 );
2401                                 ch_free( bvals );
2402                                 rc = -1;
2403                                 goto done;
2404                         }
2405                         op->o_tag = modops[i].mask;
2406                 } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_mod ) ) {
2407                         /* Parse attribute into modlist */
2408                         if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) {
2409                                 rc = syncrepl_accesslog_mods( si, bvals, &modlist );
2410                         } else {
2411                                 rc = syncrepl_changelog_mods( si, bvals, &modlist );
2412                         }
2413                         if ( rc ) goto done;
2414                 } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newRdn ) ) {
2415                         rdn = bvals[0];
2416                 } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_delRdn ) ) {
2417                         if ( !ber_bvstrcasecmp( &slap_true_bv, bvals ) ) {
2418                                 deleteOldRdn = 1;
2419                         }
2420                 } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newSup ) ) {
2421                         sup = bvals[0];
2422                 } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_controls ) ) {
2423                         int i;
2424                         struct berval rel_ctrl_bv;
2425
2426                         (void)ber_str2bv( "{" LDAP_CONTROL_RELAX, 0, 0, &rel_ctrl_bv );
2427                         for ( i = 0; bvals[i].bv_val; i++ ) {
2428                                 struct berval cbv, tmp;
2429
2430                                 ber_bvchr_post( &cbv, &bvals[i], '}' );
2431                                 ber_bvchr_post( &tmp, &cbv, '{' );
2432                                 ber_bvchr_pre( &cbv, &tmp, ' ' );
2433                                 if ( cbv.bv_len == tmp.bv_len )         /* control w/o value */
2434                                         ber_bvchr_pre( &cbv, &tmp, '}' );
2435                                 if ( !ber_bvcmp( &cbv, &rel_ctrl_bv ) )
2436                                         op->o_relax = SLAP_CONTROL_CRITICAL;
2437                         }
2438                 } else if ( !ber_bvstrcasecmp( &bv,
2439                         &slap_schema.si_ad_entryCSN->ad_cname ) )
2440                 {
2441                         slap_queue_csn( op, bvals );
2442                         do_graduate = 1;
2443                 }
2444                 ch_free( bvals );
2445         }
2446
2447         /* If we didn't get a mod type or a target DN, bail out */
2448         if ( op->o_tag == LBER_DEFAULT || BER_BVISNULL( &dn ) ) {
2449                 rc = -1;
2450                 goto done;
2451         }
2452
2453         op->o_callback = &cb;
2454         slap_op_time( &op->o_time, &op->o_tincr );
2455
2456         Debug( LDAP_DEBUG_SYNC, "syncrepl_message_to_op: %s tid %x\n",
2457                 si->si_ridtxt, op->o_tid, 0 );
2458
2459         switch( op->o_tag ) {
2460         case LDAP_REQ_ADD:
2461         case LDAP_REQ_MODIFY:
2462                 /* If we didn't get required data, bail */
2463                 if ( !modlist ) goto done;
2464
2465                 rc = slap_mods_check( op, modlist, &text, txtbuf, textlen, NULL );
2466
2467                 if ( rc != LDAP_SUCCESS ) {
2468                         Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
2469                                 "mods check (%s)\n",
2470                                 si->si_ridtxt, text, 0 );
2471                         goto done;
2472                 }
2473
2474                 if ( op->o_tag == LDAP_REQ_ADD ) {
2475                         Entry *e = entry_alloc();
2476                         op->ora_e = e;
2477                         op->ora_e->e_name = op->o_req_dn;
2478                         op->ora_e->e_nname = op->o_req_ndn;
2479                         freeReqDn = 0;
2480                         rc = slap_mods2entry( modlist, &op->ora_e, 1, 0, &text, txtbuf, textlen);
2481                         if( rc != LDAP_SUCCESS ) {
2482                                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
2483                                 "mods2entry (%s)\n",
2484                                         si->si_ridtxt, text, 0 );
2485                         } else {
2486                                 rc = op->o_bd->be_add( op, &rs );
2487                                 Debug( LDAP_DEBUG_SYNC,
2488                                         "syncrepl_message_to_op: %s be_add %s (%d)\n", 
2489                                         si->si_ridtxt, op->o_req_dn.bv_val, rc );
2490                                 do_graduate = 0;
2491                         }
2492                         if ( e == op->ora_e )
2493                                 be_entry_release_w( op, op->ora_e );
2494                 } else {
2495                         OpExtraSync oes;
2496                         op->orm_modlist = modlist;
2497                         op->o_bd = si->si_wbe;
2498                         /* delta-mmr needs additional checks in syncrepl_op_modify */
2499                         if ( SLAP_MULTIMASTER( op->o_bd )) {
2500                                 oes.oe.oe_key = (void *)syncrepl_message_to_op;
2501                                 oes.oe_si = si;
2502                                 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &oes.oe, oe_next );
2503                         }
2504                         rc = op->o_bd->be_modify( op, &rs );
2505                         if ( SLAP_MULTIMASTER( op->o_bd )) {
2506                                 LDAP_SLIST_REMOVE( &op->o_extra, &oes.oe, OpExtra, oe_next );
2507                                 BER_BVZERO( &op->o_csn );
2508                         }
2509                         modlist = op->orm_modlist;
2510                         Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
2511                                 "syncrepl_message_to_op: %s be_modify %s (%d)\n", 
2512                                 si->si_ridtxt, op->o_req_dn.bv_val, rc );
2513                         op->o_bd = si->si_be;
2514                         do_graduate = 0;
2515                 }
2516                 break;
2517         case LDAP_REQ_MODRDN:
2518                 if ( BER_BVISNULL( &rdn ) ) goto done;
2519
2520                 if ( rdnPretty( NULL, &rdn, &prdn, NULL ) ) {
2521                         goto done;
2522                 }
2523                 if ( rdnNormalize( 0, NULL, NULL, &rdn, &nrdn, NULL ) ) {
2524                         goto done;
2525                 }
2526                 if ( !BER_BVISNULL( &sup ) ) {
2527                         REWRITE_DN( si, sup, bv2, psup, nsup );
2528                         if ( rc )
2529                                 goto done;
2530                         op->orr_newSup = &psup;
2531                         op->orr_nnewSup = &nsup;
2532                 } else {
2533                         op->orr_newSup = NULL;
2534                         op->orr_nnewSup = NULL;
2535                 }
2536                 op->orr_newrdn = prdn;
2537                 op->orr_nnewrdn = nrdn;
2538                 op->orr_deleteoldrdn = deleteOldRdn;
2539                 op->orr_modlist = NULL;
2540                 if ( slap_modrdn2mods( op, &rs ) ) {
2541                         goto done;
2542                 }
2543
2544                 /* Append modlist for operational attrs */
2545                 {
2546                         Modifications *m;
2547
2548                         for ( m = op->orr_modlist; m->sml_next; m = m->sml_next )
2549                                 ;
2550                         m->sml_next = modlist;
2551                         modlist = NULL;
2552                 }
2553                 rc = op->o_bd->be_modrdn( op, &rs );
2554                 slap_mods_free( op->orr_modlist, 1 );
2555                 Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
2556                         "syncrepl_message_to_op: %s be_modrdn %s (%d)\n", 
2557                         si->si_ridtxt, op->o_req_dn.bv_val, rc );
2558                 do_graduate = 0;
2559                 break;
2560         case LDAP_REQ_DELETE:
2561                 rc = op->o_bd->be_delete( op, &rs );
2562                 Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
2563                         "syncrepl_message_to_op: %s be_delete %s (%d)\n", 
2564                         si->si_ridtxt, op->o_req_dn.bv_val, rc );
2565                 do_graduate = 0;
2566                 break;
2567         }
2568 done:
2569         if ( do_graduate )
2570                 slap_graduate_commit_csn( op );
2571         op->o_bd = si->si_be;
2572         op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
2573         BER_BVZERO( &op->o_csn );
2574         if ( modlist ) {
2575                 slap_mods_free( modlist, op->o_tag != LDAP_REQ_ADD );
2576         }
2577         if ( !BER_BVISNULL( &rdn ) ) {
2578                 if ( !BER_BVISNULL( &nsup ) ) {
2579                         ch_free( nsup.bv_val );
2580                 }
2581                 if ( !BER_BVISNULL( &psup ) ) {
2582                         ch_free( psup.bv_val );
2583                 }
2584                 if ( !BER_BVISNULL( &nrdn ) ) {
2585                         ch_free( nrdn.bv_val );
2586                 }
2587                 if ( !BER_BVISNULL( &prdn ) ) {
2588                         ch_free( prdn.bv_val );
2589                 }
2590         }
2591         if ( freeReqDn ) {
2592                 ch_free( op->o_req_ndn.bv_val );
2593                 ch_free( op->o_req_dn.bv_val );
2594         }
2595         ber_free( ber, 0 );
2596         return rc;
2597 }
2598
2599 static int
2600 syncrepl_message_to_entry(
2601         syncinfo_t      *si,
2602         Operation       *op,
2603         LDAPMessage     *msg,
2604         Modifications   **modlist,
2605         Entry                   **entry,
2606         int             syncstate,
2607         struct berval   *syncUUID
2608 )
2609 {
2610         Entry           *e = NULL;
2611         BerElement      *ber = NULL;
2612         Modifications   tmp;
2613         Modifications   *mod;
2614         Modifications   **modtail = modlist;
2615
2616         const char      *text;
2617         char txtbuf[SLAP_TEXT_BUFLEN];
2618         size_t textlen = sizeof txtbuf;
2619
2620         struct berval   bdn = BER_BVNULL, dn, ndn, bv2;
2621         int             rc, is_ctx;
2622
2623         *modlist = NULL;
2624
2625         if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
2626                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s "
2627                         "Message type should be entry (%d)",
2628                         si->si_ridtxt, ldap_msgtype( msg ), 0 );
2629                 return -1;
2630         }
2631
2632         op->o_tag = LDAP_REQ_ADD;
2633
2634         rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
2635         if ( rc != LDAP_SUCCESS ) {
2636                 Debug( LDAP_DEBUG_ANY,
2637                         "syncrepl_message_to_entry: %s dn get failed (%d)",
2638                         si->si_ridtxt, rc, 0 );
2639                 return rc;
2640         }
2641
2642         if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) {
2643                 Debug( LDAP_DEBUG_ANY,
2644                         "syncrepl_message_to_entry: %s got empty dn",
2645                         si->si_ridtxt, 0, 0 );
2646                 return LDAP_OTHER;
2647         }
2648
2649         /* syncUUID[0] is normalized UUID received over the wire
2650          * syncUUID[1] is denormalized UUID, generated here
2651          */
2652         (void)slap_uuidstr_from_normalized( &syncUUID[1], &syncUUID[0], op->o_tmpmemctx );
2653         Debug( LDAP_DEBUG_SYNC,
2654                 "syncrepl_message_to_entry: %s DN: %s, UUID: %s\n",
2655                 si->si_ridtxt, bdn.bv_val, syncUUID[1].bv_val );
2656
2657         if ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_DELETE ) {
2658                 /* NOTE: this could be done even before decoding the DN,
2659                  * although encoding errors wouldn't be detected */
2660                 rc = LDAP_SUCCESS;
2661                 goto done;
2662         }
2663
2664         if ( entry == NULL ) {
2665                 return -1;
2666         }
2667
2668         REWRITE_DN( si, bdn, bv2, dn, ndn );
2669         if ( rc != LDAP_SUCCESS ) {
2670                 /* One of the things that could happen is that the schema
2671                  * is not lined-up; this could result in unknown attributes.
2672                  * A value non conformant to the syntax should be unlikely,
2673                  * except when replicating between different versions
2674                  * of the software, or when syntax validation bugs are fixed
2675                  */
2676                 Debug( LDAP_DEBUG_ANY,
2677                         "syncrepl_message_to_entry: "
2678                         "%s dn \"%s\" normalization failed (%d)",
2679                         si->si_ridtxt, bdn.bv_val, rc );
2680                 return rc;
2681         }
2682
2683         ber_dupbv( &op->o_req_dn, &dn );
2684         ber_dupbv( &op->o_req_ndn, &ndn );
2685         slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
2686         slap_sl_free( dn.bv_val, op->o_tmpmemctx );
2687
2688         is_ctx = dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[0] );
2689
2690         e = entry_alloc();
2691         e->e_name = op->o_req_dn;
2692         e->e_nname = op->o_req_ndn;
2693
2694         while ( ber_remaining( ber ) ) {
2695                 if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) ==
2696                         LBER_ERROR ) || BER_BVISNULL( &tmp.sml_type ) )
2697                 {
2698                         break;
2699                 }
2700
2701                 /* Drop all updates to the contextCSN of the context entry
2702                  * (ITS#4622, etc.)
2703                  */
2704                 if ( is_ctx && !strcasecmp( tmp.sml_type.bv_val,
2705                         slap_schema.si_ad_contextCSN->ad_cname.bv_val )) {
2706                         ber_bvarray_free( tmp.sml_values );
2707                         continue;
2708                 }
2709
2710                 mod  = (Modifications *) ch_malloc( sizeof( Modifications ) );
2711
2712                 mod->sml_op = LDAP_MOD_REPLACE;
2713                 mod->sml_flags = 0;
2714                 mod->sml_next = NULL;
2715                 mod->sml_desc = NULL;
2716                 mod->sml_type = tmp.sml_type;
2717                 mod->sml_values = tmp.sml_values;
2718                 mod->sml_nvalues = NULL;
2719                 mod->sml_numvals = 0;   /* slap_mods_check will set this */
2720
2721 #ifdef ENABLE_REWRITE
2722                 if (si->si_rewrite) {
2723                         AttributeDescription *ad = NULL;
2724                         slap_bv2ad( &tmp.sml_type, &ad, &text );
2725                         if ( ad ) {
2726                                 mod->sml_desc = ad;
2727                                 mod->sml_type = ad->ad_cname;
2728                                 if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) {
2729                                         int i;
2730                                         for ( i = 0; tmp.sml_values[i].bv_val; i++ ) {
2731                                                 syncrepl_rewrite_dn( si, &tmp.sml_values[i], &bv2);
2732                                                 if ( !BER_BVISNULL( &bv2 )) {
2733                                                         ber_memfree( tmp.sml_values[i].bv_val );
2734                                                         tmp.sml_values[i] = bv2;
2735                                                 }
2736                                         }
2737                                 }
2738                         }
2739                 }
2740 #endif
2741                 *modtail = mod;
2742                 modtail = &mod->sml_next;
2743         }
2744
2745         if ( *modlist == NULL ) {
2746                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s no attributes\n",
2747                         si->si_ridtxt, 0, 0 );
2748                 rc = -1;
2749                 goto done;
2750         }
2751
2752         rc = slap_mods_check( op, *modlist, &text, txtbuf, textlen, NULL );
2753
2754         if ( rc != LDAP_SUCCESS ) {
2755                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s mods check (%s)\n",
2756                         si->si_ridtxt, text, 0 );
2757                 goto done;
2758         }
2759
2760         /* Strip out dynamically generated attrs */
2761         for ( modtail = modlist; *modtail ; ) {
2762                 mod = *modtail;
2763                 if ( mod->sml_desc->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
2764                         *modtail = mod->sml_next;
2765                         slap_mod_free( &mod->sml_mod, 0 );
2766                         ch_free( mod );
2767                 } else {
2768                         modtail = &mod->sml_next;
2769                 }
2770         }
2771
2772         /* Strip out attrs in exattrs list */
2773         for ( modtail = modlist; *modtail ; ) {
2774                 mod = *modtail;
2775                 if ( ldap_charray_inlist( si->si_exattrs,
2776                         mod->sml_desc->ad_type->sat_cname.bv_val ) )
2777                 {
2778                         *modtail = mod->sml_next;
2779                         slap_mod_free( &mod->sml_mod, 0 );
2780                         ch_free( mod );
2781                 } else {
2782                         modtail = &mod->sml_next;
2783                 }
2784         }
2785
2786         rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
2787         if( rc != LDAP_SUCCESS ) {
2788                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s mods2entry (%s)\n",
2789                         si->si_ridtxt, text, 0 );
2790         }
2791
2792 done:
2793         ber_free( ber, 0 );
2794         if ( rc != LDAP_SUCCESS ) {
2795                 if ( e ) {
2796                         entry_free( e );
2797                         e = NULL;
2798                 }
2799         }
2800         if ( entry )
2801                 *entry = e;
2802
2803         return rc;
2804 }
2805
2806 static struct berval generic_filterstr = BER_BVC("(objectclass=*)");
2807
2808 /* During a refresh, we may get an LDAP_SYNC_ADD for an already existing
2809  * entry if a previous refresh was interrupted before sending us a new
2810  * context state. We try to compare the new entry to the existing entry
2811  * and ignore the new entry if they are the same.
2812  *
2813  * Also, we may get an update where the entryDN has changed, due to
2814  * a ModDn on the provider. We detect this as well, so we can issue
2815  * the corresponding operation locally.
2816  *
2817  * In the case of a modify, we get a list of all the attributes
2818  * in the original entry. Rather than deleting the entry and re-adding it,
2819  * we issue a Modify request that deletes all the attributes and adds all
2820  * the new ones. This avoids the issue of trying to delete/add a non-leaf
2821  * entry.
2822  *
2823  * We otherwise distinguish ModDN from Modify; in the case of
2824  * a ModDN we just use the CSN, modifyTimestamp and modifiersName
2825  * operational attributes from the entry, and do a regular ModDN.
2826  */
2827 typedef struct dninfo {
2828         Entry *new_entry;
2829         struct berval dn;
2830         struct berval ndn;
2831         struct berval nnewSup;
2832         int renamed;    /* Was an existing entry renamed? */
2833         int delOldRDN;  /* Was old RDN deleted? */
2834         Modifications **modlist;        /* the modlist we received */
2835         Modifications *mods;    /* the modlist we compared */
2836         int oldNcount;          /* #values of old naming attr */
2837         AttributeDescription *oldDesc;  /* for renames */
2838         AttributeDescription *newDesc;  /* for renames */
2839 } dninfo;
2840
2841 #define HASHUUID        1
2842
2843 /* return 1 if inserted, 0 otherwise */
2844 static int
2845 presentlist_insert(
2846         syncinfo_t* si,
2847         struct berval *syncUUID )
2848 {
2849         char *val;
2850
2851 #ifdef HASHUUID
2852         Avlnode **av;
2853         unsigned short s;
2854
2855         if ( !si->si_presentlist )
2856                 si->si_presentlist = ch_calloc(65536, sizeof( Avlnode * ));
2857
2858         av = (Avlnode **)si->si_presentlist;
2859
2860         val = ch_malloc(UUIDLEN-2);
2861         memcpy(&s, syncUUID->bv_val, 2);
2862         memcpy(val, syncUUID->bv_val+2, UUIDLEN-2);
2863
2864         if ( avl_insert( &av[s], val,
2865                 syncuuid_cmp, avl_dup_error ) )
2866         {
2867                 ch_free( val );
2868                 return 0;
2869         }
2870 #else
2871         val = ch_malloc(UUIDLEN);
2872
2873         AC_MEMCPY( val, syncUUID->bv_val, UUIDLEN );
2874
2875         if ( avl_insert( &si->si_presentlist, val,
2876                 syncuuid_cmp, avl_dup_error ) )
2877         {
2878                 ch_free( val );
2879                 return 0;
2880         }
2881 #endif
2882
2883         return 1;
2884 }
2885
2886 static char *
2887 presentlist_find(
2888         Avlnode *av,
2889         struct berval *val )
2890 {
2891 #ifdef HASHUUID
2892         Avlnode **a2 = (Avlnode **)av;
2893         unsigned short s;
2894
2895         if (!av)
2896                 return NULL;
2897
2898         memcpy(&s, val->bv_val, 2);
2899         return avl_find( a2[s], val->bv_val+2, syncuuid_cmp );
2900 #else
2901         return avl_find( av, val->bv_val, syncuuid_cmp );
2902 #endif
2903 }
2904
2905 static int
2906 presentlist_free( Avlnode *av )
2907 {
2908 #ifdef HASHUUID
2909         Avlnode **a2 = (Avlnode **)av;
2910         int i, count = 0;
2911
2912         if ( av ) {
2913                 for (i=0; i<65536; i++) {
2914                         if (a2[i])
2915                                 count += avl_free( a2[i], ch_free );
2916                 }
2917                 ch_free( av );
2918         }
2919         return count;
2920 #else
2921         return avl_free( av, ch_free );
2922 #endif
2923 }
2924
2925 static void
2926 presentlist_delete(
2927         Avlnode **av,
2928         struct berval *val )
2929 {
2930 #ifdef HASHUUID
2931         Avlnode **a2 = *(Avlnode ***)av;
2932         unsigned short s;
2933
2934         memcpy(&s, val->bv_val, 2);
2935         avl_delete( &a2[s], val->bv_val+2, syncuuid_cmp );
2936 #else
2937         avl_delete( av, val->bv_val, syncuuid_cmp );
2938 #endif
2939 }
2940
2941 static int
2942 syncrepl_entry(
2943         syncinfo_t* si,
2944         Operation *op,
2945         Entry* entry,
2946         Modifications** modlist,
2947         int syncstate,
2948         struct berval* syncUUID,
2949         struct berval* syncCSN )
2950 {
2951         Backend *be = op->o_bd;
2952         slap_callback   cb = { NULL, NULL, NULL, NULL };
2953         int syncuuid_inserted = 0;
2954
2955         SlapReply       rs_search = {REP_RESULT};
2956         Filter f = {0};
2957         AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
2958         int rc = LDAP_SUCCESS;
2959
2960         struct berval pdn = BER_BVNULL;
2961         dninfo dni = {0};
2962         int     retry = 1;
2963         int     freecsn = 1;
2964
2965         Debug( LDAP_DEBUG_SYNC,
2966                 "syncrepl_entry: %s LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_%s) tid %x\n",
2967                 si->si_ridtxt, syncrepl_state2str( syncstate ), op->o_tid );
2968
2969         if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ) ) {
2970                 if ( !si->si_refreshPresent && !si->si_refreshDone ) {
2971                         syncuuid_inserted = presentlist_insert( si, syncUUID );
2972                 }
2973         }
2974
2975         if ( syncstate == LDAP_SYNC_PRESENT ) {
2976                 return 0;
2977         } else if ( syncstate != LDAP_SYNC_DELETE ) {
2978                 if ( entry == NULL ) {
2979                         return 0;
2980                 }
2981         }
2982
2983         if ( syncstate != LDAP_SYNC_DELETE ) {
2984                 Attribute       *a = attr_find( entry->e_attrs, slap_schema.si_ad_entryUUID );
2985
2986                 if ( a == NULL ) {
2987                         /* add if missing */
2988                         attr_merge_one( entry, slap_schema.si_ad_entryUUID,
2989                                 &syncUUID[1], syncUUID );
2990
2991                 } else if ( !bvmatch( &a->a_nvals[0], syncUUID ) ) {
2992                         /* replace only if necessary */
2993                         if ( a->a_nvals != a->a_vals ) {
2994                                 ber_memfree( a->a_nvals[0].bv_val );
2995                                 ber_dupbv( &a->a_nvals[0], syncUUID );
2996                         }
2997                         ber_memfree( a->a_vals[0].bv_val );
2998                         ber_dupbv( &a->a_vals[0], &syncUUID[1] );
2999                 }
3000         }
3001
3002         f.f_choice = LDAP_FILTER_EQUALITY;
3003         f.f_ava = &ava;
3004         ava.aa_desc = slap_schema.si_ad_entryUUID;
3005         ava.aa_value = *syncUUID;
3006
3007         if ( syncuuid_inserted ) {
3008                 Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s inserted UUID %s\n",
3009                         si->si_ridtxt, syncUUID[1].bv_val, 0 );
3010         }
3011         op->ors_filter = &f;
3012
3013         op->ors_filterstr.bv_len = STRLENOF( "(entryUUID=)" ) + syncUUID[1].bv_len;
3014         op->ors_filterstr.bv_val = (char *) slap_sl_malloc(
3015                 op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); 
3016         AC_MEMCPY( op->ors_filterstr.bv_val, "(entryUUID=", STRLENOF( "(entryUUID=" ) );
3017         AC_MEMCPY( &op->ors_filterstr.bv_val[STRLENOF( "(entryUUID=" )],
3018                 syncUUID[1].bv_val, syncUUID[1].bv_len );
3019         op->ors_filterstr.bv_val[op->ors_filterstr.bv_len - 1] = ')';
3020         op->ors_filterstr.bv_val[op->ors_filterstr.bv_len] = '\0';
3021
3022         op->o_tag = LDAP_REQ_SEARCH;
3023         op->ors_scope = LDAP_SCOPE_SUBTREE;
3024         op->ors_deref = LDAP_DEREF_NEVER;
3025
3026         /* get the entry for this UUID */
3027 #ifdef ENABLE_REWRITE
3028         if ( si->si_rewrite ) {
3029                 op->o_req_dn = si->si_suffixm;
3030                 op->o_req_ndn = si->si_suffixm;
3031         } else
3032 #endif
3033         {
3034                 op->o_req_dn = si->si_base;
3035                 op->o_req_ndn = si->si_base;
3036         }
3037
3038         op->o_time = slap_get_time();
3039         op->ors_tlimit = SLAP_NO_LIMIT;
3040         op->ors_slimit = 1;
3041         op->ors_limit = NULL;
3042
3043         op->ors_attrs = slap_anlist_all_attributes;
3044         op->ors_attrsonly = 0;
3045
3046         /* set callback function */
3047         op->o_callback = &cb;
3048         cb.sc_response = dn_callback;
3049         cb.sc_private = &dni;
3050         dni.new_entry = entry;
3051         dni.modlist = modlist;
3052
3053         rc = be->be_search( op, &rs_search );
3054         Debug( LDAP_DEBUG_SYNC,
3055                         "syncrepl_entry: %s be_search (%d)\n", 
3056                         si->si_ridtxt, rc, 0 );
3057
3058         if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
3059                 slap_sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
3060         }
3061
3062         cb.sc_response = syncrepl_null_callback;
3063         cb.sc_private = si;
3064
3065         if ( entry && !BER_BVISNULL( &entry->e_name ) ) {
3066                 Debug( LDAP_DEBUG_SYNC,
3067                                 "syncrepl_entry: %s %s\n",
3068                                 si->si_ridtxt, entry->e_name.bv_val, 0 );
3069         } else {
3070                 Debug( LDAP_DEBUG_SYNC,
3071                                 "syncrepl_entry: %s %s\n",
3072                                 si->si_ridtxt, dni.dn.bv_val ? dni.dn.bv_val : "(null)", 0 );
3073         }
3074
3075         assert( BER_BVISNULL( &op->o_csn ) );
3076         if ( syncCSN ) {
3077                 slap_queue_csn( op, syncCSN );
3078         }
3079
3080         if ( !si->si_refreshDone ) {
3081                 if ( si->si_lazyCommit )
3082                         op->o_lazyCommit = SLAP_CONTROL_NONCRITICAL;
3083                 if ( si->si_refreshCount == 500 ) {
3084                         LDAP_SLIST_REMOVE( &op->o_extra, si->si_refreshTxn, OpExtra, oe_next );
3085                         op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_COMMIT, &si->si_refreshTxn );
3086                         si->si_refreshCount = 0;
3087                         si->si_refreshTxn = NULL;
3088                 }
3089                 if ( op->o_bd->bd_info->bi_op_txn ) {
3090                         if ( !si->si_refreshCount ) {
3091                                 op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_BEGIN, &si->si_refreshTxn );
3092                         }
3093                         si->si_refreshCount++;
3094                 }
3095         }
3096
3097         slap_op_time( &op->o_time, &op->o_tincr );
3098         switch ( syncstate ) {
3099         case LDAP_SYNC_ADD:
3100         case LDAP_SYNC_MODIFY:
3101                 if ( BER_BVISNULL( &op->o_csn ))
3102                 {
3103
3104                         Attribute *a = attr_find( entry->e_attrs, slap_schema.si_ad_entryCSN );
3105                         if ( a ) {
3106                                 /* FIXME: op->o_csn is assumed to be
3107                                  * on the thread's slab; this needs
3108                                  * to be cleared ASAP.
3109                                  */
3110                                 op->o_csn = a->a_vals[0];
3111                                 freecsn = 0;
3112                         }
3113                 }
3114 retry_add:;
3115                 if ( BER_BVISNULL( &dni.dn ) ) {
3116                         SlapReply       rs_add = {REP_RESULT};
3117
3118                         op->o_req_dn = entry->e_name;
3119                         op->o_req_ndn = entry->e_nname;
3120                         op->o_tag = LDAP_REQ_ADD;
3121                         op->ora_e = entry;
3122                         op->o_bd = si->si_wbe;
3123
3124                         rc = op->o_bd->be_add( op, &rs_add );
3125                         Debug( LDAP_DEBUG_SYNC,
3126                                         "syncrepl_entry: %s be_add %s (%d)\n", 
3127                                         si->si_ridtxt, op->o_req_dn.bv_val, rc );
3128                         switch ( rs_add.sr_err ) {
3129                         case LDAP_SUCCESS:
3130                                 if ( op->ora_e == entry ) {
3131                                         be_entry_release_w( op, entry );
3132                                 }
3133                                 entry = NULL;
3134                                 break;
3135
3136                         case LDAP_REFERRAL:
3137                         /* we assume that LDAP_NO_SUCH_OBJECT is returned 
3138                          * only if the suffix entry is not present.
3139                          * This should not happen during Persist phase.
3140                          */
3141                         case LDAP_NO_SUCH_OBJECT:
3142                                 if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
3143                                         si->si_refreshDone ) {
3144                                         /* Something's wrong, start over */
3145                                         ber_bvarray_free( si->si_syncCookie.ctxcsn );
3146                                         si->si_syncCookie.ctxcsn = NULL;
3147                                         entry_free( entry );
3148                                         ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
3149                                         ber_bvarray_free( si->si_cookieState->cs_vals );
3150                                         ch_free( si->si_cookieState->cs_sids );
3151                                         si->si_cookieState->cs_vals = NULL;
3152                                         si->si_cookieState->cs_sids = 0;
3153                                         si->si_cookieState->cs_num = 0;
3154                                         ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
3155                                         return LDAP_NO_SUCH_OBJECT;
3156                                 }
3157                                 rc = syncrepl_add_glue( op, entry );
3158                                 entry = NULL;
3159                                 break;
3160
3161                         /* if an entry was added via syncrepl_add_glue(),
3162                          * it likely has no entryUUID, so the previous
3163                          * be_search() doesn't find it.  In this case,
3164                          * give syncrepl a chance to modify it. Also
3165                          * allow for entries that were recreated with the
3166                          * same DN but a different entryUUID.
3167                          */
3168                         case LDAP_ALREADY_EXISTS:
3169                                 if ( retry ) {
3170                                         Operation       op2 = *op;
3171                                         SlapReply       rs2 = { REP_RESULT };
3172                                         slap_callback   cb2 = { 0 };
3173
3174                                         op2.o_bd = be;
3175                                         op2.o_tag = LDAP_REQ_SEARCH;
3176                                         op2.o_req_dn = entry->e_name;
3177                                         op2.o_req_ndn = entry->e_nname;
3178                                         op2.ors_scope = LDAP_SCOPE_BASE;
3179                                         op2.ors_deref = LDAP_DEREF_NEVER;
3180                                         op2.ors_attrs = slap_anlist_all_attributes;
3181                                         op2.ors_attrsonly = 0;
3182                                         op2.ors_limit = NULL;
3183                                         op2.ors_slimit = 1;
3184                                         op2.ors_tlimit = SLAP_NO_LIMIT;
3185
3186                                         f.f_choice = LDAP_FILTER_PRESENT;
3187                                         f.f_desc = slap_schema.si_ad_objectClass;
3188                                         op2.ors_filter = &f;
3189                                         op2.ors_filterstr = generic_filterstr;
3190
3191                                         op2.o_callback = &cb2;
3192                                         cb2.sc_response = dn_callback;
3193                                         cb2.sc_private = &dni;
3194
3195                                         rc = be->be_search( &op2, &rs2 );
3196                                         if ( rc ) goto done;
3197
3198                                         retry = 0;
3199                                         slap_op_time( &op->o_time, &op->o_tincr );
3200                                         goto retry_add;
3201                                 }
3202                                 /* FALLTHRU */
3203
3204                         default:
3205                                 Debug( LDAP_DEBUG_ANY,
3206                                         "syncrepl_entry: %s be_add %s failed (%d)\n",
3207                                         si->si_ridtxt, op->o_req_dn.bv_val, rs_add.sr_err );
3208                                 break;
3209                         }
3210                         syncCSN = NULL;
3211                         op->o_bd = be;
3212                         goto done;
3213                 }
3214                 /* FALLTHRU */
3215                 op->o_req_dn = dni.dn;
3216                 op->o_req_ndn = dni.ndn;
3217                 if ( dni.renamed ) {
3218                         struct berval noldp, newp;
3219                         Modifications *mod, **modtail, **ml, *m2;
3220                         int i, got_replace = 0, just_rename = 0;
3221                         SlapReply rs_modify = {REP_RESULT};
3222
3223                         op->o_tag = LDAP_REQ_MODRDN;
3224                         dnRdn( &entry->e_name, &op->orr_newrdn );
3225                         dnRdn( &entry->e_nname, &op->orr_nnewrdn );
3226
3227                         if ( !BER_BVISNULL( &dni.nnewSup )) {
3228                                 dnParent( &entry->e_name, &newp );
3229                                 op->orr_newSup = &newp;
3230                                 op->orr_nnewSup = &dni.nnewSup;
3231                         } else {
3232                                 op->orr_newSup = NULL;
3233                                 op->orr_nnewSup = NULL;
3234                         }
3235                         op->orr_deleteoldrdn = dni.delOldRDN;
3236                         op->orr_modlist = NULL;
3237                         if ( ( rc = slap_modrdn2mods( op, &rs_modify ) ) ) {
3238                                 goto done;
3239                         }
3240
3241                         /* Drop the RDN-related mods from this op, because their
3242                          * equivalents were just setup by slap_modrdn2mods.
3243                          *
3244                          * If delOldRDN is TRUE then we should see a delete modop
3245                          * for oldDesc. We might see a replace instead.
3246                          *  delete with no values: therefore newDesc != oldDesc.
3247                          *   if oldNcount == 1, then Drop this op.
3248                          *  delete with 1 value: can only be the oldRDN value. Drop op.
3249                          *  delete with N values: Drop oldRDN value, keep remainder.
3250                          *  replace with 1 value: if oldNcount == 1 and
3251                          *     newDesc == oldDesc, Drop this op.
3252                          * Any other cases must be left intact.
3253                          *
3254                          * We should also see an add modop for newDesc. (But not if
3255                          * we got a replace modop due to delOldRDN.) If it has
3256                          * multiple values, we'll have to drop the new RDN value.
3257                          */
3258                         modtail = &op->orr_modlist;
3259                         if ( dni.delOldRDN ) {
3260                                 for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) {
3261                                         if ( (*ml)->sml_desc == dni.oldDesc ) {
3262                                                 mod = *ml;
3263                                                 if ( mod->sml_op == LDAP_MOD_REPLACE &&
3264                                                         dni.oldDesc != dni.newDesc ) {
3265                                                         /* This Replace is due to other Mods.
3266                                                          * Just let it ride.
3267                                                          */
3268                                                         continue;
3269                                                 }
3270                                                 if ( mod->sml_numvals <= 1 &&
3271                                                         dni.oldNcount == 1 &&
3272                                                         ( mod->sml_op == LDAP_MOD_DELETE ||
3273                                                           mod->sml_op == LDAP_MOD_REPLACE )) {
3274                                                         if ( mod->sml_op == LDAP_MOD_REPLACE )
3275                                                                 got_replace = 1;
3276                                                         /* Drop this op */
3277                                                         *ml = mod->sml_next;
3278                                                         mod->sml_next = NULL;
3279                                                         slap_mods_free( mod, 1 );
3280                                                         break;
3281                                                 }
3282                                                 if ( mod->sml_op != LDAP_MOD_DELETE || mod->sml_numvals == 0 )
3283                                                         continue;
3284                                                 for ( m2 = op->orr_modlist; m2; m2=m2->sml_next ) {
3285                                                         if ( m2->sml_desc == dni.oldDesc &&
3286                                                                 m2->sml_op == LDAP_MOD_DELETE ) break;
3287                                                 }
3288                                                 for ( i=0; i<mod->sml_numvals; i++ ) {
3289                                                         if ( bvmatch( &mod->sml_values[i], &m2->sml_values[0] )) {
3290                                                                 mod->sml_numvals--;
3291                                                                 ch_free( mod->sml_values[i].bv_val );
3292                                                                 mod->sml_values[i] = mod->sml_values[mod->sml_numvals];
3293                                                                 BER_BVZERO( &mod->sml_values[mod->sml_numvals] );
3294                                                                 if ( mod->sml_nvalues ) {
3295                                                                         ch_free( mod->sml_nvalues[i].bv_val );
3296                                                                         mod->sml_nvalues[i] = mod->sml_nvalues[mod->sml_numvals];
3297                                                                         BER_BVZERO( &mod->sml_nvalues[mod->sml_numvals] );
3298                                                                 }
3299                                                                 break;
3300                                                         }
3301                                                 }
3302                                                 if ( !mod->sml_numvals ) {
3303                                                         /* Drop this op */
3304                                                         *ml = mod->sml_next;
3305                                                         mod->sml_next = NULL;
3306                                                         slap_mods_free( mod, 1 );
3307                                                 }
3308                                                 break;
3309                                         }
3310                                 }
3311                         }
3312                         if ( !got_replace ) {
3313                                 for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) {
3314                                         if ( (*ml)->sml_desc == dni.newDesc ) {
3315                                                 mod = *ml;
3316                                                 if ( mod->sml_op != LDAP_MOD_ADD )
3317                                                         continue;
3318                                                 if ( mod->sml_numvals == 1 ) {
3319                                                         /* Drop this op */
3320                                                         *ml = mod->sml_next;
3321                                                         mod->sml_next = NULL;
3322                                                         slap_mods_free( mod, 1 );
3323                                                         break;
3324                                                 }
3325                                                 for ( m2 = op->orr_modlist; m2; m2=m2->sml_next ) {
3326                                                         if ( m2->sml_desc == dni.oldDesc &&
3327                                                                 m2->sml_op == SLAP_MOD_SOFTADD ) break;
3328                                                 }
3329                                                 for ( i=0; i<mod->sml_numvals; i++ ) {
3330                                                         if ( bvmatch( &mod->sml_values[i], &m2->sml_values[0] )) {
3331                                                                 mod->sml_numvals--;
3332                                                                 ch_free( mod->sml_values[i].bv_val );
3333                                                                 mod->sml_values[i] = mod->sml_values[mod->sml_numvals];
3334                                                                 BER_BVZERO( &mod->sml_values[mod->sml_numvals] );
3335                                                                 if ( mod->sml_nvalues ) {
3336                                                                         ch_free( mod->sml_nvalues[i].bv_val );
3337                                                                         mod->sml_nvalues[i] = mod->sml_nvalues[mod->sml_numvals];
3338                                                                         BER_BVZERO( &mod->sml_nvalues[mod->sml_numvals] );
3339                                                                 }
3340                                                                 break;
3341                                                         }
3342                                                 }
3343                                                 break;
3344                                         }
3345                                 }
3346                         }
3347
3348                         /* RDNs must be NUL-terminated for back-ldap */
3349                         noldp = op->orr_newrdn;
3350                         ber_dupbv_x( &op->orr_newrdn, &noldp, op->o_tmpmemctx );
3351                         noldp = op->orr_nnewrdn;
3352                         ber_dupbv_x( &op->orr_nnewrdn, &noldp, op->o_tmpmemctx );
3353
3354                         /* Setup opattrs too */
3355                         {
3356                                 static AttributeDescription *nullattr = NULL;
3357                                 static AttributeDescription **const opattrs[] = {
3358                                         &slap_schema.si_ad_entryCSN,
3359                                         &slap_schema.si_ad_modifiersName,
3360                                         &slap_schema.si_ad_modifyTimestamp,
3361                                         &nullattr
3362                                 };
3363                                 AttributeDescription *opattr;
3364                                 int i;
3365
3366                                 modtail = &m2;
3367                                 /* pull mod off incoming modlist */
3368                                 for ( i = 0; (opattr = *opattrs[i]) != NULL; i++ ) {
3369                                         for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next )
3370                                         {
3371                                                 if ( (*ml)->sml_desc == opattr ) {
3372                                                         mod = *ml;
3373                                                         *ml = mod->sml_next;
3374                                                         mod->sml_next = NULL;
3375                                                         *modtail = mod;
3376                                                         modtail = &mod->sml_next;
3377                                                         break;
3378                                                 }
3379                                         }
3380                                 }
3381                                 /* If there are still Modifications left, put the opattrs
3382                                  * back, and let be_modify run. Otherwise, append the opattrs
3383                                  * to the orr_modlist.
3384                                  */
3385                                 if ( dni.mods ) {
3386                                         mod = dni.mods;
3387                                         /* don't set a CSN for the rename op */
3388                                         if ( syncCSN )
3389                                                 slap_graduate_commit_csn( op );
3390                                 } else {
3391                                         mod = op->orr_modlist;
3392                                         just_rename = 1;
3393                                 }
3394                                 for ( ; mod->sml_next; mod=mod->sml_next );
3395                                 mod->sml_next = m2;
3396                         }
3397                         op->o_bd = si->si_wbe;
3398 retry_modrdn:;
3399                         rs_reinit( &rs_modify, REP_RESULT );
3400                         rc = op->o_bd->be_modrdn( op, &rs_modify );
3401
3402                         /* NOTE: noSuchObject should result because the new superior
3403                          * has not been added yet (ITS#6472) */
3404                         if ( rc == LDAP_NO_SUCH_OBJECT && op->orr_nnewSup != NULL ) {
3405                                 Operation op2 = *op;
3406                                 rc = syncrepl_add_glue_ancestors( &op2, entry );
3407                                 if ( rc == LDAP_SUCCESS ) {
3408                                         goto retry_modrdn;
3409                                 }
3410                         }
3411                 
3412                         op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx );
3413                         op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx );
3414
3415                         slap_mods_free( op->orr_modlist, 1 );
3416                         Debug( LDAP_DEBUG_SYNC,
3417                                         "syncrepl_entry: %s be_modrdn %s (%d)\n", 
3418                                         si->si_ridtxt, op->o_req_dn.bv_val, rc );
3419                         op->o_bd = be;
3420                         /* Renamed entries may still have other mods so just fallthru */
3421                         op->o_req_dn = entry->e_name;
3422                         op->o_req_ndn = entry->e_nname;
3423                         /* Use CSN on the modify */
3424                         if ( just_rename )
3425                                 syncCSN = NULL;
3426                         else if ( syncCSN )
3427                                 slap_queue_csn( op, syncCSN );
3428                 }
3429                 if ( dni.mods ) {
3430                         SlapReply rs_modify = {REP_RESULT};
3431
3432                         op->o_tag = LDAP_REQ_MODIFY;
3433                         op->orm_modlist = dni.mods;
3434                         op->orm_no_opattrs = 1;
3435                         op->o_bd = si->si_wbe;
3436
3437                         rc = op->o_bd->be_modify( op, &rs_modify );
3438                         slap_mods_free( op->orm_modlist, 1 );
3439                         op->orm_no_opattrs = 0;
3440                         Debug( LDAP_DEBUG_SYNC,
3441                                         "syncrepl_entry: %s be_modify %s (%d)\n", 
3442                                         si->si_ridtxt, op->o_req_dn.bv_val, rc );
3443                         if ( rs_modify.sr_err != LDAP_SUCCESS ) {
3444                                 Debug( LDAP_DEBUG_ANY,
3445                                         "syncrepl_entry: %s be_modify failed (%d)\n",
3446                                         si->si_ridtxt, rs_modify.sr_err, 0 );
3447                         }
3448                         syncCSN = NULL;
3449                         op->o_bd = be;
3450                 } else if ( !dni.renamed ) {
3451                         Debug( LDAP_DEBUG_SYNC,
3452                                         "syncrepl_entry: %s entry unchanged, ignored (%s)\n", 
3453                                         si->si_ridtxt, op->o_req_dn.bv_val, 0 );
3454                         if ( syncCSN ) {
3455                                 slap_graduate_commit_csn( op );
3456                                 syncCSN = NULL;
3457                         }
3458                 }
3459                 goto done;
3460         case LDAP_SYNC_DELETE :
3461                 if ( !BER_BVISNULL( &dni.dn ) ) {
3462                         SlapReply       rs_delete = {REP_RESULT};
3463                         op->o_req_dn = dni.dn;
3464                         op->o_req_ndn = dni.ndn;
3465                         op->o_tag = LDAP_REQ_DELETE;
3466                         op->o_bd = si->si_wbe;
3467                         if ( !syncCSN ) {
3468                                 slap_queue_csn( op, si->si_syncCookie.ctxcsn );
3469                         }
3470                         rc = op->o_bd->be_delete( op, &rs_delete );
3471                         Debug( LDAP_DEBUG_SYNC,
3472                                         "syncrepl_entry: %s be_delete %s (%d)\n", 
3473                                         si->si_ridtxt, op->o_req_dn.bv_val, rc );
3474                         if ( rc == LDAP_NO_SUCH_OBJECT )
3475                                 rc = LDAP_SUCCESS;
3476
3477                         while ( rs_delete.sr_err == LDAP_SUCCESS
3478                                 && op->o_delete_glue_parent ) {
3479                                 op->o_delete_glue_parent = 0;
3480                                 if ( !be_issuffix( be, &op->o_req_ndn ) ) {
3481                                         slap_callback cb = { NULL };
3482                                         cb.sc_response = syncrepl_null_callback;
3483                                         dnParent( &op->o_req_ndn, &pdn );
3484                                         op->o_req_dn = pdn;
3485                                         op->o_req_ndn = pdn;
3486                                         op->o_callback = &cb;
3487                                         rs_reinit( &rs_delete, REP_RESULT );
3488                                         op->o_bd->be_delete( op, &rs_delete );
3489                                 } else {
3490                                         break;
3491                                 }
3492                         }
3493                         syncCSN = NULL;
3494                         op->o_bd = be;
3495                 }
3496                 goto done;
3497
3498         default :
3499                 Debug( LDAP_DEBUG_ANY,
3500                         "syncrepl_entry: %s unknown syncstate\n", si->si_ridtxt, 0, 0 );
3501                 goto done;
3502         }
3503
3504 done:
3505         slap_sl_free( syncUUID[1].bv_val, op->o_tmpmemctx );
3506         BER_BVZERO( &syncUUID[1] );
3507         if ( !BER_BVISNULL( &dni.ndn ) ) {
3508                 op->o_tmpfree( dni.ndn.bv_val, op->o_tmpmemctx );
3509         }
3510         if ( !BER_BVISNULL( &dni.dn ) ) {
3511                 op->o_tmpfree( dni.dn.bv_val, op->o_tmpmemctx );
3512         }
3513         if ( entry ) {
3514                 entry_free( entry );
3515         }
3516         if ( syncCSN ) {
3517                 slap_graduate_commit_csn( op );
3518         }
3519         if ( !BER_BVISNULL( &op->o_csn ) && freecsn ) {
3520                 op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
3521         }
3522         BER_BVZERO( &op->o_csn );
3523         return rc;
3524 }
3525
3526 static struct berval gcbva[] = {
3527         BER_BVC("top"),
3528         BER_BVC("glue"),
3529         BER_BVNULL
3530 };
3531
3532 #define NP_DELETE_ONE   2
3533
3534 static void
3535 syncrepl_del_nonpresent(
3536         Operation *op,
3537         syncinfo_t *si,
3538         BerVarray uuids,
3539         struct sync_cookie *sc,
3540         int m )
3541 {
3542         Backend* be = op->o_bd;
3543         slap_callback   cb = { NULL };
3544         struct nonpresent_entry *np_list, *np_prev;
3545         int rc;
3546         AttributeName   an[2];
3547
3548         struct berval pdn = BER_BVNULL;
3549         struct berval csn;
3550
3551 #ifdef ENABLE_REWRITE
3552         if ( si->si_rewrite ) {
3553                 op->o_req_dn = si->si_suffixm;
3554                 op->o_req_ndn = si->si_suffixm;
3555         } else
3556 #endif
3557         {
3558                 op->o_req_dn = si->si_base;
3559                 op->o_req_ndn = si->si_base;
3560         }
3561
3562         cb.sc_response = nonpresent_callback;
3563         cb.sc_private = si;
3564
3565         op->o_callback = &cb;
3566         op->o_tag = LDAP_REQ_SEARCH;
3567         op->ors_scope = si->si_scope;
3568         op->ors_deref = LDAP_DEREF_NEVER;
3569         op->o_time = slap_get_time();
3570         op->ors_tlimit = SLAP_NO_LIMIT;
3571
3572
3573         if ( uuids ) {
3574                 Filter uf;
3575                 AttributeAssertion eq = ATTRIBUTEASSERTION_INIT;
3576                 int i;
3577
3578                 op->ors_attrsonly = 1;
3579                 op->ors_attrs = slap_anlist_no_attrs;
3580                 op->ors_limit = NULL;
3581                 op->ors_filter = &uf;
3582
3583                 uf.f_ava = &eq;
3584                 uf.f_av_desc = slap_schema.si_ad_entryUUID;
3585                 uf.f_next = NULL;
3586                 uf.f_choice = LDAP_FILTER_EQUALITY;
3587                 si->si_refreshDelete |= NP_DELETE_ONE;
3588
3589                 for (i=0; uuids[i].bv_val; i++) {
3590                         SlapReply rs_search = {REP_RESULT};
3591
3592                         op->ors_slimit = 1;
3593                         uf.f_av_value = uuids[i];
3594                         filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
3595                         rc = be->be_search( op, &rs_search );
3596                         op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
3597                 }
3598                 si->si_refreshDelete ^= NP_DELETE_ONE;
3599         } else {
3600                 Filter *cf, *of;
3601                 Filter mmf[2];
3602                 AttributeAssertion mmaa;
3603                 SlapReply rs_search = {REP_RESULT};
3604
3605                 memset( &an[0], 0, 2 * sizeof( AttributeName ) );
3606                 an[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
3607                 an[0].an_desc = slap_schema.si_ad_entryUUID;
3608                 op->ors_attrs = an;
3609                 op->ors_slimit = SLAP_NO_LIMIT;
3610                 op->ors_tlimit = SLAP_NO_LIMIT;
3611                 op->ors_limit = NULL;
3612                 op->ors_attrsonly = 0;
3613                 op->ors_filter = filter_dup( si->si_filter, op->o_tmpmemctx );
3614                 /* In multimaster, updates can continue to arrive while
3615                  * we're searching. Limit the search result to entries
3616                  * older than our newest cookie CSN.
3617                  */
3618                 if ( SLAP_MULTIMASTER( op->o_bd )) {
3619                         Filter *f;
3620                         int i;
3621
3622                         f = mmf;
3623                         f->f_choice = LDAP_FILTER_AND;
3624                         f->f_next = op->ors_filter;
3625                         f->f_and = f+1;
3626                         of = f->f_and;
3627                         f = of;
3628                         f->f_choice = LDAP_FILTER_LE;
3629                         f->f_ava = &mmaa;
3630                         f->f_av_desc = slap_schema.si_ad_entryCSN;
3631                         f->f_next = NULL;
3632                         BER_BVZERO( &f->f_av_value );
3633                         for ( i=0; i<sc->numcsns; i++ ) {
3634                                 if ( ber_bvcmp( &sc->ctxcsn[i], &f->f_av_value ) > 0 )
3635                                         f->f_av_value = sc->ctxcsn[i];
3636                         }
3637                         of = op->ors_filter;
3638                         op->ors_filter = mmf;
3639                         filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
3640                 } else {
3641                         cf = NULL;
3642                         op->ors_filterstr = si->si_filterstr;
3643                 }
3644                 op->o_nocaching = 1;
3645
3646
3647                 rc = be->be_search( op, &rs_search );
3648                 if ( SLAP_MULTIMASTER( op->o_bd )) {
3649                         op->ors_filter = of;
3650                 }
3651                 if ( op->ors_filter ) filter_free_x( op, op->ors_filter, 1 );
3652                 if ( op->ors_filterstr.bv_val != si->si_filterstr.bv_val ) {
3653                         op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
3654                 }
3655
3656         }
3657
3658         op->o_nocaching = 0;
3659
3660         if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
3661
3662                 if ( sc->ctxcsn && !BER_BVISNULL( &sc->ctxcsn[m] ) ) {
3663                         csn = sc->ctxcsn[m];
3664                 } else {
3665                         csn = si->si_syncCookie.ctxcsn[0];
3666                 }
3667
3668                 op->o_bd = si->si_wbe;
3669                 slap_queue_csn( op, &csn );
3670
3671                 np_list = LDAP_LIST_FIRST( &si->si_nonpresentlist );
3672                 while ( np_list != NULL ) {
3673                         SlapReply rs_delete = {REP_RESULT};
3674
3675                         LDAP_LIST_REMOVE( np_list, npe_link );
3676                         np_prev = np_list;
3677                         np_list = LDAP_LIST_NEXT( np_list, npe_link );
3678                         op->o_tag = LDAP_REQ_DELETE;
3679                         op->o_callback = &cb;
3680                         cb.sc_response = syncrepl_null_callback;
3681                         cb.sc_private = si;
3682                         op->o_req_dn = *np_prev->npe_name;
3683                         op->o_req_ndn = *np_prev->npe_nname;
3684                         rc = op->o_bd->be_delete( op, &rs_delete );
3685                         Debug( LDAP_DEBUG_SYNC,
3686                                 "syncrepl_del_nonpresent: %s be_delete %s (%d)\n", 
3687                                 si->si_ridtxt, op->o_req_dn.bv_val, rc );
3688
3689                         if ( rs_delete.sr_err == LDAP_NOT_ALLOWED_ON_NONLEAF ) {
3690                                 SlapReply rs_modify = {REP_RESULT};
3691                                 Modifications mod1, mod2;
3692                                 mod1.sml_op = LDAP_MOD_REPLACE;
3693                                 mod1.sml_flags = 0;
3694                                 mod1.sml_desc = slap_schema.si_ad_objectClass;
3695                                 mod1.sml_type = mod1.sml_desc->ad_cname;
3696                                 mod1.sml_numvals = 2;
3697                                 mod1.sml_values = &gcbva[0];
3698                                 mod1.sml_nvalues = NULL;
3699                                 mod1.sml_next = &mod2;
3700
3701                                 mod2.sml_op = LDAP_MOD_REPLACE;
3702                                 mod2.sml_flags = 0;
3703                                 mod2.sml_desc = slap_schema.si_ad_structuralObjectClass;
3704                                 mod2.sml_type = mod2.sml_desc->ad_cname;
3705                                 mod2.sml_numvals = 1;
3706                                 mod2.sml_values = &gcbva[1];
3707                                 mod2.sml_nvalues = NULL;
3708                                 mod2.sml_next = NULL;
3709
3710                                 op->o_tag = LDAP_REQ_MODIFY;
3711                                 op->orm_modlist = &mod1;
3712
3713                                 rc = op->o_bd->be_modify( op, &rs_modify );
3714                                 if ( mod2.sml_next ) slap_mods_free( mod2.sml_next, 1 );
3715                         }
3716
3717                         while ( rs_delete.sr_err == LDAP_SUCCESS &&
3718                                         op->o_delete_glue_parent ) {
3719                                 op->o_delete_glue_parent = 0;
3720                                 if ( !be_issuffix( be, &op->o_req_ndn ) ) {
3721                                         slap_callback cb = { NULL };
3722                                         cb.sc_response = syncrepl_null_callback;
3723                                         dnParent( &op->o_req_ndn, &pdn );
3724                                         op->o_req_dn = pdn;
3725                                         op->o_req_ndn = pdn;
3726                                         op->o_callback = &cb;
3727                                         rs_reinit( &rs_delete, REP_RESULT );
3728                                         /* give it a root privil ? */
3729                                         op->o_bd->be_delete( op, &rs_delete );
3730                                 } else {
3731                                         break;
3732                                 }
3733                         }
3734
3735                         op->o_delete_glue_parent = 0;
3736
3737                         ber_bvfree( np_prev->npe_name );
3738                         ber_bvfree( np_prev->npe_nname );
3739                         ch_free( np_prev );
3740
3741                         if ( slapd_shutdown ) {
3742                                 break;
3743                         }
3744                 }
3745
3746                 slap_graduate_commit_csn( op );
3747                 op->o_bd = be;
3748
3749                 op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
3750                 BER_BVZERO( &op->o_csn );
3751         }
3752
3753         return;
3754 }
3755
3756 static int
3757 syncrepl_add_glue_ancestors(
3758         Operation* op,
3759         Entry *e )
3760 {
3761         Backend *be = op->o_bd;
3762         slap_callback cb = { NULL };
3763         Attribute       *a;
3764         int     rc = LDAP_SUCCESS;
3765         int suffrdns;
3766         int i;
3767         struct berval dn = BER_BVNULL;
3768         struct berval ndn = BER_BVNULL;
3769         Entry   *glue;
3770         struct berval   ptr, nptr;
3771         char            *comma;
3772
3773         op->o_tag = LDAP_REQ_ADD;
3774         op->o_callback = &cb;
3775         cb.sc_response = syncrepl_null_callback;
3776         cb.sc_private = NULL;
3777
3778         dn = e->e_name;
3779         ndn = e->e_nname;
3780
3781         /* count RDNs in suffix */
3782         if ( !BER_BVISEMPTY( &be->be_nsuffix[0] ) ) {
3783                 for ( i = 0, ptr = be->be_nsuffix[0], comma = ptr.bv_val; comma != NULL; comma = ber_bvchr( &ptr, ',' ) ) {
3784                         comma++;
3785                         ptr.bv_len -= comma - ptr.bv_val;
3786                         ptr.bv_val = comma;
3787                         i++;
3788                 }
3789                 suffrdns = i;
3790         } else {
3791                 /* suffix is "" */
3792                 suffrdns = 0;
3793         }
3794
3795         /* Start with BE suffix */
3796         ptr = dn;
3797         for ( i = 0; i < suffrdns; i++ ) {
3798                 comma = ber_bvrchr( &ptr, ',' );
3799                 if ( comma != NULL ) {
3800                         ptr.bv_len = comma - ptr.bv_val;
3801                 } else {
3802                         ptr.bv_len = 0;
3803                         break;
3804                 }
3805         }
3806         
3807         if ( !BER_BVISEMPTY( &ptr ) ) {
3808                 dn.bv_len -= ptr.bv_len + ( suffrdns != 0 );
3809                 dn.bv_val += ptr.bv_len + ( suffrdns != 0 );
3810         }
3811
3812         /* the normalizedDNs are always the same length, no counting
3813          * required.
3814          */
3815         nptr = ndn;
3816         if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) {
3817                 ndn.bv_val += ndn.bv_len - be->be_nsuffix[0].bv_len;
3818                 ndn.bv_len = be->be_nsuffix[0].bv_len;
3819
3820                 nptr.bv_len = ndn.bv_val - nptr.bv_val - 1;
3821
3822         } else {
3823                 nptr.bv_len = 0;
3824         }
3825
3826         while ( ndn.bv_val > e->e_nname.bv_val ) {
3827                 SlapReply       rs_add = {REP_RESULT};
3828
3829                 glue = entry_alloc();
3830                 ber_dupbv( &glue->e_name, &dn );
3831                 ber_dupbv( &glue->e_nname, &ndn );
3832
3833                 a = attr_alloc( slap_schema.si_ad_objectClass );
3834
3835                 a->a_numvals = 2;
3836                 a->a_vals = ch_calloc( 3, sizeof( struct berval ) );
3837                 ber_dupbv( &a->a_vals[0], &gcbva[0] );
3838                 ber_dupbv( &a->a_vals[1], &gcbva[1] );
3839                 ber_dupbv( &a->a_vals[2], &gcbva[2] );
3840
3841                 a->a_nvals = a->a_vals;
3842
3843                 a->a_next = glue->e_attrs;
3844                 glue->e_attrs = a;
3845
3846                 a = attr_alloc( slap_schema.si_ad_structuralObjectClass );
3847
3848                 a->a_numvals = 1;
3849                 a->a_vals = ch_calloc( 2, sizeof( struct berval ) );
3850                 ber_dupbv( &a->a_vals[0], &gcbva[1] );
3851                 ber_dupbv( &a->a_vals[1], &gcbva[2] );
3852
3853                 a->a_nvals = a->a_vals;
3854
3855                 a->a_next = glue->e_attrs;
3856                 glue->e_attrs = a;
3857
3858                 op->o_req_dn = glue->e_name;
3859                 op->o_req_ndn = glue->e_nname;
3860                 op->ora_e = glue;
3861                 rc = be->be_add ( op, &rs_add );
3862                 if ( rs_add.sr_err == LDAP_SUCCESS ) {
3863                         if ( op->ora_e == glue )
3864                                 be_entry_release_w( op, glue );
3865                 } else {
3866                 /* incl. ALREADY EXIST */
3867                         entry_free( glue );
3868                         if ( rs_add.sr_err != LDAP_ALREADY_EXISTS ) {
3869                                 entry_free( e );
3870                                 return rc;
3871                         }
3872                 }
3873
3874                 /* Move to next child */
3875                 comma = ber_bvrchr( &ptr, ',' );
3876                 if ( comma == NULL ) {
3877                         break;
3878                 }
3879                 ptr.bv_len = comma - ptr.bv_val;
3880                 
3881                 dn.bv_val = ++comma;
3882                 dn.bv_len = e->e_name.bv_len - (dn.bv_val - e->e_name.bv_val);
3883
3884                 comma = ber_bvrchr( &nptr, ',' );
3885                 assert( comma != NULL );
3886                 nptr.bv_len = comma - nptr.bv_val;
3887
3888                 ndn.bv_val = ++comma;
3889                 ndn.bv_len = e->e_nname.bv_len - (ndn.bv_val - e->e_nname.bv_val);
3890         }
3891
3892         return rc;
3893 }
3894
3895 int
3896 syncrepl_add_glue(
3897         Operation* op,
3898         Entry *e )
3899 {
3900         slap_callback cb = { NULL };
3901         int     rc;
3902         Backend *be = op->o_bd;
3903         SlapReply       rs_add = {REP_RESULT};
3904
3905         rc = syncrepl_add_glue_ancestors( op, e );
3906         switch ( rc ) {
3907         case LDAP_SUCCESS:
3908         case LDAP_ALREADY_EXISTS:
3909                 break;
3910
3911         default:
3912                 return rc;
3913         }
3914
3915         op->o_tag = LDAP_REQ_ADD;
3916         op->o_callback = &cb;
3917         cb.sc_response = syncrepl_null_callback;
3918         cb.sc_private = NULL;
3919
3920         op->o_req_dn = e->e_name;
3921         op->o_req_ndn = e->e_nname;
3922         op->ora_e = e;
3923         rc = be->be_add ( op, &rs_add );
3924         if ( rs_add.sr_err == LDAP_SUCCESS ) {
3925                 if ( op->ora_e == e )
3926                         be_entry_release_w( op, e );
3927         } else {
3928                 entry_free( e );
3929         }
3930
3931         return rc;
3932 }
3933
3934 static int
3935 syncrepl_updateCookie(
3936         syncinfo_t *si,
3937         Operation *op,
3938         struct sync_cookie *syncCookie,
3939         int save )
3940 {
3941         Backend *be = op->o_bd;
3942         Modifications mod;
3943         struct berval first = BER_BVNULL;
3944         struct sync_cookie sc;
3945 #ifdef CHECK_CSN
3946         Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax;
3947 #endif
3948
3949         int rc, i, j, changed = 0;
3950         ber_len_t len;
3951
3952         slap_callback cb = { NULL };
3953         SlapReply       rs_modify = {REP_RESULT};
3954
3955         mod.sml_op = LDAP_MOD_REPLACE;
3956         mod.sml_desc = slap_schema.si_ad_contextCSN;
3957         mod.sml_type = mod.sml_desc->ad_cname;
3958         mod.sml_flags = SLAP_MOD_INTERNAL;
3959         mod.sml_nvalues = NULL;
3960         mod.sml_next = NULL;
3961
3962         ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
3963         while ( si->si_cookieState->cs_updating )
3964                 ldap_pvt_thread_cond_wait( &si->si_cookieState->cs_cond, &si->si_cookieState->cs_mutex );
3965
3966 #ifdef CHECK_CSN
3967         for ( i=0; i<syncCookie->numcsns; i++ ) {
3968                 assert( !syn->ssyn_validate( syn, syncCookie->ctxcsn+i ));
3969         }
3970         for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
3971                 assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i ));
3972         }
3973 #endif
3974
3975         /* clone the cookieState CSNs so we can Replace the whole thing */
3976         sc.numcsns = si->si_cookieState->cs_num;
3977         if ( sc.numcsns ) {
3978                 ber_bvarray_dup_x( &sc.ctxcsn, si->si_cookieState->cs_vals, NULL );
3979                 sc.sids = ch_malloc( sc.numcsns * sizeof(int));
3980                 for ( i=0; i<sc.numcsns; i++ )
3981                         sc.sids[i] = si->si_cookieState->cs_sids[i];
3982         } else {
3983                 sc.ctxcsn = NULL;
3984                 sc.sids = NULL;
3985         }
3986
3987         /* find any CSNs in the syncCookie that are newer than the cookieState */
3988         for ( i=0; i<syncCookie->numcsns; i++ ) {
3989                 for ( j=0; j<sc.numcsns; j++ ) {
3990                         if ( syncCookie->sids[i] < sc.sids[j] )
3991                                 break;
3992                         if ( syncCookie->sids[i] != sc.sids[j] )
3993                                 continue;
3994                         len = syncCookie->ctxcsn[i].bv_len;
3995                         if ( len > sc.ctxcsn[j].bv_len )
3996                                 len = sc.ctxcsn[j].bv_len;
3997                         if ( memcmp( syncCookie->ctxcsn[i].bv_val,
3998                                 sc.ctxcsn[j].bv_val, len ) > 0 ) {
3999                                 ber_bvreplace( &sc.ctxcsn[j], &syncCookie->ctxcsn[i] );
4000                                 changed = 1;
4001                                 if ( BER_BVISNULL( &first ) ||
4002                                         memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
4003                                         first = syncCookie->ctxcsn[i];
4004                                 }
4005                         }
4006                         break;
4007                 }
4008                 /* there was no match for this SID, it's a new CSN */
4009                 if ( j == sc.numcsns ||
4010                         syncCookie->sids[i] != sc.sids[j] ) {
4011                         slap_insert_csn_sids( &sc, j, syncCookie->sids[i],
4012                                 &syncCookie->ctxcsn[i] );
4013                         if ( BER_BVISNULL( &first ) ||
4014                                 memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
4015                                 first = syncCookie->ctxcsn[i];
4016                         }
4017                         changed = 1;
4018                 }
4019         }
4020         /* Should never happen, ITS#5065 */
4021         if ( BER_BVISNULL( &first ) || !changed ) {
4022                 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
4023                 ber_bvarray_free( sc.ctxcsn );
4024                 ch_free( sc.sids );
4025                 return 0;
4026         }
4027
4028         si->si_cookieState->cs_updating = 1;
4029         ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
4030
4031         if ( save || !si->si_has_syncprov ) {
4032                 op->o_bd = si->si_wbe;
4033                 slap_queue_csn( op, &first );
4034
4035                 op->o_tag = LDAP_REQ_MODIFY;
4036
4037                 cb.sc_response = syncrepl_null_callback;
4038                 cb.sc_private = si;
4039
4040                 op->o_callback = &cb;
4041                 op->o_req_dn = si->si_contextdn;
4042                 op->o_req_ndn = si->si_contextdn;
4043
4044                 /* update contextCSN */
4045                 op->o_dont_replicate = 1;
4046
4047                 mod.sml_numvals = sc.numcsns;
4048                 mod.sml_values = sc.ctxcsn;
4049
4050                 op->orm_modlist = &mod;
4051                 op->orm_no_opattrs = 1;
4052                 rc = op->o_bd->be_modify( op, &rs_modify );
4053
4054                 if ( rs_modify.sr_err == LDAP_NO_SUCH_OBJECT &&
4055                         SLAP_SYNC_SUBENTRY( op->o_bd )) {
4056                         const char      *text;
4057                         char txtbuf[SLAP_TEXT_BUFLEN];
4058                         size_t textlen = sizeof txtbuf;
4059                         Entry *e = slap_create_context_csn_entry( op->o_bd, NULL );
4060                         rs_reinit( &rs_modify, REP_RESULT );
4061                         rc = slap_mods2entry( &mod, &e, 0, 1, &text, txtbuf, textlen);
4062                         op->ora_e = e;
4063                         rc = op->o_bd->be_add( op, &rs_modify );
4064                         if ( e == op->ora_e )
4065                                 be_entry_release_w( op, op->ora_e );
4066                 }
4067
4068                 op->orm_no_opattrs = 0;
4069                 op->o_dont_replicate = 0;
4070         } else {
4071                 rc = 0;
4072         }
4073
4074         op->orm_no_opattrs = 0;
4075         op->o_dont_replicate = 0;
4076         ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
4077
4078         if ( rs_modify.sr_err == LDAP_SUCCESS ) {
4079                 slap_sync_cookie_free( &si->si_syncCookie, 0 );
4080                 ber_bvarray_free( si->si_cookieState->cs_vals );
4081                 ch_free( si->si_cookieState->cs_sids );
4082                 si->si_cookieState->cs_vals = sc.ctxcsn;
4083                 si->si_cookieState->cs_sids = sc.sids;
4084                 si->si_cookieState->cs_num = sc.numcsns;
4085
4086                 /* Don't just dup the provider's cookie, recreate it */
4087                 si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
4088                 ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn, si->si_cookieState->cs_vals, NULL );
4089                 si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num * sizeof(int) );
4090                 for ( i=0; i<si->si_cookieState->cs_num; i++ )
4091                         si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i];
4092
4093                 si->si_cookieState->cs_age++;
4094                 si->si_cookieAge = si->si_cookieState->cs_age;
4095         } else {
4096                 Debug( LDAP_DEBUG_ANY,
4097                         "syncrepl_updateCookie: %s be_modify failed (%d)\n",
4098                         si->si_ridtxt, rs_modify.sr_err, 0 );
4099                 ch_free( sc.sids );
4100                 ber_bvarray_free( sc.ctxcsn );
4101         }
4102
4103 #ifdef CHECK_CSN
4104         for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
4105                 assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i ));
4106         }
4107 #endif
4108
4109         si->si_cookieState->cs_updating = 0;
4110         ldap_pvt_thread_cond_broadcast( &si->si_cookieState->cs_cond );
4111         ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
4112
4113         op->o_bd = be;
4114         if ( op->o_csn.bv_val )
4115                 op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
4116         BER_BVZERO( &op->o_csn );
4117         if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
4118
4119         return rc;
4120 }
4121
4122 /* Compare the attribute from the old entry to the one in the new
4123  * entry. The Modifications from the new entry will either be left
4124  * in place, or changed to an Add or Delete as needed.
4125  */
4126 static void
4127 attr_cmp( Operation *op, Attribute *old, Attribute *new,
4128         Modifications ***mret, Modifications ***mcur )
4129 {
4130         int i, j;
4131         Modifications *mod, **modtail;
4132
4133         modtail = *mret;
4134
4135         if ( old ) {
4136                 int n, o, nn, no;
4137                 struct berval **adds, **dels;
4138                 /* count old and new */
4139                 for ( o=0; old->a_vals[o].bv_val; o++ ) ;
4140                 for ( n=0; new->a_vals[n].bv_val; n++ ) ;
4141
4142                 /* there MUST be both old and new values */
4143                 assert( o != 0 );
4144                 assert( n != 0 );
4145                 j = 0;
4146
4147                 adds = op->o_tmpalloc( sizeof(struct berval *) * n, op->o_tmpmemctx );
4148                 dels = op->o_tmpalloc( sizeof(struct berval *) * o, op->o_tmpmemctx );
4149
4150                 for ( i=0; i<o; i++ ) dels[i] = &old->a_vals[i];
4151                 for ( i=0; i<n; i++ ) adds[i] = &new->a_vals[i];
4152
4153                 nn = n; no = o;
4154
4155                 for ( i=0; i<o; i++ ) {
4156                         for ( j=0; j<n; j++ ) {
4157                                 if ( !adds[j] )
4158                                         continue;
4159                                 if ( bvmatch( dels[i], adds[j] ) ) {
4160                                         no--;
4161                                         nn--;
4162                                         adds[j] = NULL;
4163                                         dels[i] = NULL;
4164                                         break;
4165                                 }
4166                         }
4167                 }
4168
4169                 /* Don't delete/add an objectClass, always use the replace op.
4170                  * Modify would fail if provider has replaced entry with a new,
4171                  * and the new explicitly includes a superior of a class that was
4172                  * only included implicitly in the old entry.  Ref ITS#5517.
4173                  *
4174                  * Also use replace op if attr has no equality matching rule.
4175                  * (ITS#5781)
4176                  */
4177                 if ( ( nn || ( no > 0 && no < o ) ) &&
4178                         ( old->a_desc == slap_schema.si_ad_objectClass ||
4179                          !old->a_desc->ad_type->sat_equality ) )
4180                 {
4181                         no = o;
4182                 }
4183
4184                 i = j;
4185                 /* all old values were deleted, just use the replace op */
4186                 if ( no == o ) {
4187                         i = j-1;
4188                 } else if ( no ) {
4189                 /* delete some values */
4190                         mod = ch_malloc( sizeof( Modifications ) );
4191                         mod->sml_op = LDAP_MOD_DELETE;
4192                         mod->sml_flags = 0;
4193                         mod->sml_desc = old->a_desc;
4194                         mod->sml_type = mod->sml_desc->ad_cname;
4195                         mod->sml_numvals = no;
4196                         mod->sml_values = ch_malloc( ( no + 1 ) * sizeof(struct berval) );
4197                         if ( old->a_vals != old->a_nvals ) {
4198                                 mod->sml_nvalues = ch_malloc( ( no + 1 ) * sizeof(struct berval) );
4199                         } else {
4200                                 mod->sml_nvalues = NULL;
4201                         }
4202                         j = 0;
4203                         for ( i = 0; i < o; i++ ) {
4204                                 if ( !dels[i] ) continue;
4205                                 ber_dupbv( &mod->sml_values[j], &old->a_vals[i] );
4206                                 if ( mod->sml_nvalues ) {
4207                                         ber_dupbv( &mod->sml_nvalues[j], &old->a_nvals[i] );
4208                                 }
4209                                 j++;
4210                         }
4211                         BER_BVZERO( &mod->sml_values[j] );
4212                         if ( mod->sml_nvalues ) {
4213                                 BER_BVZERO( &mod->sml_nvalues[j] );
4214                         }
4215                         *modtail = mod;
4216                         modtail = &mod->sml_next;
4217                         i = j;
4218                 }
4219                 op->o_tmpfree( dels, op->o_tmpmemctx );
4220                 /* some values were added */
4221                 if ( nn && no < o ) {
4222                         mod = ch_malloc( sizeof( Modifications ) );
4223                         mod->sml_op = LDAP_MOD_ADD;
4224                         mod->sml_flags = 0;
4225                         mod->sml_desc = old->a_desc;
4226                         mod->sml_type = mod->sml_desc->ad_cname;
4227                         mod->sml_numvals = nn;
4228                         mod->sml_values = ch_malloc( ( nn + 1 ) * sizeof(struct berval) );
4229                         if ( old->a_vals != old->a_nvals ) {
4230                                 mod->sml_nvalues = ch_malloc( ( nn + 1 ) * sizeof(struct berval) );
4231                         } else {
4232                                 mod->sml_nvalues = NULL;
4233                         }
4234                         j = 0;
4235                         for ( i = 0; i < n; i++ ) {
4236                                 if ( !adds[i] ) continue;
4237                                 ber_dupbv( &mod->sml_values[j], &new->a_vals[i] );
4238                                 if ( mod->sml_nvalues ) {
4239                                         ber_dupbv( &mod->sml_nvalues[j], &new->a_nvals[i] );
4240                                 }
4241                                 j++;
4242                         }
4243                         BER_BVZERO( &mod->sml_values[j] );
4244                         if ( mod->sml_nvalues ) {
4245                                 BER_BVZERO( &mod->sml_nvalues[j] );
4246                         }
4247                         *modtail = mod;
4248                         modtail = &mod->sml_next;
4249                         i = j;
4250                 }
4251                 op->o_tmpfree( adds, op->o_tmpmemctx );
4252         } else {
4253                 /* new attr, just use the new mod */
4254                 i = 0;
4255                 j = 1;
4256         }
4257         /* advance to next element */
4258         mod = **mcur;
4259         if ( mod ) {
4260                 if ( i != j ) {
4261                         **mcur = mod->sml_next;
4262                         *modtail = mod;
4263                         modtail = &mod->sml_next;
4264                 } else {
4265                         *mcur = &mod->sml_next;
4266                 }
4267         }
4268         *mret = modtail;
4269 }
4270
4271 /* Generate a set of modifications to change the old entry into the
4272  * new one. On input ml is a list of modifications equivalent to
4273  * the new entry. It will be massaged and the result will be stored
4274  * in mods.
4275  */
4276 void syncrepl_diff_entry( Operation *op, Attribute *old, Attribute *new,
4277         Modifications **mods, Modifications **ml, int is_ctx)
4278 {
4279         Modifications **modtail = mods;
4280
4281         /* We assume that attributes are saved in the same order
4282          * in the remote and local databases. So if we walk through
4283          * the attributeDescriptions one by one they should match in
4284          * lock step. If not, look for an add or delete.
4285          */
4286         while ( old && new )
4287         {
4288                 /* If we've seen this before, use its mod now */
4289                 if ( new->a_flags & SLAP_ATTR_IXADD ) {
4290                         attr_cmp( op, NULL, new, &modtail, &ml );
4291                         new = new->a_next;
4292                         continue;
4293                 }
4294                 /* Skip contextCSN */
4295                 if ( is_ctx && old->a_desc ==
4296                         slap_schema.si_ad_contextCSN ) {
4297                         old = old->a_next;
4298                         continue;
4299                 }
4300
4301                 if ( old->a_desc != new->a_desc ) {
4302                         Modifications *mod;
4303                         Attribute *tmp;
4304
4305                         /* If it's just been re-added later,
4306                          * remember that we've seen it.
4307                          */
4308                         tmp = attr_find( new, old->a_desc );
4309                         if ( tmp ) {
4310                                 tmp->a_flags |= SLAP_ATTR_IXADD;
4311                         } else {
4312                                 /* If it's a new attribute, pull it in.
4313                                  */
4314                                 tmp = attr_find( old, new->a_desc );
4315                                 if ( !tmp ) {
4316                                         attr_cmp( op, NULL, new, &modtail, &ml );
4317                                         new = new->a_next;
4318                                         continue;
4319                                 }
4320                                 /* Delete old attr */
4321                                 mod = ch_malloc( sizeof( Modifications ) );
4322                                 mod->sml_op = LDAP_MOD_DELETE;
4323                                 mod->sml_flags = 0;
4324                                 mod->sml_desc = old->a_desc;
4325                                 mod->sml_type = mod->sml_desc->ad_cname;
4326                                 mod->sml_numvals = 0;
4327                                 mod->sml_values = NULL;
4328                                 mod->sml_nvalues = NULL;
4329                                 *modtail = mod;
4330                                 modtail = &mod->sml_next;
4331                         }
4332                         old = old->a_next;
4333                         continue;
4334                 }
4335                 /* kludge - always update modifiersName so that it
4336                  * stays co-located with the other mod opattrs. But only
4337                  * if we know there are other valid mods.
4338                  */
4339                 if ( *mods && ( old->a_desc == slap_schema.si_ad_modifiersName ||
4340                         old->a_desc == slap_schema.si_ad_modifyTimestamp ))
4341                         attr_cmp( op, NULL, new, &modtail, &ml );
4342                 else
4343                         attr_cmp( op, old, new, &modtail, &ml );
4344                 new = new->a_next;
4345                 old = old->a_next;
4346         }
4347         *modtail = *ml;
4348         *ml = NULL;
4349 }
4350
4351 static int
4352 dn_callback(
4353         Operation*      op,
4354         SlapReply*      rs )
4355 {
4356         dninfo *dni = op->o_callback->sc_private;
4357
4358         if ( rs->sr_type == REP_SEARCH ) {
4359                 if ( !BER_BVISNULL( &dni->dn ) ) {
4360                         Debug( LDAP_DEBUG_ANY,
4361                                 "dn_callback : consistency error - "
4362                                 "entryUUID is not unique\n", 0, 0, 0 );
4363                 } else {
4364                         ber_dupbv_x( &dni->dn, &rs->sr_entry->e_name, op->o_tmpmemctx );
4365                         ber_dupbv_x( &dni->ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx );
4366                         /* If there is a new entry, see if it differs from the old.
4367                          * We compare the non-normalized values so that cosmetic changes
4368                          * in the provider are always propagated.
4369                          */
4370                         if ( dni->new_entry ) {
4371                                 Attribute *old, *new;
4372                                 struct berval old_rdn, new_rdn;
4373                                 struct berval old_p, new_p;
4374                                 int is_ctx, new_sup = 0;
4375
4376                                 /* If old entry is not a glue entry, make sure new entry
4377                                  * is actually newer than old entry
4378                                  */
4379                                 if ( !is_entry_glue( rs->sr_entry )) {
4380                                         old = attr_find( rs->sr_entry->e_attrs,
4381                                                 slap_schema.si_ad_entryCSN );
4382                                         new = attr_find( dni->new_entry->e_attrs,
4383                                                 slap_schema.si_ad_entryCSN );
4384                                         if ( new && old ) {
4385                                                 int rc;
4386                                                 ber_len_t len = old->a_vals[0].bv_len;
4387                                                 if ( len > new->a_vals[0].bv_len )
4388                                                         len = new->a_vals[0].bv_len;
4389                                                 rc = memcmp( old->a_vals[0].bv_val,
4390                                                         new->a_vals[0].bv_val, len );
4391                                                 if ( rc > 0 ) {
4392                                                         Debug( LDAP_DEBUG_SYNC,
4393                                                                 "dn_callback : new entry is older than ours "
4394                                                                 "%s ours %s, new %s\n",
4395                                                                 rs->sr_entry->e_name.bv_val,
4396                                                                 old->a_vals[0].bv_val,
4397                                                                 new->a_vals[0].bv_val );
4398                                                         return LDAP_SUCCESS;
4399                                                 } else if ( rc == 0 ) {
4400                                                         Debug( LDAP_DEBUG_SYNC,
4401                                                                 "dn_callback : entries have identical CSN "
4402                                                                 "%s %s\n",
4403                                                                 rs->sr_entry->e_name.bv_val,
4404                                                                 old->a_vals[0].bv_val, 0 );
4405                                                         return LDAP_SUCCESS;
4406                                                 }
4407                                         }
4408                                 }
4409
4410                                 is_ctx = dn_match( &rs->sr_entry->e_nname,
4411                                         &op->o_bd->be_nsuffix[0] );
4412
4413                                 /* Did the DN change?
4414                                  * case changes in the parent are ignored,
4415                                  * we only want to know if the RDN was
4416                                  * actually changed.
4417                                  */
4418                                 dnRdn( &rs->sr_entry->e_name, &old_rdn );
4419                                 dnRdn( &dni->new_entry->e_name, &new_rdn );
4420                                 dnParent( &rs->sr_entry->e_nname, &old_p );
4421                                 dnParent( &dni->new_entry->e_nname, &new_p );
4422
4423                                 new_sup = !dn_match( &old_p, &new_p );
4424                                 if ( !dn_match( &old_rdn, &new_rdn ) || new_sup )
4425                                 {
4426                                         struct berval oldRDN, oldVal;
4427                                         AttributeDescription *ad = NULL;
4428                                         int oldpos, newpos;
4429                                         Attribute *a;
4430
4431                                         dni->renamed = 1;
4432                                         if ( new_sup )
4433                                                 dni->nnewSup = new_p;
4434
4435                                         /* See if the oldRDN was deleted */
4436                                         dnRdn( &rs->sr_entry->e_nname, &oldRDN );
4437                                         oldVal.bv_val = strchr(oldRDN.bv_val, '=') + 1;
4438                                         oldVal.bv_len = oldRDN.bv_len - ( oldVal.bv_val -
4439                                                 oldRDN.bv_val );
4440                                         oldRDN.bv_len -= oldVal.bv_len + 1;
4441                                         slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
4442                                         dni->oldDesc = ad;
4443                                         for ( oldpos=0, a=rs->sr_entry->e_attrs;
4444                                                 a && a->a_desc != ad; oldpos++, a=a->a_next );
4445                                         /* a should not be NULL but apparently it happens.
4446                                          * ITS#7144
4447                                          */
4448                                         dni->oldNcount = a ? a->a_numvals : 0;
4449                                         for ( newpos=0, a=dni->new_entry->e_attrs;
4450                                                 a && a->a_desc != ad; newpos++, a=a->a_next );
4451                                         if ( !a || oldpos != newpos || attr_valfind( a,
4452                                                 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
4453                                                 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
4454                                                 SLAP_MR_VALUE_OF_SYNTAX,
4455                                                 &oldVal, NULL, op->o_tmpmemctx ) != LDAP_SUCCESS )
4456                                         {
4457                                                 dni->delOldRDN = 1;
4458                                         }
4459                                         /* Get the newRDN's desc */
4460                                         dnRdn( &dni->new_entry->e_nname, &oldRDN );
4461                                         oldVal.bv_val = strchr(oldRDN.bv_val, '=');
4462                                         oldRDN.bv_len = oldVal.bv_val - oldRDN.bv_val;
4463                                         ad = NULL;
4464                                         slap_bv2ad( &oldRDN, &ad, &rs->sr_text );
4465                                         dni->newDesc = ad;
4466
4467                                         /* A ModDN has happened, but in Refresh mode other
4468                                          * changes may have occurred before we picked it up.
4469                                          * So fallthru to regular Modify processing.
4470                                          */
4471                                 }
4472
4473                                 syncrepl_diff_entry( op, rs->sr_entry->e_attrs,
4474                                         dni->new_entry->e_attrs, &dni->mods, dni->modlist,
4475                                         is_ctx );
4476                         }
4477                 }
4478         } else if ( rs->sr_type == REP_RESULT ) {
4479                 if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) {
4480                         Debug( LDAP_DEBUG_ANY,
4481                                 "dn_callback : consistency error - "
4482                                 "entryUUID is not unique\n", 0, 0, 0 );
4483                 }
4484         }
4485
4486         return LDAP_SUCCESS;
4487 }
4488
4489 static int
4490 nonpresent_callback(
4491         Operation*      op,
4492         SlapReply*      rs )
4493 {
4494         syncinfo_t *si = op->o_callback->sc_private;
4495         Attribute *a;
4496         int count = 0;
4497         char *present_uuid = NULL;
4498         struct nonpresent_entry *np_entry;
4499
4500         if ( rs->sr_type == REP_RESULT ) {
4501                 count = presentlist_free( si->si_presentlist );
4502                 si->si_presentlist = NULL;
4503
4504         } else if ( rs->sr_type == REP_SEARCH ) {
4505                 if ( !( si->si_refreshDelete & NP_DELETE_ONE ) ) {
4506                         a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
4507
4508                         if ( a ) {
4509                                 present_uuid = presentlist_find( si->si_presentlist, &a->a_nvals[0] );
4510                         }
4511
4512                         if ( LogTest( LDAP_DEBUG_SYNC ) ) {
4513                                 char buf[sizeof("rid=999 non")];
4514
4515                                 snprintf( buf, sizeof(buf), "%s %s", si->si_ridtxt,
4516                                         present_uuid ? "" : "non" );
4517
4518                                 Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %spresent UUID %s, dn %s\n",
4519                                         buf, a ? a->a_vals[0].bv_val : "<missing>", rs->sr_entry->e_name.bv_val );
4520                         }
4521
4522                         if ( a == NULL ) return 0;
4523                 }
4524
4525                 if ( present_uuid == NULL ) {
4526                         np_entry = (struct nonpresent_entry *)
4527                                 ch_calloc( 1, sizeof( struct nonpresent_entry ) );
4528                         np_entry->npe_name = ber_dupbv( NULL, &rs->sr_entry->e_name );
4529                         np_entry->npe_nname = ber_dupbv( NULL, &rs->sr_entry->e_nname );
4530                         LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link );
4531
4532                 } else {
4533                         presentlist_delete( &si->si_presentlist, &a->a_nvals[0] );
4534                         ch_free( present_uuid );
4535                 }
4536         }
4537         return LDAP_SUCCESS;
4538 }
4539
4540 static struct berval *
4541 slap_uuidstr_from_normalized(
4542         struct berval* uuidstr,
4543         struct berval* normalized,
4544         void *ctx )
4545 {
4546 #if 0
4547         struct berval *new;
4548         unsigned char nibble;
4549         int i, d = 0;
4550
4551         if ( normalized == NULL ) return NULL;
4552         if ( normalized->bv_len != 16 ) return NULL;
4553
4554         if ( uuidstr ) {
4555                 new = uuidstr;
4556         } else {
4557                 new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx );
4558                 if ( new == NULL ) {
4559                         return NULL;
4560                 }
4561         }
4562
4563         new->bv_len = 36;
4564
4565         if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) {
4566                 if ( new != uuidstr ) {
4567                         slap_sl_free( new, ctx );
4568                 }
4569                 return NULL;
4570         }
4571
4572         for ( i = 0; i < 16; i++ ) {
4573                 if ( i == 4 || i == 6 || i == 8 || i == 10 ) {
4574                         new->bv_val[(i<<1)+d] = '-';
4575                         d += 1;
4576                 }
4577
4578                 nibble = (normalized->bv_val[i] >> 4) & 0xF;
4579                 if ( nibble < 10 ) {
4580                         new->bv_val[(i<<1)+d] = nibble + '0';
4581                 } else {
4582                         new->bv_val[(i<<1)+d] = nibble - 10 + 'a';
4583                 }
4584
4585                 nibble = (normalized->bv_val[i]) & 0xF;
4586                 if ( nibble < 10 ) {
4587                         new->bv_val[(i<<1)+d+1] = nibble + '0';
4588                 } else {
4589                         new->bv_val[(i<<1)+d+1] = nibble - 10 + 'a';
4590                 }
4591         }
4592
4593         new->bv_val[new->bv_len] = '\0';
4594         return new;
4595 #endif
4596
4597         struct berval   *new;
4598         int             rc = 0;
4599
4600         if ( normalized == NULL ) return NULL;
4601         if ( normalized->bv_len != 16 ) return NULL;
4602
4603         if ( uuidstr ) {
4604                 new = uuidstr;
4605
4606         } else {
4607                 new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx );
4608                 if ( new == NULL ) {
4609                         return NULL;
4610                 }
4611         }
4612
4613         new->bv_len = 36;
4614
4615         if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) {
4616                 rc = 1;
4617                 goto done;
4618         }
4619
4620         rc = lutil_uuidstr_from_normalized( normalized->bv_val,
4621                 normalized->bv_len, new->bv_val, new->bv_len + 1 );
4622
4623 done:;
4624         if ( rc == -1 ) {
4625                 if ( new != NULL ) {
4626                         if ( new->bv_val != NULL ) {
4627                                 slap_sl_free( new->bv_val, ctx );
4628                         }
4629
4630                         if ( new != uuidstr ) {
4631                                 slap_sl_free( new, ctx );
4632                         }
4633                 }
4634                 new = NULL;
4635
4636         } else {
4637                 new->bv_len = rc;
4638         }
4639
4640         return new;
4641 }
4642
4643 static int
4644 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
4645 {
4646 #ifdef HASHUUID
4647         return ( memcmp( v_uuid1, v_uuid2, UUIDLEN-2 ));
4648 #else
4649         return ( memcmp( v_uuid1, v_uuid2, UUIDLEN ));
4650 #endif
4651 }
4652
4653 void
4654 syncinfo_free( syncinfo_t *sie, int free_all )
4655 {
4656         syncinfo_t *si_next;
4657
4658         Debug( LDAP_DEBUG_TRACE, "syncinfo_free: %s\n",
4659                 sie->si_ridtxt, 0, 0 );
4660
4661         do {
4662                 si_next = sie->si_next;
4663
4664                 if ( sie->si_ld ) {
4665                         if ( sie->si_conn ) {
4666                                 connection_client_stop( sie->si_conn );
4667                                 sie->si_conn = NULL;
4668                         }
4669                         ldap_unbind_ext( sie->si_ld, NULL, NULL );
4670                 }
4671         
4672                 if ( sie->si_re ) {
4673                         struct re_s             *re = sie->si_re;
4674                         sie->si_re = NULL;
4675
4676                         ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
4677                         if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
4678                                 ldap_pvt_runqueue_stoptask( &slapd_rq, re );
4679                         ldap_pvt_runqueue_remove( &slapd_rq, re );
4680                         ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
4681                 }
4682
4683                 ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
4684
4685                 bindconf_free( &sie->si_bindconf );
4686
4687                 if ( sie->si_filterstr.bv_val ) {
4688                         ch_free( sie->si_filterstr.bv_val );
4689                 }
4690                 if ( sie->si_filter ) {
4691                         filter_free( sie->si_filter );
4692                 }
4693                 if ( sie->si_logfilterstr.bv_val ) {
4694                         ch_free( sie->si_logfilterstr.bv_val );
4695                 }
4696                 if ( sie->si_logfilter ) {
4697                         filter_free( sie->si_logfilter );
4698                 }
4699                 if ( sie->si_base.bv_val ) {
4700                         ch_free( sie->si_base.bv_val );
4701                 }
4702                 if ( sie->si_logbase.bv_val ) {
4703                         ch_free( sie->si_logbase.bv_val );
4704                 }
4705                 if ( sie->si_be && SLAP_SYNC_SUBENTRY( sie->si_be )) {
4706                         ch_free( sie->si_contextdn.bv_val );
4707                 }
4708                 if ( sie->si_attrs ) {
4709                         int i = 0;
4710                         while ( sie->si_attrs[i] != NULL ) {
4711                                 ch_free( sie->si_attrs[i] );
4712                                 i++;
4713                         }
4714                         ch_free( sie->si_attrs );
4715                 }
4716                 if ( sie->si_exattrs ) {
4717                         int i = 0;
4718                         while ( sie->si_exattrs[i] != NULL ) {
4719                                 ch_free( sie->si_exattrs[i] );
4720                                 i++;
4721                         }
4722                         ch_free( sie->si_exattrs );
4723                 }
4724                 if ( sie->si_anlist ) {
4725                         int i = 0;
4726                         while ( sie->si_anlist[i].an_name.bv_val != NULL ) {
4727                                 ch_free( sie->si_anlist[i].an_name.bv_val );
4728                                 i++;
4729                         }
4730                         ch_free( sie->si_anlist );
4731                 }
4732                 if ( sie->si_exanlist ) {
4733                         int i = 0;
4734                         while ( sie->si_exanlist[i].an_name.bv_val != NULL ) {
4735                                 ch_free( sie->si_exanlist[i].an_name.bv_val );
4736                                 i++;
4737                         }
4738                         ch_free( sie->si_exanlist );
4739                 }
4740                 if ( sie->si_retryinterval ) {
4741                         ch_free( sie->si_retryinterval );
4742                 }
4743                 if ( sie->si_retrynum ) {
4744                         ch_free( sie->si_retrynum );
4745                 }
4746                 if ( sie->si_retrynum_init ) {
4747                         ch_free( sie->si_retrynum_init );
4748                 }
4749                 slap_sync_cookie_free( &sie->si_syncCookie, 0 );
4750                 if ( sie->si_presentlist ) {
4751                     presentlist_free( sie->si_presentlist );
4752                 }
4753                 while ( !LDAP_LIST_EMPTY( &sie->si_nonpresentlist ) ) {
4754                         struct nonpresent_entry* npe;
4755                         npe = LDAP_LIST_FIRST( &sie->si_nonpresentlist );
4756                         LDAP_LIST_REMOVE( npe, npe_link );
4757                         if ( npe->npe_name ) {
4758                                 if ( npe->npe_name->bv_val ) {
4759                                         ch_free( npe->npe_name->bv_val );
4760                                 }
4761                                 ch_free( npe->npe_name );
4762                         }
4763                         if ( npe->npe_nname ) {
4764                                 if ( npe->npe_nname->bv_val ) {
4765                                         ch_free( npe->npe_nname->bv_val );
4766                                 }
4767                                 ch_free( npe->npe_nname );
4768                         }
4769                         ch_free( npe );
4770                 }
4771                 if ( sie->si_cookieState ) {
4772                         sie->si_cookieState->cs_ref--;
4773                         if ( !sie->si_cookieState->cs_ref ) {
4774                                 ch_free( sie->si_cookieState->cs_sids );
4775                                 ber_bvarray_free( sie->si_cookieState->cs_vals );
4776                                 ldap_pvt_thread_cond_destroy( &sie->si_cookieState->cs_cond );
4777                                 ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
4778                                 ch_free( sie->si_cookieState->cs_psids );
4779                                 ber_bvarray_free( sie->si_cookieState->cs_pvals );
4780                                 ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_pmutex );
4781                                 ch_free( sie->si_cookieState );
4782                         }
4783                 }
4784 #ifdef ENABLE_REWRITE
4785                 if ( sie->si_rewrite )
4786                         rewrite_info_delete( &sie->si_rewrite );
4787                 if ( sie->si_suffixm.bv_val )
4788                         ch_free( sie->si_suffixm.bv_val );
4789 #endif
4790                 ch_free( sie );
4791                 sie = si_next;
4792         } while ( free_all && si_next );
4793 }
4794
4795 #ifdef ENABLE_REWRITE
4796 static int
4797 config_suffixm( ConfigArgs *c, syncinfo_t *si )
4798 {
4799         char *argvEngine[] = { "rewriteEngine", "on", NULL };
4800         char *argvContext[] = { "rewriteContext", SUFFIXM_CTX, NULL };
4801         char *argvRule[] = { "rewriteRule", NULL, NULL, ":", NULL };
4802         char *vnc, *rnc;
4803         int rc;
4804
4805         if ( si->si_rewrite )
4806                 rewrite_info_delete( &si->si_rewrite );
4807         si->si_rewrite = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
4808
4809         rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvEngine );
4810         if ( rc != LDAP_SUCCESS )
4811                 return rc;
4812
4813         rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvContext );
4814         if ( rc != LDAP_SUCCESS )
4815                 return rc;
4816
4817         vnc = ch_malloc( si->si_base.bv_len + 6 );
4818         strcpy( vnc, "(.*)" );
4819         lutil_strcopy( lutil_strcopy( vnc+4, si->si_base.bv_val ), "$" );
4820         argvRule[1] = vnc;
4821
4822         rnc = ch_malloc( si->si_suffixm.bv_len + 3 );
4823         strcpy( rnc, "%1" );
4824         strcpy( rnc+2, si->si_suffixm.bv_val );
4825         argvRule[2] = rnc;
4826
4827         rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 4, argvRule );
4828         ch_free( vnc );
4829         ch_free( rnc );
4830         return rc;
4831 }
4832 #endif
4833
4834 /* NOTE: used & documented in slapd.conf(5) */
4835 #define IDSTR                   "rid"
4836 #define PROVIDERSTR             "provider"
4837 #define SCHEMASTR               "schemachecking"
4838 #define FILTERSTR               "filter"
4839 #define SEARCHBASESTR           "searchbase"
4840 #define SCOPESTR                "scope"
4841 #define ATTRSONLYSTR            "attrsonly"
4842 #define ATTRSSTR                "attrs"
4843 #define TYPESTR                 "type"
4844 #define INTERVALSTR             "interval"
4845 #define RETRYSTR                "retry"
4846 #define SLIMITSTR               "sizelimit"
4847 #define TLIMITSTR               "timelimit"
4848 #define SYNCDATASTR             "syncdata"
4849 #define LOGBASESTR              "logbase"
4850 #define LOGFILTERSTR    "logfilter"
4851 #define SUFFIXMSTR              "suffixmassage"
4852 #define STRICT_REFRESH  "strictrefresh"
4853 #define LAZY_COMMIT             "lazycommit"
4854
4855 /* FIXME: undocumented */
4856 #define EXATTRSSTR              "exattrs"
4857 #define MANAGEDSAITSTR          "manageDSAit"
4858
4859 /* mandatory */
4860 enum {
4861         GOT_RID                 = 0x00000001U,
4862         GOT_PROVIDER            = 0x00000002U,
4863         GOT_SCHEMACHECKING      = 0x00000004U,
4864         GOT_FILTER              = 0x00000008U,
4865         GOT_SEARCHBASE          = 0x00000010U,
4866         GOT_SCOPE               = 0x00000020U,
4867         GOT_ATTRSONLY           = 0x00000040U,
4868         GOT_ATTRS               = 0x00000080U,
4869         GOT_TYPE                = 0x00000100U,
4870         GOT_INTERVAL            = 0x00000200U,
4871         GOT_RETRY               = 0x00000400U,
4872         GOT_SLIMIT              = 0x00000800U,
4873         GOT_TLIMIT              = 0x00001000U,
4874         GOT_SYNCDATA            = 0x00002000U,
4875         GOT_LOGBASE             = 0x00004000U,
4876         GOT_LOGFILTER           = 0x00008000U,
4877         GOT_EXATTRS             = 0x00010000U,
4878         GOT_MANAGEDSAIT         = 0x00020000U,
4879         GOT_BINDCONF            = 0x00040000U,
4880         GOT_SUFFIXM             = 0x00080000U,
4881
4882 /* check */
4883         GOT_REQUIRED            = (GOT_RID|GOT_PROVIDER|GOT_SEARCHBASE)
4884 };
4885
4886 static slap_verbmasks datamodes[] = {
4887         { BER_BVC("default"), SYNCDATA_DEFAULT },
4888         { BER_BVC("accesslog"), SYNCDATA_ACCESSLOG },
4889         { BER_BVC("changelog"), SYNCDATA_CHANGELOG },
4890         { BER_BVNULL, 0 }
4891 };
4892
4893 static int
4894 parse_syncrepl_retry(
4895         ConfigArgs      *c,
4896         char            *arg,
4897         syncinfo_t      *si )
4898 {
4899         char **retry_list;
4900         int j, k, n;
4901         int use_default = 0;
4902
4903         char *val = arg + STRLENOF( RETRYSTR "=" );
4904         if ( strcasecmp( val, "undefined" ) == 0 ) {
4905                 val = "3600 +";
4906                 use_default = 1;
4907         }
4908
4909         retry_list = (char **) ch_calloc( 1, sizeof( char * ) );
4910         retry_list[0] = NULL;
4911
4912         slap_str2clist( &retry_list, val, " ,\t" );
4913
4914         for ( k = 0; retry_list && retry_list[k]; k++ ) ;
4915         n = k / 2;
4916         if ( k % 2 ) {
4917                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
4918                         "Error: incomplete syncrepl retry list" );
4919                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4920                 for ( k = 0; retry_list && retry_list[k]; k++ ) {
4921                         ch_free( retry_list[k] );
4922                 }
4923                 ch_free( retry_list );
4924                 return 1;
4925         }
4926         si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t ) );
4927         si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int ) );
4928         si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int ) );
4929         for ( j = 0; j < n; j++ ) {
4930                 unsigned long   t;
4931                 if ( lutil_atoul( &t, retry_list[j*2] ) != 0 ) {
4932                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
4933                                 "Error: invalid retry interval \"%s\" (#%d)",
4934                                 retry_list[j*2], j );
4935                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4936                         /* do some cleanup */
4937                         return 1;
4938                 }
4939                 si->si_retryinterval[j] = (time_t)t;
4940                 if ( *retry_list[j*2+1] == '+' ) {
4941                         si->si_retrynum_init[j] = RETRYNUM_FOREVER;
4942                         si->si_retrynum[j] = RETRYNUM_FOREVER;
4943                         j++;
4944                         break;
4945                 } else {
4946                         if ( lutil_atoi( &si->si_retrynum_init[j], retry_list[j*2+1] ) != 0
4947                                         || si->si_retrynum_init[j] <= 0 )
4948                         {
4949                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
4950                                         "Error: invalid initial retry number \"%s\" (#%d)",
4951                                         retry_list[j*2+1], j );
4952                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4953                                 /* do some cleanup */
4954                                 return 1;
4955                         }
4956                         if ( lutil_atoi( &si->si_retrynum[j], retry_list[j*2+1] ) != 0
4957                                         || si->si_retrynum[j] <= 0 )
4958                         {
4959                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
4960                                         "Error: invalid retry number \"%s\" (#%d)",
4961                                         retry_list[j*2+1], j );
4962                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
4963                                 /* do some cleanup */
4964                                 return 1;
4965                         }
4966                 }
4967         }
4968         if ( j < 1 || si->si_retrynum_init[j-1] != RETRYNUM_FOREVER ) {
4969                 Debug( LDAP_DEBUG_CONFIG,
4970                         "%s: syncrepl will eventually stop retrying; the \"retry\" parameter should end with a '+'.\n",
4971                         c->log, 0, 0 );
4972         }
4973
4974         si->si_retrynum_init[j] = RETRYNUM_TAIL;
4975         si->si_retrynum[j] = RETRYNUM_TAIL;
4976         si->si_retryinterval[j] = 0;
4977         
4978         for ( k = 0; retry_list && retry_list[k]; k++ ) {
4979                 ch_free( retry_list[k] );
4980         }
4981         ch_free( retry_list );
4982         if ( !use_default ) {
4983                 si->si_got |= GOT_RETRY;
4984         }
4985
4986         return 0;
4987 }
4988
4989 static int
4990 parse_syncrepl_line(
4991         ConfigArgs      *c,
4992         syncinfo_t      *si )
4993 {
4994         int     i;
4995         char    *val;
4996
4997         for ( i = 1; i < c->argc; i++ ) {
4998                 if ( !strncasecmp( c->argv[ i ], IDSTR "=",
4999                                         STRLENOF( IDSTR "=" ) ) )
5000                 {
5001                         int tmp;
5002                         /* '\0' string terminator accounts for '=' */
5003                         val = c->argv[ i ] + STRLENOF( IDSTR "=" );
5004                         if ( lutil_atoi( &tmp, val ) != 0 ) {
5005                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
5006                                         "Error: parse_syncrepl_line: "
5007                                         "unable to parse syncrepl id \"%s\"", val );
5008                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5009                                 return -1;
5010                         }
5011                         if ( tmp > SLAP_SYNC_RID_MAX || tmp < 0 ) {
5012                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
5013                                         "Error: parse_syncrepl_line: "
5014                                         "syncrepl id %d is out of range [0..%d]", tmp, SLAP_SYNC_RID_MAX );
5015                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5016                                 return -1;
5017                         }
5018                         si->si_rid = tmp;
5019                         sprintf( si->si_ridtxt, IDSTR "=%03d", si->si_rid );
5020                         si->si_got |= GOT_RID;
5021                 } else if ( !strncasecmp( c->argv[ i ], PROVIDERSTR "=",
5022                                         STRLENOF( PROVIDERSTR "=" ) ) )
5023                 {
5024                         val = c->argv[ i ] + STRLENOF( PROVIDERSTR "=" );
5025                         ber_str2bv( val, 0, 1, &si->si_bindconf.sb_uri );
5026 #ifdef HAVE_TLS
5027                         if ( ldap_is_ldaps_url( val ))
5028                                 si->si_bindconf.sb_tls_do_init = 1;
5029 #endif
5030                         si->si_got |= GOT_PROVIDER;
5031                 } else if ( !strncasecmp( c->argv[ i ], SCHEMASTR "=",
5032                                         STRLENOF( SCHEMASTR "=" ) ) )
5033                 {
5034                         val = c->argv[ i ] + STRLENOF( SCHEMASTR "=" );
5035                         if ( !strncasecmp( val, "on", STRLENOF( "on" ) ) ) {
5036                                 si->si_schemachecking = 1;
5037                         } else if ( !strncasecmp( val, "off", STRLENOF( "off" ) ) ) {
5038                                 si->si_schemachecking = 0;
5039                         } else {
5040                                 si->si_schemachecking = 1;
5041                         }
5042                         si->si_got |= GOT_SCHEMACHECKING;
5043                 } else if ( !strncasecmp( c->argv[ i ], FILTERSTR "=",
5044                                         STRLENOF( FILTERSTR "=" ) ) )
5045                 {
5046                         val = c->argv[ i ] + STRLENOF( FILTERSTR "=" );
5047                         if ( si->si_filterstr.bv_val )
5048                                 ch_free( si->si_filterstr.bv_val );
5049                         ber_str2bv( val, 0, 1, &si->si_filterstr );
5050                         si->si_got |= GOT_FILTER;
5051                 } else if ( !strncasecmp( c->argv[ i ], LOGFILTERSTR "=",
5052                                         STRLENOF( LOGFILTERSTR "=" ) ) )
5053                 {
5054                         val = c->argv[ i ] + STRLENOF( LOGFILTERSTR "=" );
5055                         if ( si->si_logfilterstr.bv_val )
5056                                 ch_free( si->si_logfilterstr.bv_val );
5057                         ber_str2bv( val, 0, 1, &si->si_logfilterstr );
5058                         si->si_got |= GOT_LOGFILTER;
5059                 } else if ( !strncasecmp( c->argv[ i ], SEARCHBASESTR "=",
5060                                         STRLENOF( SEARCHBASESTR "=" ) ) )
5061                 {
5062                         struct berval   bv;
5063                         int             rc;
5064
5065                         val = c->argv[ i ] + STRLENOF( SEARCHBASESTR "=" );
5066                         if ( si->si_base.bv_val ) {
5067                                 ch_free( si->si_base.bv_val );
5068                         }
5069                         ber_str2bv( val, 0, 0, &bv );
5070                         rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_base, NULL );
5071                         if ( rc != LDAP_SUCCESS ) {
5072                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
5073                                         "Invalid base DN \"%s\": %d (%s)",
5074                                         val, rc, ldap_err2string( rc ) );
5075                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5076                                 return -1;
5077                         }
5078                         si->si_got |= GOT_SEARCHBASE;
5079 #ifdef ENABLE_REWRITE
5080                 } else if ( !strncasecmp( c->argv[ i ], SUFFIXMSTR "=",
5081                                         STRLENOF( SUFFIXMSTR "=" ) ) )
5082                 {
5083                         struct berval   bv;
5084                         int             rc;
5085
5086                         val = c->argv[ i ] + STRLENOF( SUFFIXMSTR "=" );
5087                         if ( si->si_suffixm.bv_val ) {
5088                                 ch_free( si->si_suffixm.bv_val );
5089                         }
5090                         ber_str2bv( val, 0, 0, &bv );
5091                         rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_suffixm, NULL );
5092                         if ( rc != LDAP_SUCCESS ) {
5093                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
5094                                         "Invalid massage DN \"%s\": %d (%s)",
5095                                         val, rc, ldap_err2string( rc ) );
5096                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5097                                 return -1;
5098                         }
5099                         if ( !be_issubordinate( c->be, &si->si_suffixm )) {
5100                                 ch_free( si->si_suffixm.bv_val );
5101                                 BER_BVZERO( &si->si_suffixm );
5102                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
5103                                         "Massage DN \"%s\" is not within the database naming context",
5104                                         val );
5105                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5106                                 return -1;
5107                         }
5108                         si->si_got |= GOT_SUFFIXM;
5109 #endif
5110                 } else if ( !strncasecmp( c->argv[ i ], LOGBASESTR "=",
5111                                         STRLENOF( LOGBASESTR "=" ) ) )
5112                 {
5113                         struct berval   bv;
5114                         int             rc;
5115
5116                         val = c->argv[ i ] + STRLENOF( LOGBASESTR "=" );
5117                         if ( si->si_logbase.bv_val ) {
5118                                 ch_free( si->si_logbase.bv_val );
5119                         }
5120                         ber_str2bv( val, 0, 0, &bv );
5121                         rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_logbase, NULL );
5122                         if ( rc != LDAP_SUCCESS ) {
5123                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
5124                                         "Invalid logbase DN \"%s\": %d (%s)",
5125                                         val, rc, ldap_err2string( rc ) );
5126                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5127                                 return -1;
5128                         }
5129                         si->si_got |= GOT_LOGBASE;
5130                 } else if ( !strncasecmp( c->argv[ i ], SCOPESTR "=",
5131                                         STRLENOF( SCOPESTR "=" ) ) )
5132                 {
5133                         int j;
5134                         val = c->argv[ i ] + STRLENOF( SCOPESTR "=" );
5135                         j = ldap_pvt_str2scope( val );
5136                         if ( j < 0 ) {
5137                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
5138                                         "Error: parse_syncrepl_line: "
5139                                         "unknown scope \"%s\"", val);
5140                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5141                                 return -1;
5142                         }
5143                         si->si_scope = j;
5144                         si->si_got |= GOT_SCOPE;
5145                 } else if ( !strncasecmp( c->argv[ i ], ATTRSONLYSTR,
5146                                         STRLENOF( ATTRSONLYSTR ) ) )
5147                 {
5148                         si->si_attrsonly = 1;
5149                         si->si_got |= GOT_ATTRSONLY;
5150                 } else if ( !strncasecmp( c->argv[ i ], ATTRSSTR "=",
5151                                         STRLENOF( ATTRSSTR "=" ) ) )
5152                 {
5153                         val = c->argv[ i ] + STRLENOF( ATTRSSTR "=" );
5154                         if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) {
5155                                 char *attr_fname;
5156                                 attr_fname = ch_strdup( val + STRLENOF(":include:") );
5157                                 si->si_anlist = file2anlist( si->si_anlist, attr_fname, " ,\t" );
5158                                 if ( si->si_anlist == NULL ) {
5159                                         ch_free( attr_fname );
5160                                         return -1;
5161                                 }
5162                                 si->si_anfile = attr_fname;
5163                         } else {
5164                                 char *str, *s, *next;
5165                                 const char *delimstr = " ,\t";
5166                                 str = ch_strdup( val );
5167                                 for ( s = ldap_pvt_strtok( str, delimstr, &next );
5168                                                 s != NULL;
5169                                                 s = ldap_pvt_strtok( NULL, delimstr, &next ) )
5170                                 {
5171                                         if ( strlen(s) == 1 && *s == '*' ) {
5172                                                 si->si_allattrs = 1;
5173                                                 val[ s - str ] = delimstr[0];
5174                                         }
5175                                         if ( strlen(s) == 1 && *s == '+' ) {
5176                                                 si->si_allopattrs = 1;
5177                                                 val [ s - str ] = delimstr[0];
5178                                         }
5179                                 }
5180                                 ch_free( str );
5181                                 si->si_anlist = str2anlist( si->si_anlist, val, " ,\t" );
5182                                 if ( si->si_anlist == NULL ) {
5183                                         return -1;
5184                                 }
5185                         }
5186                         si->si_got |= GOT_ATTRS;
5187                 } else if ( !strncasecmp( c->argv[ i ], EXATTRSSTR "=",
5188                                         STRLENOF( EXATTRSSTR "=" ) ) )
5189                 {
5190                         val = c->argv[ i ] + STRLENOF( EXATTRSSTR "=" );
5191                         if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) {
5192                                 char *attr_fname;
5193                                 attr_fname = ch_strdup( val + STRLENOF(":include:") );
5194                                 si->si_exanlist = file2anlist(
5195                                         si->si_exanlist, attr_fname, " ,\t" );
5196                                 if ( si->si_exanlist == NULL ) {
5197                                         ch_free( attr_fname );
5198                                         return -1;
5199                                 }
5200                                 ch_free( attr_fname );
5201                         } else {
5202                                 si->si_exanlist = str2anlist( si->si_exanlist, val, " ,\t" );
5203                                 if ( si->si_exanlist == NULL ) {
5204                                         return -1;
5205                                 }
5206                         }
5207                         si->si_got |= GOT_EXATTRS;
5208                 } else if ( !strncasecmp( c->argv[ i ], TYPESTR "=",
5209                                         STRLENOF( TYPESTR "=" ) ) )
5210                 {
5211                         val = c->argv[ i ] + STRLENOF( TYPESTR "=" );
5212                         if ( !strncasecmp( val, "refreshOnly",
5213                                                 STRLENOF("refreshOnly") ) )
5214                         {
5215                                 si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_ONLY;
5216                         } else if ( !strncasecmp( val, "refreshAndPersist",
5217                                                 STRLENOF("refreshAndPersist") ) )
5218                         {
5219                                 si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_AND_PERSIST;
5220                                 si->si_interval = 60;
5221                         } else {
5222                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
5223                                         "Error: parse_syncrepl_line: "
5224                                         "unknown sync type \"%s\"", val);
5225                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5226                                 return -1;
5227                         }
5228                         si->si_got |= GOT_TYPE;
5229                 } else if ( !strncasecmp( c->argv[ i ], INTERVALSTR "=",
5230                                         STRLENOF( INTERVALSTR "=" ) ) )
5231                 {
5232                         val = c->argv[ i ] + STRLENOF( INTERVALSTR "=" );
5233                         if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
5234                                 si->si_interval = 0;
5235                         } else if ( strchr( val, ':' ) != NULL ) {
5236                                 char *next, *ptr = val;
5237                                 int dd, hh, mm, ss;
5238
5239                                 dd = strtol( ptr, &next, 10 );
5240                                 if ( next == ptr || next[0] != ':' || dd < 0 ) {
5241                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
5242                                                 "Error: parse_syncrepl_line: "
5243                                                 "invalid interval \"%s\", unable to parse days", val );
5244                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5245                                         return -1;
5246                                 }
5247                                 ptr = next + 1;
5248                                 hh = strtol( ptr, &next, 10 );
5249                                 if ( next == ptr || next[0] != ':' || hh < 0 || hh > 24 ) {
5250                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
5251                                                 "Error: parse_syncrepl_line: "
5252                                                 "invalid interval \"%s\", unable to parse hours", val );
5253                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5254                                         return -1;
5255                                 }
5256                                 ptr = next + 1;
5257                                 mm = strtol( ptr, &next, 10 );
5258                                 if ( next == ptr || next[0] != ':' || mm < 0 || mm > 60 ) {
5259                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
5260                                                 "Error: parse_syncrepl_line: "
5261                                                 "invalid interval \"%s\", unable to parse minutes", val );
5262                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5263                                         return -1;
5264                                 }
5265                                 ptr = next + 1;
5266                                 ss = strtol( ptr, &next, 10 );
5267                                 if ( next == ptr || next[0] != '\0' || ss < 0 || ss > 60 ) {
5268                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
5269                                                 "Error: parse_syncrepl_line: "
5270                                                 "invalid interval \"%s\", unable to parse seconds", val );
5271                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5272                                         return -1;
5273                                 }
5274                                 si->si_interval = (( dd * 24 + hh ) * 60 + mm ) * 60 + ss;
5275                         } else {
5276                                 unsigned long   t;
5277
5278                                 if ( lutil_parse_time( val, &t ) != 0 ) {
5279                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
5280                                                 "Error: parse_syncrepl_line: "
5281                                                 "invalid interval \"%s\"", val );
5282                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5283                                         return -1;
5284                                 }
5285                                 si->si_interval = (time_t)t;
5286                         }
5287                         if ( si->si_interval < 0 ) {
5288                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
5289                                         "Error: parse_syncrepl_line: "
5290                                         "invalid interval \"%ld\"",
5291                                         (long) si->si_interval);
5292                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5293                                 return -1;
5294                         }
5295                         si->si_got |= GOT_INTERVAL;
5296                 } else if ( !strncasecmp( c->argv[ i ], RETRYSTR "=",
5297                                         STRLENOF( RETRYSTR "=" ) ) )
5298                 {
5299                         if ( parse_syncrepl_retry( c, c->argv[ i ], si ) ) {
5300                                 return 1;
5301                         }
5302                 } else if ( !strncasecmp( c->argv[ i ], MANAGEDSAITSTR "=",
5303                                         STRLENOF( MANAGEDSAITSTR "=" ) ) )
5304                 {
5305                         val = c->argv[ i ] + STRLENOF( MANAGEDSAITSTR "=" );
5306                         if ( lutil_atoi( &si->si_manageDSAit, val ) != 0
5307                                 || si->si_manageDSAit < 0 || si->si_manageDSAit > 1 )
5308                         {
5309                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
5310                                         "invalid manageDSAit value \"%s\".\n",
5311                                         val );
5312                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5313                                 return 1;
5314                         }
5315                         si->si_got |= GOT_MANAGEDSAIT;
5316                 } else if ( !strncasecmp( c->argv[ i ], SLIMITSTR "=",
5317                                         STRLENOF( SLIMITSTR "=") ) )
5318                 {
5319                         val = c->argv[ i ] + STRLENOF( SLIMITSTR "=" );
5320                         if ( strcasecmp( val, "unlimited" ) == 0 ) {
5321                                 si->si_slimit = 0;
5322
5323                         } else if ( lutil_atoi( &si->si_slimit, val ) != 0 || si->si_slimit < 0 ) {
5324                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
5325                                         "invalid size limit value \"%s\".\n",
5326                                         val );
5327                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5328                                 return 1;
5329                         }
5330                         si->si_got |= GOT_SLIMIT;
5331                 } else if ( !strncasecmp( c->argv[ i ], TLIMITSTR "=",
5332                                         STRLENOF( TLIMITSTR "=" ) ) )
5333                 {
5334                         val = c->argv[ i ] + STRLENOF( TLIMITSTR "=" );
5335                         if ( strcasecmp( val, "unlimited" ) == 0 ) {
5336                                 si->si_tlimit = 0;
5337
5338                         } else if ( lutil_atoi( &si->si_tlimit, val ) != 0 || si->si_tlimit < 0 ) {
5339                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
5340                                         "invalid time limit value \"%s\".\n",
5341                                         val );
5342                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5343                                 return 1;
5344                         }
5345                         si->si_got |= GOT_TLIMIT;
5346                 } else if ( !strncasecmp( c->argv[ i ], SYNCDATASTR "=",
5347                                         STRLENOF( SYNCDATASTR "=" ) ) )
5348                 {
5349                         val = c->argv[ i ] + STRLENOF( SYNCDATASTR "=" );
5350                         si->si_syncdata = verb_to_mask( val, datamodes );
5351                         si->si_got |= GOT_SYNCDATA;
5352                 } else if ( !strncasecmp( c->argv[ i ], STRICT_REFRESH,
5353                                         STRLENOF( STRICT_REFRESH ) ) )
5354                 {
5355                         si->si_strict_refresh = 1;
5356                 } else if ( !strncasecmp( c->argv[ i ], LAZY_COMMIT,
5357                                         STRLENOF( LAZY_COMMIT ) ) )
5358                 {
5359                         si->si_lazyCommit = 1;
5360                 } else if ( !bindconf_parse( c->argv[i], &si->si_bindconf ) ) {
5361                         si->si_got |= GOT_BINDCONF;
5362                 } else {
5363                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
5364                                 "Error: parse_syncrepl_line: "
5365                                 "unable to parse \"%s\"\n", c->argv[ i ] );
5366                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5367                         return -1;
5368                 }
5369         }
5370
5371         if ( ( si->si_got & GOT_REQUIRED ) != GOT_REQUIRED ) {
5372                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
5373                         "Error: Malformed \"syncrepl\" line in slapd config file, missing%s%s%s",
5374                         si->si_got & GOT_RID ? "" : " "IDSTR,
5375                         si->si_got & GOT_PROVIDER ? "" : " "PROVIDERSTR,
5376                         si->si_got & GOT_SEARCHBASE ? "" : " "SEARCHBASESTR );
5377                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5378                 return -1;
5379         }
5380
5381         if ( !be_issubordinate( c->be, &si->si_base ) && !( si->si_got & GOT_SUFFIXM )) {
5382                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
5383                         "Base DN \"%s\" is not within the database naming context",
5384                         si->si_base.bv_val );
5385                 ch_free( si->si_base.bv_val );
5386                 BER_BVZERO( &si->si_base );
5387                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5388                 return -1;
5389         }
5390
5391 #ifdef ENABLE_REWRITE
5392         if ( si->si_got & GOT_SUFFIXM ) {
5393                 if (config_suffixm( c, si )) {
5394                         ch_free( si->si_suffixm.bv_val );
5395                         BER_BVZERO( &si->si_suffixm );
5396                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
5397                                 "Error configuring rewrite engine" );
5398                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
5399                         return -1;
5400                 }
5401         }
5402 #endif
5403
5404         if ( !( si->si_got & GOT_RETRY ) ) {
5405                 Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": no retry defined, using default\n", 
5406                         si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", 0 );
5407                 if ( si->si_retryinterval == NULL ) {
5408                         if ( parse_syncrepl_retry( c, "retry=undefined", si ) ) {
5409                                 return 1;
5410                         }
5411                 }
5412         }
5413
5414         si->si_filter = str2filter( si->si_filterstr.bv_val );
5415         if ( si->si_filter == NULL ) {
5416                 Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse filter=\"%s\"\n", 
5417                         si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_filterstr.bv_val );
5418                 return 1;
5419         }
5420
5421         if ( si->si_got & GOT_LOGFILTER ) {
5422                 si->si_logfilter = str2filter( si->si_logfilterstr.bv_val );
5423                 if ( si->si_logfilter == NULL ) {
5424                         Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse logfilter=\"%s\"\n", 
5425                                 si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_logfilterstr.bv_val );
5426                         return 1;
5427                 }
5428         }
5429
5430         return 0;
5431 }
5432
5433 static int
5434 add_syncrepl(
5435         ConfigArgs *c )
5436 {
5437         syncinfo_t *si;
5438         int     rc = 0;
5439
5440         if ( !( c->be->be_search && c->be->be_add && c->be->be_modify && c->be->be_delete ) ) {
5441                 snprintf( c->cr_msg, sizeof(c->cr_msg), "database %s does not support "
5442                         "operations required for syncrepl", c->be->be_type );
5443                 Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg, 0 );
5444                 return 1;
5445         }
5446         if ( BER_BVISEMPTY( &c->be->be_rootdn ) ) {
5447                 strcpy( c->cr_msg, "rootDN must be defined before syncrepl may be used" );
5448                 Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg, 0 );
5449                 return 1;
5450         }
5451         si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) );
5452
5453         if ( si == NULL ) {
5454                 Debug( LDAP_DEBUG_ANY, "out of memory in add_syncrepl\n", 0, 0, 0 );
5455                 return 1;
5456         }
5457
5458         si->si_bindconf.sb_tls = SB_TLS_OFF;
5459         si->si_bindconf.sb_method = LDAP_AUTH_SIMPLE;
5460         si->si_schemachecking = 0;
5461         ber_str2bv( "(objectclass=*)", STRLENOF("(objectclass=*)"), 1,
5462                 &si->si_filterstr );
5463         si->si_base.bv_val = NULL;
5464         si->si_scope = LDAP_SCOPE_SUBTREE;
5465         si->si_attrsonly = 0;
5466         si->si_anlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ) );
5467         si->si_exanlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ) );
5468         si->si_attrs = NULL;
5469         si->si_allattrs = 0;
5470         si->si_allopattrs = 0;
5471         si->si_exattrs = NULL;
5472         si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_ONLY;
5473         si->si_interval = 86400;
5474         si->si_retryinterval = NULL;
5475         si->si_retrynum_init = NULL;
5476         si->si_retrynum = NULL;
5477         si->si_manageDSAit = 0;
5478         si->si_tlimit = 0;
5479         si->si_slimit = 0;
5480
5481         si->si_presentlist = NULL;
5482         LDAP_LIST_INIT( &si->si_nonpresentlist );
5483         ldap_pvt_thread_mutex_init( &si->si_mutex );
5484
5485         rc = parse_syncrepl_line( c, si );
5486
5487         if ( rc == 0 ) {
5488                 LDAPURLDesc *lud;
5489
5490                 /* Must be LDAPv3 because we need controls */
5491                 switch ( si->si_bindconf.sb_version ) {
5492                 case 0:
5493                         /* not explicitly set */
5494                         si->si_bindconf.sb_version = LDAP_VERSION3;
5495                         break;
5496                 case 3:
5497                         /* explicitly set */
5498                         break;
5499                 default:
5500                         Debug( LDAP_DEBUG_ANY,
5501                                 "version %d incompatible with syncrepl\n",
5502                                 si->si_bindconf.sb_version, 0, 0 );
5503                         syncinfo_free( si, 0 ); 
5504                         return 1;
5505                 }
5506
5507                 if ( ldap_url_parse( si->si_bindconf.sb_uri.bv_val, &lud )) {
5508                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
5509                                 "<%s> invalid URL", c->argv[0] );
5510                         Debug( LDAP_DEBUG_ANY, "%s: %s %s\n",
5511                                 c->log, c->cr_msg, si->si_bindconf.sb_uri.bv_val );
5512                         return 1;
5513                 }
5514
5515                 si->si_be = c->be;
5516                 if ( slapMode & SLAP_SERVER_MODE ) {
5517                         int isMe = 0;
5518                         /* check if consumer points to current server and database.
5519                          * If so, ignore this configuration.
5520                          */
5521                         if ( !SLAP_DBHIDDEN( c->be ) ) {
5522                                 int i;
5523                                 /* if searchbase doesn't match current DB suffix,
5524                                  * assume it's different
5525                                  */
5526                                 for ( i=0; !BER_BVISNULL( &c->be->be_nsuffix[i] ); i++ ) {
5527                                         if ( bvmatch( &si->si_base, &c->be->be_nsuffix[i] )) {
5528                                                 isMe = 1;
5529                                                 break;
5530                                         }
5531                                 }
5532                                 /* if searchbase matches, see if URLs match */
5533                                 if ( isMe && config_check_my_url( si->si_bindconf.sb_uri.bv_val,
5534                                                 lud ) == NULL )
5535                                         isMe = 0;
5536                         }
5537
5538                         if ( !isMe ) {
5539                                 init_syncrepl( si );
5540                                 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
5541                                 si->si_re = ldap_pvt_runqueue_insert( &slapd_rq,
5542                                         si->si_interval, do_syncrepl, si, "do_syncrepl",
5543                                         si->si_ridtxt );
5544                                 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
5545                                 if ( si->si_re )
5546                                         rc = config_sync_shadow( c ) ? -1 : 0;
5547                                 else
5548                                         rc = -1;
5549                         }
5550                 } else {
5551                         /* mirrormode still needs to see this flag in tool mode */
5552                         rc = config_sync_shadow( c ) ? -1 : 0;
5553                 }
5554                 ldap_free_urldesc( lud );
5555         }
5556
5557 #ifdef HAVE_TLS
5558         /* Use main slapd defaults */
5559         bindconf_tls_defaults( &si->si_bindconf );
5560 #endif
5561         if ( rc < 0 ) {
5562                 Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n", 0, 0, 0 );
5563                 syncinfo_free( si, 0 ); 
5564                 return 1;
5565         } else {
5566                 Debug( LDAP_DEBUG_CONFIG,
5567                         "Config: ** successfully added syncrepl %s \"%s\"\n",
5568                         si->si_ridtxt,
5569                         BER_BVISNULL( &si->si_bindconf.sb_uri ) ?
5570                         "(null)" : si->si_bindconf.sb_uri.bv_val, 0 );
5571                 if ( c->be->be_syncinfo ) {
5572                         syncinfo_t *sip;
5573
5574                         si->si_cookieState = c->be->be_syncinfo->si_cookieState;
5575
5576                         /* add new syncrepl to end of list (same order as when deleting) */
5577                         for ( sip = c->be->be_syncinfo; sip->si_next; sip = sip->si_next );
5578                         sip->si_next = si;
5579                 } else {
5580                         si->si_cookieState = ch_calloc( 1, sizeof( cookie_state ));
5581                         ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_mutex );
5582                         ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_pmutex );
5583                         ldap_pvt_thread_cond_init( &si->si_cookieState->cs_cond );
5584
5585                         c->be->be_syncinfo = si;
5586                 }
5587                 si->si_cookieState->cs_ref++;
5588
5589                 si->si_next = NULL;
5590
5591                 return 0;
5592         }
5593 }
5594
5595 static void
5596 syncrepl_unparse( syncinfo_t *si, struct berval *bv )
5597 {
5598         struct berval bc, uri, bs;
5599         char buf[BUFSIZ*2], *ptr;
5600         ber_len_t len;
5601         int i;
5602 #       define WHATSLEFT        ((ber_len_t) (&buf[sizeof( buf )] - ptr))
5603
5604         BER_BVZERO( bv );
5605
5606         /* temporarily inhibit bindconf from printing URI */
5607         uri = si->si_bindconf.sb_uri;
5608         BER_BVZERO( &si->si_bindconf.sb_uri );
5609         si->si_bindconf.sb_version = 0;
5610         bindconf_unparse( &si->si_bindconf, &bc );
5611         si->si_bindconf.sb_uri = uri;
5612         si->si_bindconf.sb_version = LDAP_VERSION3;
5613
5614         ptr = buf;
5615         assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_RID_MAX );
5616         len = snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
5617                 si->si_rid, si->si_bindconf.sb_uri.bv_val );
5618         if ( len >= sizeof( buf ) ) return;
5619         ptr += len;
5620         if ( !BER_BVISNULL( &bc ) ) {
5621                 if ( WHATSLEFT <= bc.bv_len ) {
5622                         free( bc.bv_val );
5623                         return;
5624                 }
5625                 ptr = lutil_strcopy( ptr, bc.bv_val );
5626                 free( bc.bv_val );
5627         }
5628         if ( !BER_BVISEMPTY( &si->si_filterstr ) ) {
5629                 if ( WHATSLEFT <= STRLENOF( " " FILTERSTR "=\"" "\"" ) + si->si_filterstr.bv_len ) return;
5630                 ptr = lutil_strcopy( ptr, " " FILTERSTR "=\"" );
5631                 ptr = lutil_strcopy( ptr, si->si_filterstr.bv_val );
5632                 *ptr++ = '"';
5633         }
5634         if ( !BER_BVISNULL( &si->si_base ) ) {
5635                 if ( WHATSLEFT <= STRLENOF( " " SEARCHBASESTR "=\"" "\"" ) + si->si_base.bv_len ) return;
5636                 ptr = lutil_strcopy( ptr, " " SEARCHBASESTR "=\"" );
5637                 ptr = lutil_strcopy( ptr, si->si_base.bv_val );
5638                 *ptr++ = '"';
5639         }
5640 #ifdef ENABLE_REWRITE
5641         if ( !BER_BVISNULL( &si->si_suffixm ) ) {
5642                 if ( WHATSLEFT <= STRLENOF( " " SUFFIXMSTR "=\"" "\"" ) + si->si_suffixm.bv_len ) return;
5643                 ptr = lutil_strcopy( ptr, " " SUFFIXMSTR "=\"" );
5644                 ptr = lutil_strcopy( ptr, si->si_suffixm.bv_val );
5645                 *ptr++ = '"';
5646         }
5647 #endif
5648         if ( !BER_BVISEMPTY( &si->si_logfilterstr ) ) {
5649                 if ( WHATSLEFT <= STRLENOF( " " LOGFILTERSTR "=\"" "\"" ) + si->si_logfilterstr.bv_len ) return;
5650                 ptr = lutil_strcopy( ptr, " " LOGFILTERSTR "=\"" );
5651                 ptr = lutil_strcopy( ptr, si->si_logfilterstr.bv_val );
5652                 *ptr++ = '"';
5653         }
5654         if ( !BER_BVISNULL( &si->si_logbase ) ) {
5655                 if ( WHATSLEFT <= STRLENOF( " " LOGBASESTR "=\"" "\"" ) + si->si_logbase.bv_len ) return;
5656                 ptr = lutil_strcopy( ptr, " " LOGBASESTR "=\"" );
5657                 ptr = lutil_strcopy( ptr, si->si_logbase.bv_val );
5658                 *ptr++ = '"';
5659         }
5660         if ( ldap_pvt_scope2bv( si->si_scope, &bs ) == LDAP_SUCCESS ) {
5661                 if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + bs.bv_len ) return;
5662                 ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
5663                 ptr = lutil_strcopy( ptr, bs.bv_val );
5664         }
5665         if ( si->si_attrsonly ) {
5666                 if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
5667                 ptr = lutil_strcopy( ptr, " " ATTRSONLYSTR );
5668         }
5669         if ( si->si_anfile ) {
5670                 if ( WHATSLEFT <= STRLENOF( " " ATTRSSTR "=\":include:" "\"" ) + strlen( si->si_anfile ) ) return;
5671                 ptr = lutil_strcopy( ptr, " " ATTRSSTR "=:include:\"" );
5672                 ptr = lutil_strcopy( ptr, si->si_anfile );
5673                 *ptr++ = '"';
5674         } else if ( si->si_allattrs || si->si_allopattrs ||
5675                 ( si->si_anlist && !BER_BVISNULL(&si->si_anlist[0].an_name) ) )
5676         {
5677                 char *old;
5678
5679                 if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
5680                 ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" );
5681                 old = ptr;
5682                 ptr = anlist_unparse( si->si_anlist, ptr, WHATSLEFT );
5683                 if ( ptr == NULL ) return;
5684                 if ( si->si_allattrs ) {
5685                         if ( WHATSLEFT <= STRLENOF( ",*\"" ) ) return;
5686                         if ( old != ptr ) *ptr++ = ',';
5687                         *ptr++ = '*';
5688                 }
5689                 if ( si->si_allopattrs ) {
5690                         if ( WHATSLEFT <= STRLENOF( ",+\"" ) ) return;
5691                         if ( old != ptr ) *ptr++ = ',';
5692                         *ptr++ = '+';
5693                 }
5694                 *ptr++ = '"';
5695         }
5696         if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) {
5697                 if ( WHATSLEFT <= STRLENOF( " " EXATTRSSTR "=" ) ) return;
5698                 ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" );
5699                 ptr = anlist_unparse( si->si_exanlist, ptr, WHATSLEFT );
5700                 if ( ptr == NULL ) return;
5701         }
5702         if ( WHATSLEFT <= STRLENOF( " " SCHEMASTR "=" ) + STRLENOF( "off" ) ) return;
5703         ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" );
5704         ptr = lutil_strcopy( ptr, si->si_schemachecking ? "on" : "off" );
5705         
5706         if ( WHATSLEFT <= STRLENOF( " " TYPESTR "=" ) + STRLENOF( "refreshAndPersist" ) ) return;
5707         ptr = lutil_strcopy( ptr, " " TYPESTR "=" );
5708         ptr = lutil_strcopy( ptr, si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ?
5709                 "refreshAndPersist" : "refreshOnly" );
5710
5711         if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
5712                 int dd, hh, mm, ss;
5713
5714                 dd = si->si_interval;
5715                 ss = dd % 60;
5716                 dd /= 60;
5717                 mm = dd % 60;
5718                 dd /= 60;
5719                 hh = dd % 24;
5720                 dd /= 24;
5721                 len = snprintf( ptr, WHATSLEFT, " %s=%02d:%02d:%02d:%02d",
5722                         INTERVALSTR, dd, hh, mm, ss );
5723                 if ( len >= WHATSLEFT ) return;
5724                 ptr += len;
5725         }
5726
5727         if ( si->si_got & GOT_RETRY ) {
5728                 const char *space = "";
5729                 if ( WHATSLEFT <= STRLENOF( " " RETRYSTR "=\"" "\"" ) ) return;
5730                 ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" );
5731                 for (i=0; si->si_retryinterval[i]; i++) {
5732                         len = snprintf( ptr, WHATSLEFT, "%s%ld ", space,
5733                                 (long) si->si_retryinterval[i] );
5734                         space = " ";
5735                         if ( WHATSLEFT - 1 <= len ) return;
5736                         ptr += len;
5737                         if ( si->si_retrynum_init[i] == RETRYNUM_FOREVER )
5738                                 *ptr++ = '+';
5739                         else {
5740                                 len = snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] );
5741                                 if ( WHATSLEFT <= len ) return;
5742                                 ptr += len;
5743                         }
5744                 }
5745                 if ( WHATSLEFT <= STRLENOF( "\"" ) ) return;
5746                 *ptr++ = '"';
5747         } else {
5748                 ptr = lutil_strcopy( ptr, " " RETRYSTR "=undefined" );
5749         }
5750
5751         if ( si->si_slimit ) {
5752                 len = snprintf( ptr, WHATSLEFT, " " SLIMITSTR "=%d", si->si_slimit );
5753                 if ( WHATSLEFT <= len ) return;
5754                 ptr += len;
5755         }
5756
5757         if ( si->si_tlimit ) {
5758                 len = snprintf( ptr, WHATSLEFT, " " TLIMITSTR "=%d", si->si_tlimit );
5759                 if ( WHATSLEFT <= len ) return;
5760                 ptr += len;
5761         }
5762
5763         if ( si->si_syncdata ) {
5764                 if ( enum_to_verb( datamodes, si->si_syncdata, &bc ) >= 0 ) {
5765                         if ( WHATSLEFT <= STRLENOF( " " SYNCDATASTR "=" ) + bc.bv_len ) return;
5766                         ptr = lutil_strcopy( ptr, " " SYNCDATASTR "=" );
5767                         ptr = lutil_strcopy( ptr, bc.bv_val );
5768                 }
5769         }
5770
5771         if ( si->si_lazyCommit ) {
5772                 ptr = lutil_strcopy( ptr, " " LAZY_COMMIT );
5773         }
5774
5775         bc.bv_len = ptr - buf;
5776         bc.bv_val = buf;
5777         ber_dupbv( bv, &bc );
5778 }
5779
5780 int
5781 syncrepl_config( ConfigArgs *c )
5782 {
5783         if (c->op == SLAP_CONFIG_EMIT) {
5784                 if ( c->be->be_syncinfo ) {
5785                         struct berval bv;
5786                         syncinfo_t *si;
5787
5788                         for ( si = c->be->be_syncinfo; si; si=si->si_next ) {
5789                                 syncrepl_unparse( si, &bv ); 
5790                                 ber_bvarray_add( &c->rvalue_vals, &bv );
5791                         }
5792                         return 0;
5793                 }
5794                 return 1;
5795         } else if ( c->op == LDAP_MOD_DELETE ) {
5796                 int isrunning = 0;
5797                 if ( c->be->be_syncinfo ) {
5798                         syncinfo_t *si, **sip;
5799                         int i;
5800
5801                         for ( sip = &c->be->be_syncinfo, i=0; *sip; i++ ) {
5802                                 si = *sip;
5803                                 if ( c->valx == -1 || i == c->valx ) {
5804                                         *sip = si->si_next;
5805                                         si->si_ctype = -1;
5806                                         si->si_next = NULL;
5807                                         /* If the task is currently active, we have to leave
5808                                          * it running. It will exit on its own. This will only
5809                                          * happen when running on the cn=config DB.
5810                                          */
5811                                         if ( si->si_re ) {
5812                                                 if ( si->si_be == c->be || ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
5813                                                         isrunning = 1;
5814                                                 } else {
5815                                                         /* There is no active thread, but we must still
5816                                                          * ensure that no thread is (or will be) queued
5817                                                          * while we removes the task.
5818                                                          */
5819                                                         struct re_s *re = si->si_re;
5820                                                         si->si_re = NULL;
5821
5822                                                         if ( si->si_conn ) {
5823                                                                 connection_client_stop( si->si_conn );
5824                                                                 si->si_conn = NULL;
5825                                                         }
5826
5827                                                         ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
5828                                                         if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) ) {
5829                                                                 ldap_pvt_runqueue_stoptask( &slapd_rq, re );
5830                                                                 isrunning = 1;
5831                                                         }
5832                                                         if ( ldap_pvt_thread_pool_retract( re->pool_cookie ) > 0 )
5833                                                                 isrunning = 0;
5834
5835                                                         ldap_pvt_runqueue_remove( &slapd_rq, re );
5836                                                         ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
5837
5838                                                         ldap_pvt_thread_mutex_unlock( &si->si_mutex );
5839                                                 }
5840                                         }
5841                                         if ( !isrunning ) {
5842                                                 syncinfo_free( si, 0 );
5843                                         }
5844                                         if ( i == c->valx )
5845                                                 break;
5846                                 } else {
5847                                         sip = &si->si_next;
5848                                 }
5849                         }
5850                 }
5851                 if ( !c->be->be_syncinfo ) {
5852                         SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_SHADOW_MASK;
5853                 }
5854                 return 0;
5855         }
5856         if ( SLAP_SLURP_SHADOW( c->be ) ) {
5857                 Debug(LDAP_DEBUG_ANY, "%s: "
5858                         "syncrepl: database already shadowed.\n",
5859                         c->log, 0, 0);
5860                 return(1);
5861         } else {
5862                 return add_syncrepl( c );
5863         }
5864 }