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