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