]> git.sur5r.net Git - openldap/blob - servers/slapd/syncrepl.c
087a7cf46f93716343fc2ab267356a2ce705c3f3
[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-2005 The OpenLDAP Foundation.
6  * Portions Copyright 2003 by IBM Corporation.
7  * Portions Copyright 2003 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 /* FIXME: for ldap_ld_free() */
35 #undef ldap_debug
36 #include "../../libraries/libldap/ldap-int.h"
37
38 struct nonpresent_entry {
39         struct berval *npe_name;
40         struct berval *npe_nname;
41         LDAP_LIST_ENTRY(nonpresent_entry) npe_link;
42 };
43
44 typedef struct syncinfo_s {
45         struct slap_backend_db *si_be;
46         struct re_s                     *si_re;
47         long                            si_rid;
48         struct berval           si_provideruri;
49         slap_bindconf           si_bindconf;
50         struct berval           si_filterstr;
51         struct berval           si_base;
52         int                                     si_scope;
53         int                                     si_attrsonly;
54         char                            *si_anfile;
55         AttributeName           *si_anlist;
56         AttributeName           *si_exanlist;
57         char                            **si_attrs;
58         char                            **si_exattrs;
59         int                                     si_allattrs;
60         int                                     si_allopattrs;
61         int                                     si_schemachecking;
62         int                                     si_type;
63         time_t                          si_interval;
64         time_t                          *si_retryinterval;
65         int                                     *si_retrynum_init;
66         int                                     *si_retrynum;
67         struct sync_cookie      si_syncCookie;
68         int                                     si_manageDSAit;
69         int                                     si_slimit;
70         int                                     si_tlimit;
71         int                                     si_refreshDelete;
72         int                                     si_refreshPresent;
73         Avlnode                         *si_presentlist;
74         LDAP                            *si_ld;
75         LDAP_LIST_HEAD(np, nonpresent_entry) si_nonpresentlist;
76         ldap_pvt_thread_mutex_t si_mutex;
77 } syncinfo_t;
78
79 static int syncuuid_cmp( const void *, const void * );
80 static void avl_ber_bvfree( void * );
81 static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray );
82 static int syncrepl_message_to_entry(
83                                         syncinfo_t *, Operation *, LDAPMessage *,
84                                         Modifications **, Entry **, int );
85 static int syncrepl_entry(
86                                         syncinfo_t *, Operation*, Entry*,
87                                         Modifications**,int, struct berval*,
88                                         struct sync_cookie *,
89                                         struct berval * );
90 static void syncrepl_updateCookie(
91                                         syncinfo_t *, Operation *, struct berval *,
92                                         struct sync_cookie * );
93 static struct berval * slap_uuidstr_from_normalized(
94                                         struct berval *, struct berval *, void * );
95
96 /* callback functions */
97 static int dn_callback( struct slap_op *, struct slap_rep * );
98 static int nonpresent_callback( struct slap_op *, struct slap_rep * );
99 static int null_callback( struct slap_op *, struct slap_rep * );
100
101 static AttributeDescription *sync_descs[4];
102
103 static void
104 init_syncrepl(syncinfo_t *si)
105 {
106         int i, j, k, l, n;
107         char **attrs, **exattrs;
108
109         if ( !sync_descs[0] ) {
110                 sync_descs[0] = slap_schema.si_ad_objectClass;
111                 sync_descs[1] = slap_schema.si_ad_structuralObjectClass;
112                 sync_descs[2] = slap_schema.si_ad_entryCSN;
113                 sync_descs[3] = NULL;
114         }
115
116         if ( si->si_allattrs && si->si_allopattrs )
117                 attrs = NULL;
118         else
119                 attrs = anlist2attrs( si->si_anlist );
120
121         if ( attrs ) {
122                 if ( si->si_allattrs ) {
123                         i = 0;
124                         while ( attrs[i] ) {
125                                 if ( !is_at_operational( at_find( attrs[i] ))) {
126                                         for ( j = i; attrs[j] != NULL; j++ ) {
127                                                 if ( j == i )
128                                                         ch_free( attrs[i] );
129                                                 attrs[j] = attrs[j+1];
130                                         }
131                                 } else {
132                                         i++;
133                                 }
134                         }
135                         attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
136                         attrs[i] = ch_strdup("*");
137                         attrs[i + 1] = NULL;
138
139                 } else if ( si->si_allopattrs ) {
140                         i = 0;
141                         while ( attrs[i] ) {
142                                 if ( is_at_operational( at_find( attrs[i] ))) {
143                                         for ( j = i; attrs[j] != NULL; j++ ) {
144                                                 if ( j == i )
145                                                         ch_free( attrs[i] );
146                                                 attrs[j] = attrs[j+1];
147                                         }
148                                 } else {
149                                         i++;
150                                 }
151                         }
152                         attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) );
153                         attrs[i] = ch_strdup("+");
154                         attrs[i + 1] = NULL;
155                 }
156
157                 for ( i = 0; sync_descs[i] != NULL; i++ ) {
158                         j = 0;
159                         while ( attrs[j] ) {
160                                 if ( !strcmp( attrs[j], sync_descs[i]->ad_cname.bv_val )) {
161                                         for ( k = j; attrs[k] != NULL; k++ ) {
162                                                 if ( k == j )
163                                                         ch_free( attrs[k] );
164                                                 attrs[k] = attrs[k+1];
165                                         }
166                                 } else {
167                                         j++;
168                                 }
169                         }
170                 }
171
172                 for ( n = 0; attrs[ n ] != NULL; n++ ) /* empty */;
173
174                 if ( si->si_allopattrs ) {
175                         attrs = ( char ** ) ch_realloc( attrs, (n + 2)*sizeof( char * ));
176                 } else {
177                         attrs = ( char ** ) ch_realloc( attrs, (n + 4)*sizeof( char * ));
178                 }
179
180                 if ( attrs == NULL ) {
181                         Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
182                 }
183
184                 /* Add Attributes */
185                 if ( si->si_allopattrs ) {
186                         attrs[n++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
187                 } else {
188                         for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
189                                 attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
190                         }
191                 }
192                 attrs[ n ] = NULL;
193
194         } else {
195
196                 i = 0;
197                 if ( si->si_allattrs == si->si_allopattrs ) {
198                         attrs = (char**) ch_malloc( 3 * sizeof(char*) );
199                         attrs[i++] = ch_strdup( "*" );
200                         attrs[i++] = ch_strdup( "+" );
201                 } else if ( si->si_allattrs && !si->si_allopattrs ) {
202                         for ( n = 0; sync_descs[ n ] != NULL; n++ ) ;
203                         attrs = (char**) ch_malloc( (n+1)* sizeof(char*) );
204                         attrs[i++] = ch_strdup( "*" );
205                         for ( j = 1; sync_descs[ j ] != NULL; j++ ) {
206                                 attrs[i++] = ch_strdup ( sync_descs[j]->ad_cname.bv_val );
207                         }
208                 } else if ( !si->si_allattrs && si->si_allopattrs ) {
209                         attrs = (char**) ch_malloc( 3 * sizeof(char*) );
210                         attrs[i++] = ch_strdup( "+" );
211                         attrs[i++] = ch_strdup( sync_descs[0]->ad_cname.bv_val );
212                 }
213                 attrs[i] = NULL;
214         }
215         
216         si->si_attrs = attrs;
217
218         exattrs = anlist2attrs( si->si_exanlist );
219
220         if ( exattrs ) {
221                 for ( n = 0; exattrs[n] != NULL; n++ ) ;
222
223                 for ( i = 0; sync_descs[i] != NULL; i++ ) {
224                         j = 0;
225                         while ( exattrs[j] != NULL ) {
226                                 if ( !strcmp( exattrs[j], sync_descs[i]->ad_cname.bv_val )) {
227                                         for ( k = j; exattrs[k] != NULL; k++ ) {
228                                                 if ( k == j )
229                                                         ch_free( exattrs[k] );
230                                                 exattrs[k] = exattrs[k+1];
231                                         }
232                                 } else {
233                                         j++;
234                                 }
235                         }
236                 }
237
238                 for ( i = 0; exattrs[i] != NULL; i++ ) {
239                         for ( j = 0; si->si_anlist[j].an_name.bv_val; j++ ) {
240                                 ObjectClass     *oc;
241                                 if ( ( oc = si->si_anlist[j].an_oc ) ) {
242                                         k = 0;
243                                         while ( oc->soc_required[k] ) {
244                                                 if ( !strcmp( exattrs[i],
245                                                          oc->soc_required[k]->sat_cname.bv_val )) {
246                                                         for ( l = i; exattrs[l]; l++ ) {
247                                                                 if ( l == i )
248                                                                         ch_free( exattrs[i] );
249                                                                 exattrs[l] = exattrs[l+1];
250                                                         }
251                                                 } else {
252                                                         k++;
253                                                 }
254                                         }
255                                 }
256                         }
257                 }
258
259                 for ( i = 0; exattrs[i] != NULL; i++ ) ;
260
261                 if ( i != n )
262                         exattrs = (char **) ch_realloc( exattrs, (i + 1)*sizeof(char *));
263         }
264
265         si->si_exattrs = exattrs;       
266 }
267
268 static int
269 ldap_sync_search(
270         syncinfo_t *si,
271         void *ctx )
272 {
273         BerElementBuffer berbuf;
274         BerElement *ber = (BerElement *)&berbuf;
275         LDAPControl c[2], *ctrls[3];
276         struct timeval timeout;
277         ber_int_t       msgid;
278         int rc;
279
280         /* setup LDAP SYNC control */
281         ber_init2( ber, NULL, LBER_USE_DER );
282         ber_set_option( ber, LBER_OPT_BER_MEMCTX, &ctx );
283
284         if ( !BER_BVISNULL( &si->si_syncCookie.octet_str ) )
285         {
286                 ber_printf( ber, "{eO}",
287                         abs(si->si_type),
288                         &si->si_syncCookie.octet_str );
289         } else {
290                 ber_printf( ber, "{e}",
291                         abs(si->si_type) );
292         }
293
294         if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 )) == LBER_ERROR ) {
295                 ber_free_buf( ber );
296                 return rc;
297         }
298
299         c[0].ldctl_oid = LDAP_CONTROL_SYNC;
300         c[0].ldctl_iscritical = si->si_type < 0;
301         ctrls[0] = &c[0];
302
303         if ( !BER_BVISNULL( &si->si_bindconf.sb_authzId ) ) {
304                 c[1].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
305                 c[1].ldctl_value = si->si_bindconf.sb_authzId;
306                 c[1].ldctl_iscritical = 1;
307                 ctrls[1] = &c[1];
308                 ctrls[2] = NULL;
309         } else {
310                 ctrls[1] = NULL;
311         }
312
313         timeout.tv_sec = si->si_tlimit;
314         timeout.tv_usec = 0;
315
316         rc = ldap_search_ext( si->si_ld, si->si_base.bv_val, si->si_scope,
317                 si->si_filterstr.bv_val, si->si_attrs, si->si_attrsonly,
318                 ctrls, NULL, si->si_tlimit > 0 ? &timeout : NULL,
319                 si->si_slimit, &msgid );
320         ber_free_buf( ber );
321         return rc;
322 }
323
324 static int
325 do_syncrep1(
326         Operation *op,
327         syncinfo_t *si )
328 {
329         int     rc;
330         int cmdline_cookie_found = 0;
331
332         struct sync_cookie      *sc = NULL;
333         struct berval   *psub;
334 #ifdef HAVE_TLS
335         void    *ssl;
336 #endif
337
338         psub = &si->si_be->be_nsuffix[0];
339
340         /* Init connection to master */
341         rc = ldap_initialize( &si->si_ld, si->si_provideruri.bv_val );
342         if ( rc != LDAP_SUCCESS ) {
343                 Debug( LDAP_DEBUG_ANY,
344                         "do_syncrep1: ldap_initialize failed (%s)\n",
345                         si->si_provideruri.bv_val, 0, 0 );
346                 return rc;
347         }
348
349         op->o_protocol = LDAP_VERSION3;
350         ldap_set_option( si->si_ld, LDAP_OPT_PROTOCOL_VERSION, &op->o_protocol );
351
352         /* Bind to master */
353
354         if ( si->si_bindconf.sb_tls ) {
355                 rc = ldap_start_tls_s( si->si_ld, NULL, NULL );
356                 if( rc != LDAP_SUCCESS ) {
357                         Debug( LDAP_DEBUG_ANY,
358                                 "%s: ldap_start_tls failed (%d)\n",
359                                 si->si_bindconf.sb_tls == SB_TLS_CRITICAL ? "Error" : "Warning",
360                                 rc, 0 );
361                         if( si->si_bindconf.sb_tls == SB_TLS_CRITICAL ) goto done;
362                 }
363         }
364
365         if ( si->si_bindconf.sb_method == LDAP_AUTH_SASL ) {
366 #ifdef HAVE_CYRUS_SASL
367                 void *defaults;
368
369                 if ( si->si_bindconf.sb_secprops != NULL ) {
370                         rc = ldap_set_option( si->si_ld,
371                                 LDAP_OPT_X_SASL_SECPROPS, si->si_bindconf.sb_secprops);
372
373                         if( rc != LDAP_OPT_SUCCESS ) {
374                                 Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
375                                         "(%s,SECPROPS,\"%s\") failed!\n",
376                                         si->si_provideruri.bv_val, si->si_bindconf.sb_secprops, 0 );
377                                 goto done;
378                         }
379                 }
380
381                 defaults = lutil_sasl_defaults( si->si_ld,
382                         si->si_bindconf.sb_saslmech.bv_val,
383                         si->si_bindconf.sb_realm.bv_val,
384                         si->si_bindconf.sb_authcId.bv_val,
385                         si->si_bindconf.sb_cred.bv_val,
386                         si->si_bindconf.sb_authzId.bv_val );
387
388                 rc = ldap_sasl_interactive_bind_s( si->si_ld,
389                                 si->si_bindconf.sb_binddn.bv_val,
390                                 si->si_bindconf.sb_saslmech.bv_val,
391                                 NULL, NULL,
392                                 LDAP_SASL_QUIET,
393                                 lutil_sasl_interact,
394                                 defaults );
395
396                 lutil_sasl_freedefs( defaults );
397
398                 /* FIXME: different error behaviors according to
399                  *      1) return code
400                  *      2) on err policy : exit, retry, backoff ...
401                  */
402                 if ( rc != LDAP_SUCCESS ) {
403                         static struct berval bv_GSSAPI = BER_BVC( "GSSAPI" );
404
405                         Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
406                                 "ldap_sasl_interactive_bind_s failed (%d)\n",
407                                 rc, 0, 0 );
408
409                         /* FIXME (see above comment) */
410                         /* if Kerberos credentials cache is not active, retry */
411                         if ( ber_bvcmp( &si->si_bindconf.sb_saslmech, &bv_GSSAPI ) == 0 &&
412                                 rc == LDAP_LOCAL_ERROR )
413                         {
414                                 rc = LDAP_SERVER_DOWN;
415                         }
416
417                         goto done;
418                 }
419 #else /* HAVE_CYRUS_SASL */
420                 /* Should never get here, we trapped this at config time */
421                 assert(0);
422                 fprintf( stderr, "not compiled with SASL support\n" );
423                 rc = LDAP_OTHER;
424                 goto done;
425 #endif
426
427         } else if ( si->si_bindconf.sb_method == LDAP_AUTH_SIMPLE ) {
428                 rc = ldap_sasl_bind_s( si->si_ld,
429                         si->si_bindconf.sb_binddn.bv_val, LDAP_SASL_SIMPLE,
430                         &si->si_bindconf.sb_cred, NULL, NULL, NULL );
431                 if ( rc != LDAP_SUCCESS ) {
432                         Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
433                                 "ldap_sasl_bind_s failed (%d)\n", rc, 0, 0 );
434                         goto done;
435                 }
436         }
437
438         /* Set SSF to strongest of TLS, SASL SSFs */
439         op->o_sasl_ssf = 0;
440         op->o_tls_ssf = 0;
441         op->o_transport_ssf = 0;
442 #ifdef HAVE_TLS
443         if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl )
444                 == LDAP_SUCCESS && ssl != NULL )
445         {
446                 op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
447         }
448 #endif /* HAVE_TLS */
449         ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &op->o_sasl_ssf );
450         op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
451                 ?  op->o_sasl_ssf : op->o_tls_ssf;
452
453
454         if ( BER_BVISNULL( &si->si_syncCookie.octet_str )) {
455                 /* get contextCSN shadow replica from database */
456                 BerVarray csn = NULL;
457
458                 assert( si->si_rid < 1000 );
459                 op->o_req_ndn = op->o_bd->be_nsuffix[0];
460                 op->o_req_dn = op->o_req_ndn;
461
462                 /* try to read stored contextCSN */
463                 backend_attribute( op, NULL, &op->o_req_ndn,
464                         slap_schema.si_ad_contextCSN, &csn, ACL_READ );
465                 if ( csn ) {
466                         ch_free( si->si_syncCookie.ctxcsn.bv_val );
467                         ber_dupbv( &si->si_syncCookie.ctxcsn, csn );
468                         ber_bvarray_free_x( csn, op->o_tmpmemctx );
469                 }
470
471                 si->si_syncCookie.rid = si->si_rid;
472
473                 LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) {
474                         if ( si->si_rid == sc->rid ) {
475                                 cmdline_cookie_found = 1;
476                                 break;
477                         }
478                 }
479
480                 if ( cmdline_cookie_found ) {
481                         /* cookie is supplied in the command line */
482
483                         LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );
484
485                         if ( BER_BVISNULL( &sc->ctxcsn ) ) {
486                                 /* if cmdline cookie does not have ctxcsn */
487                                 /* component, set it to an initial value */
488                                 slap_init_sync_cookie_ctxcsn( sc );
489                         }
490                         slap_sync_cookie_free( &si->si_syncCookie, 0 );
491                         slap_dup_sync_cookie( &si->si_syncCookie, sc );
492                         slap_sync_cookie_free( sc, 1 );
493                 }
494
495                 slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
496                         &si->si_syncCookie.ctxcsn, si->si_syncCookie.rid );
497         }
498
499         rc = ldap_sync_search( si, op->o_tmpmemctx );
500
501         if( rc != LDAP_SUCCESS ) {
502                 Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
503                         "ldap_search_ext: %s (%d)\n", ldap_err2string( rc ), rc, 0 );
504         }
505
506 done:
507         if ( rc ) {
508                 if ( si->si_ld ) {
509                         ldap_unbind_ext( si->si_ld, NULL, NULL );
510                         si->si_ld = NULL;
511                 }
512         }
513
514         return rc;
515 }
516
517 static int
518 do_syncrep2(
519         Operation *op,
520         syncinfo_t *si )
521 {
522         LDAPControl     **rctrls = NULL;
523         LDAPControl     *rctrlp;
524
525         BerElementBuffer berbuf;
526         BerElement      *ber = (BerElement *)&berbuf;
527
528         LDAPMessage     *res = NULL;
529         LDAPMessage     *msg = NULL;
530
531         char            *retoid = NULL;
532         struct berval   *retdata = NULL;
533
534         Entry           *entry = NULL;
535
536         int             syncstate;
537         struct berval   syncUUID = BER_BVNULL;
538         struct sync_cookie      syncCookie = { BER_BVNULL };
539         struct sync_cookie      syncCookie_req = { BER_BVNULL };
540         struct berval           cookie = BER_BVNULL;
541
542         int     rc, err, i;
543         ber_len_t       len;
544
545         int rc_efree = 1;
546
547         struct berval   *psub;
548         Modifications   *modlist = NULL;
549
550         const char              *text;
551         int                             match;
552
553         struct timeval *tout_p = NULL;
554         struct timeval tout = { 0, 0 };
555
556         int             refreshDeletes = 0;
557         int             refreshDone = 1;
558         BerVarray syncUUIDs = NULL;
559         ber_tag_t si_tag;
560
561         if ( slapd_shutdown ) {
562                 rc = -2;
563                 goto done;
564         }
565
566         ber_init2( ber, NULL, LBER_USE_DER );
567         ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
568
569         Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2\n", 0, 0, 0 );
570
571         psub = &si->si_be->be_nsuffix[0];
572
573         slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
574
575         if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
576                 tout_p = &tout;
577         } else {
578                 tout_p = NULL;
579         }
580
581         while (( rc = ldap_result( si->si_ld, LDAP_RES_ANY, LDAP_MSG_ONE,
582                 tout_p, &res )) > 0 )
583         {
584                 if ( slapd_shutdown ) {
585                         rc = -2;
586                         goto done;
587                 }
588                 for( msg = ldap_first_message( si->si_ld, res );
589                         msg != NULL;
590                         msg = ldap_next_message( si->si_ld, msg ) )
591                 {
592                         if ( slapd_shutdown ) {
593                                 rc = -2;
594                                 goto done;
595                         }
596                         switch( ldap_msgtype( msg ) ) {
597                         case LDAP_RES_SEARCH_ENTRY:
598                                 ldap_get_entry_controls( si->si_ld, msg, &rctrls );
599                                 /* we can't work without the control */
600                                 if ( !rctrls ) {
601                                         Debug( LDAP_DEBUG_ANY, "do_syncrep2: "
602                                                 "got search entry without "
603                                                 "control\n", 0, 0, 0 );
604                                         rc = -1;
605                                         goto done;
606                                 }
607                                 rctrlp = *rctrls;
608                                 ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
609                                 ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID );
610                                 if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
611                                         ber_scanf( ber, /*"{"*/ "m}", &cookie );
612                                         if ( !BER_BVISNULL( &cookie ) ) {
613                                                 ch_free( syncCookie.octet_str.bv_val );
614                                                 ber_dupbv( &syncCookie.octet_str, &cookie );
615                                         }
616                                         if ( !BER_BVISNULL( &syncCookie.octet_str ) )
617                                         {
618                                                 slap_parse_sync_cookie( &syncCookie );
619                                         }
620                                 }
621                                 if ( syncrepl_message_to_entry( si, op, msg,
622                                         &modlist, &entry, syncstate ) == LDAP_SUCCESS ) {
623                                         rc_efree = syncrepl_entry( si, op, entry, &modlist,
624                                                 syncstate, &syncUUID, &syncCookie_req, &syncCookie.ctxcsn );
625                                         if ( !BER_BVISNULL( &syncCookie.octet_str ) )
626                                         {
627                                                 syncrepl_updateCookie( si, op, psub, &syncCookie );
628                                         }
629                                 }
630                                 ldap_controls_free( rctrls );
631                                 if ( modlist ) {
632                                         slap_mods_free( modlist, 1 );
633                                 }
634                                 if ( rc_efree && entry ) {
635                                         entry_free( entry );
636                                 }
637                                 entry = NULL;
638                                 break;
639
640                         case LDAP_RES_SEARCH_REFERENCE:
641                                 Debug( LDAP_DEBUG_ANY,
642                                         "do_syncrep2: reference received error\n", 0, 0, 0 );
643                                 break;
644
645                         case LDAP_RES_SEARCH_RESULT:
646                                 Debug( LDAP_DEBUG_SYNC,
647                                         "do_syncrep2: LDAP_RES_SEARCH_RESULT\n", 0, 0, 0 );
648                                 ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
649                                         &rctrls, 0 );
650                                 if ( rctrls ) {
651                                         rctrlp = *rctrls;
652                                         ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
653
654                                         ber_scanf( ber, "{" /*"}"*/);
655                                         if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
656                                                 ber_scanf( ber, "m", &cookie );
657                                                 if ( !BER_BVISNULL( &cookie ) ) {
658                                                         ch_free( syncCookie.octet_str.bv_val );
659                                                         ber_dupbv( &syncCookie.octet_str, &cookie);
660                                                 }
661                                                 if ( !BER_BVISNULL( &syncCookie.octet_str ) )
662                                                 {
663                                                         slap_parse_sync_cookie( &syncCookie );
664                                                 }
665                                         }
666                                         if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
667                                         {
668                                                 ber_scanf( ber, "b", &refreshDeletes );
669                                         }
670                                         ber_scanf( ber, /*"{"*/ "}" );
671                                 }
672                                 if ( BER_BVISNULL( &syncCookie_req.ctxcsn )) {
673                                         match = -1;
674                                 } else if ( BER_BVISNULL( &syncCookie.ctxcsn )) {
675                                         match = 1;
676                                 } else {
677                                         value_match( &match, slap_schema.si_ad_entryCSN,
678                                                 slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
679                                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
680                                                 &syncCookie_req.ctxcsn, &syncCookie.ctxcsn,
681                                                 &text );
682                                 }
683                                 if ( !BER_BVISNULL( &syncCookie.octet_str ) &&
684                                         match < 0 && err == LDAP_SUCCESS )
685                                 {
686                                         syncrepl_updateCookie( si, op, psub, &syncCookie );
687                                 }
688                                 if ( rctrls ) {
689                                         ldap_controls_free( rctrls );
690                                 }
691                                 if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
692                                         /* FIXME : different error behaviors according to
693                                          *      1) err code : LDAP_BUSY ...
694                                          *      2) on err policy : stop service, stop sync, retry
695                                          */
696                                         if ( refreshDeletes == 0 && match < 0 &&
697                                                 err == LDAP_SUCCESS )
698                                         {
699                                                 syncrepl_del_nonpresent( op, si, NULL );
700                                         } else {
701                                                 avl_free( si->si_presentlist, avl_ber_bvfree );
702                                                 si->si_presentlist = NULL;
703                                         }
704                                 }
705                                 rc = -2;
706                                 goto done;
707                                 break;
708
709                         case LDAP_RES_INTERMEDIATE:
710                                 rc = ldap_parse_intermediate( si->si_ld, msg,
711                                         &retoid, &retdata, NULL, 0 );
712                                 if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
713                                         ber_init2( ber, retdata, LBER_USE_DER );
714
715                                         switch ( si_tag = ber_peek_tag( ber, &len )) {
716                                         ber_tag_t tag;
717                                         case LDAP_TAG_SYNC_NEW_COOKIE:
718                                                 Debug( LDAP_DEBUG_SYNC,
719                                                         "do_syncrep2: %s - %s%s\n", 
720                                                         "LDAP_RES_INTERMEDIATE", 
721                                                         "NEW_COOKIE", "\n" );
722                                                 ber_scanf( ber, "tm", &tag, &cookie );
723                                                 break;
724                                         case LDAP_TAG_SYNC_REFRESH_DELETE:
725                                         case LDAP_TAG_SYNC_REFRESH_PRESENT:
726                                                 Debug( LDAP_DEBUG_SYNC,
727                                                         "do_syncrep2: %s - %s%s\n", 
728                                                         "LDAP_RES_INTERMEDIATE", 
729                                                         si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ?
730                                                         "REFRESH_PRESENT" : "REFRESH_DELETE",
731                                                         "\n" );
732                                                 if ( si_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
733                                                         si->si_refreshDelete = 1;
734                                                 } else {
735                                                         si->si_refreshPresent = 1;
736                                                 }
737                                                 ber_scanf( ber, "t{" /*"}"*/, &tag );
738                                                 if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
739                                                 {
740                                                         ber_scanf( ber, "m", &cookie );
741                                                         if ( !BER_BVISNULL( &cookie ) ) {
742                                                                 ch_free( syncCookie.octet_str.bv_val );
743                                                                 ber_dupbv( &syncCookie.octet_str, &cookie );
744                                                         }
745                                                         if ( !BER_BVISNULL( &syncCookie.octet_str ) )
746                                                         {
747                                                                 slap_parse_sync_cookie( &syncCookie );
748                                                         }
749                                                 }
750                                                 if ( ber_peek_tag( ber, &len ) ==
751                                                         LDAP_TAG_REFRESHDONE )
752                                                 {
753                                                         ber_scanf( ber, "b", &refreshDone );
754                                                 }
755                                                 ber_scanf( ber, /*"{"*/ "}" );
756                                                 break;
757                                         case LDAP_TAG_SYNC_ID_SET:
758                                                 Debug( LDAP_DEBUG_SYNC,
759                                                         "do_syncrep2: %s - %s%s\n", 
760                                                         "LDAP_RES_INTERMEDIATE", 
761                                                         "SYNC_ID_SET",
762                                                         "\n" );
763                                                 ber_scanf( ber, "t{" /*"}"*/, &tag );
764                                                 if ( ber_peek_tag( ber, &len ) ==
765                                                         LDAP_TAG_SYNC_COOKIE )
766                                                 {
767                                                         ber_scanf( ber, "m", &cookie );
768                                                         if ( !BER_BVISNULL( &cookie ) ) {
769                                                                 ch_free( syncCookie.octet_str.bv_val );
770                                                                 ber_dupbv( &syncCookie.octet_str, &cookie );
771                                                         }
772                                                         if ( !BER_BVISNULL( &syncCookie.octet_str ) )
773                                                         {
774                                                                 slap_parse_sync_cookie( &syncCookie );
775                                                         }
776                                                 }
777                                                 if ( ber_peek_tag( ber, &len ) ==
778                                                         LDAP_TAG_REFRESHDELETES )
779                                                 {
780                                                         ber_scanf( ber, "b", &refreshDeletes );
781                                                 }
782                                                 ber_scanf( ber, "[W]", &syncUUIDs );
783                                                 ber_scanf( ber, /*"{"*/ "}" );
784                                                 if ( refreshDeletes ) {
785                                                         syncrepl_del_nonpresent( op, si, syncUUIDs );
786                                                         ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
787                                                 } else {
788                                                         for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
789                                                                 struct berval *syncuuid_bv;
790                                                                 syncuuid_bv = ber_dupbv( NULL, &syncUUIDs[i] );
791                                                                 slap_sl_free( syncUUIDs[i].bv_val,op->o_tmpmemctx );
792                                                                 avl_insert( &si->si_presentlist,
793                                                                         (caddr_t) syncuuid_bv,
794                                                                         syncuuid_cmp, avl_dup_error );
795                                                         }
796                                                         slap_sl_free( syncUUIDs, op->o_tmpmemctx );
797                                                 }
798                                                 break;
799                                         default:
800                                                 Debug( LDAP_DEBUG_ANY,
801                                                         "do_syncrep2 : unknown syncinfo tag (%ld)\n",
802                                                 (long) si_tag, 0, 0 );
803                                                 ldap_memfree( retoid );
804                                                 ber_bvfree( retdata );
805                                                 continue;
806                                         }
807
808                                         if ( BER_BVISNULL( &syncCookie_req.ctxcsn )) {
809                                                 match = -1;
810                                         } else if ( BER_BVISNULL( &syncCookie.ctxcsn )) {
811                                                 match = 1;
812                                         } else {
813                                                 value_match( &match, slap_schema.si_ad_entryCSN,
814                                                         slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
815                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
816                                                         &syncCookie_req.ctxcsn,
817                                                         &syncCookie.ctxcsn, &text );
818                                         }
819
820                                         if ( !BER_BVISNULL( &syncCookie.ctxcsn ) &&
821                                                 match < 0 )
822                                         {
823                                                 syncrepl_updateCookie( si, op, psub, &syncCookie);
824                                         }
825
826                                         if ( si->si_refreshPresent == 1 ) {
827                                                 if ( match < 0 ) {
828                                                         syncrepl_del_nonpresent( op, si, NULL );
829                                                 }
830                                         } 
831
832                                         ldap_memfree( retoid );
833                                         ber_bvfree( retdata );
834                                         break;
835
836                                 } else {
837                                         Debug( LDAP_DEBUG_ANY, "do_syncrep2 : "
838                                                 "unknown intermediate response (%d)\n",
839                                                 rc, 0, 0 );
840                                         ldap_memfree( retoid );
841                                         ber_bvfree( retdata );
842                                         break;
843                                 }
844                                 break;
845
846                         default:
847                                 Debug( LDAP_DEBUG_ANY, "do_syncrep2 : "
848                                         "unknown message\n", 0, 0, 0 );
849                                 break;
850
851                         }
852                         if ( !BER_BVISNULL( &syncCookie.octet_str )) {
853                                 slap_sync_cookie_free( &syncCookie_req, 0 );
854                                 slap_dup_sync_cookie( &syncCookie_req, &syncCookie );
855                                 slap_sync_cookie_free( &syncCookie, 0 );
856                         }
857                 }
858                 ldap_msgfree( res );
859                 res = NULL;
860         }
861
862         if ( rc == -1 ) {
863                 const char *errstr;
864
865                 ldap_get_option( si->si_ld, LDAP_OPT_ERROR_NUMBER, &rc );
866                 errstr = ldap_err2string( rc );
867                 
868                 Debug( LDAP_DEBUG_ANY,
869                         "do_syncrep2 : %s\n", errstr, 0, 0 );
870         }
871
872 done:
873         slap_sync_cookie_free( &syncCookie, 0 );
874         slap_sync_cookie_free( &syncCookie_req, 0 );
875
876         if ( res ) ldap_msgfree( res );
877
878         if ( rc && si->si_ld ) {
879                 ldap_unbind_ext( si->si_ld, NULL, NULL );
880                 si->si_ld = NULL;
881         }
882
883         return rc;
884 }
885
886 static void *
887 do_syncrepl(
888         void    *ctx,
889         void    *arg )
890 {
891         struct re_s* rtask = arg;
892         syncinfo_t *si = ( syncinfo_t * ) rtask->arg;
893         Connection conn = {0};
894         char opbuf[OPERATION_BUFFER_SIZE];
895         Operation *op;
896         int rc = LDAP_SUCCESS;
897         int first = 0;
898         int dostop = 0;
899         ber_socket_t s;
900         int i, defer = 1;
901         Backend *be;
902
903         Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl\n", 0, 0, 0 );
904
905         if ( si == NULL )
906                 return NULL;
907
908         ldap_pvt_thread_mutex_lock( &si->si_mutex );
909
910         switch( abs( si->si_type )) {
911         case LDAP_SYNC_REFRESH_ONLY:
912         case LDAP_SYNC_REFRESH_AND_PERSIST:
913                 break;
914         default:
915                 ldap_pvt_thread_mutex_unlock( &si->si_mutex );
916                 return NULL;
917         }
918
919         if ( slapd_shutdown ) {
920                 if ( si->si_ld ) {
921                         ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
922                         connection_client_stop( s );
923                         ldap_unbind_ext( si->si_ld, NULL, NULL );
924                         si->si_ld = NULL;
925                 }
926                 ldap_pvt_thread_mutex_unlock( &si->si_mutex );
927                 return NULL;
928         }
929
930         op = (Operation *)opbuf;
931         connection_fake_init( &conn, op, ctx );
932
933         /* use global malloc for now */
934         op->o_tmpmemctx = NULL;
935         op->o_tmpmfuncs = &ch_mfuncs;
936
937         op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
938         op->o_bd = be = si->si_be;
939         op->o_dn = op->o_bd->be_rootdn;
940         op->o_ndn = op->o_bd->be_rootndn;
941
942         /* Establish session, do search */
943         if ( !si->si_ld ) {
944                 first = 1;
945                 si->si_refreshDelete = 0;
946                 si->si_refreshPresent = 0;
947                 rc = do_syncrep1( op, si );
948         }
949
950         /* Process results */
951         if ( rc == LDAP_SUCCESS ) {
952                 ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
953
954                 rc = do_syncrep2( op, si );
955
956                 if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
957                         /* If we succeeded, enable the connection for further listening.
958                          * If we failed, tear down the connection and reschedule.
959                          */
960                         if ( rc == LDAP_SUCCESS ) {
961                                 if ( first ) {
962                                         rc = connection_client_setup( s, do_syncrepl, arg );
963                                 } else {
964                                         connection_client_enable( s );
965                                 } 
966                         } else if ( !first ) {
967                                 dostop = 1;
968                         }
969                 } else {
970                         if ( rc == -2 ) rc = 0;
971                 }
972         }
973
974         /* At this point, we have 4 cases:
975          * 1) for any hard failure, give up and remove this task
976          * 2) for ServerDown, reschedule this task to run
977          * 3) for Refresh and Success, reschedule to run
978          * 4) for Persist and Success, reschedule to defer
979          */
980         ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
981
982         if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) {
983                 ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
984         }
985
986         if ( dostop ) {
987                 connection_client_stop( s );
988         }
989
990         if ( rc == LDAP_SUCCESS ) {
991                 if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
992                         defer = 0;
993                 }
994                 rtask->interval.tv_sec = si->si_interval;
995                 ldap_pvt_runqueue_resched( &slapd_rq, rtask, defer );
996                 if ( si->si_retrynum ) {
997                         for ( i = 0; si->si_retrynum_init[i] != -2; i++ ) {
998                                 si->si_retrynum[i] = si->si_retrynum_init[i];
999                         }
1000                         si->si_retrynum[i] = -2;
1001                 }
1002         } else {
1003                 for ( i = 0; si->si_retrynum && si->si_retrynum[i] <= 0; i++ ) {
1004                         if ( si->si_retrynum[i] == -1  || si->si_retrynum[i] == -2 )
1005                                 break;
1006                 }
1007
1008                 if ( !si->si_retrynum || si->si_retrynum[i] == -2 ) {
1009                         ldap_pvt_runqueue_remove( &slapd_rq, rtask );
1010                 } else if ( si->si_retrynum[i] >= -1 ) {
1011                         if ( si->si_retrynum[i] > 0 )
1012                                 si->si_retrynum[i]--;
1013                         rtask->interval.tv_sec = si->si_retryinterval[i];
1014                         ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
1015                         slap_wake_listener();
1016                 }
1017         }
1018         
1019         ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
1020         ldap_pvt_thread_mutex_unlock( &si->si_mutex );
1021
1022         return NULL;
1023 }
1024
1025 static int
1026 syncrepl_message_to_entry(
1027         syncinfo_t      *si,
1028         Operation       *op,
1029         LDAPMessage     *msg,
1030         Modifications   **modlist,
1031         Entry                   **entry,
1032         int             syncstate
1033 )
1034 {
1035         Entry           *e = NULL;
1036         BerElement      *ber = NULL;
1037         Modifications   tmp;
1038         Modifications   *mod;
1039         Modifications   **modtail = modlist;
1040
1041         const char      *text;
1042         char txtbuf[SLAP_TEXT_BUFLEN];
1043         size_t textlen = sizeof txtbuf;
1044
1045         struct berval   bdn = {0, NULL}, dn, ndn;
1046         int             rc;
1047
1048         *modlist = NULL;
1049
1050         if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
1051                 Debug( LDAP_DEBUG_ANY,
1052                         "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
1053                 return -1;
1054         }
1055
1056         op->o_tag = LDAP_REQ_ADD;
1057
1058         rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
1059
1060         if ( rc != LDAP_SUCCESS ) {
1061                 Debug( LDAP_DEBUG_ANY,
1062                         "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
1063                 return rc;
1064         }
1065
1066         dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
1067         ber_dupbv( &op->o_req_dn, &dn );
1068         ber_dupbv( &op->o_req_ndn, &ndn );
1069         slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
1070         slap_sl_free( dn.bv_val, op->o_tmpmemctx );
1071
1072         if ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_DELETE ) {
1073                 if ( entry )
1074                         *entry = NULL;
1075                 return LDAP_SUCCESS;
1076         }
1077
1078         if ( entry == NULL ) {
1079                 return -1;
1080         }
1081
1082         e = ( Entry * ) ch_calloc( 1, sizeof( Entry ) );
1083         *entry = e;
1084         e->e_name = op->o_req_dn;
1085         e->e_nname = op->o_req_ndn;
1086
1087         while ( ber_remaining( ber ) ) {
1088                 if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) ==
1089                         LBER_ERROR ) || BER_BVISNULL( &tmp.sml_type ) )
1090                 {
1091                         break;
1092                 }
1093
1094                 mod  = (Modifications *) ch_malloc( sizeof( Modifications ));
1095
1096                 mod->sml_op = LDAP_MOD_REPLACE;
1097                 mod->sml_flags = 0;
1098                 mod->sml_next = NULL;
1099                 mod->sml_desc = NULL;
1100                 mod->sml_type = tmp.sml_type;
1101                 mod->sml_values = tmp.sml_values;
1102                 mod->sml_nvalues = NULL;
1103
1104                 *modtail = mod;
1105                 modtail = &mod->sml_next;
1106         }
1107
1108         if ( *modlist == NULL ) {
1109                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: no attributes\n",
1110                         0, 0, 0 );
1111                 rc = -1;
1112                 goto done;
1113         }
1114
1115         rc = slap_mods_check( *modlist, &text, txtbuf, textlen, NULL );
1116
1117         if ( rc != LDAP_SUCCESS ) {
1118                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods check (%s)\n",
1119                         text, 0, 0 );
1120                 goto done;
1121         }
1122
1123         /* Strip out dynamically generated attrs */
1124         for ( modtail = modlist; *modtail ; ) {
1125                 mod = *modtail;
1126                 if ( mod->sml_desc->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
1127                         *modtail = mod->sml_next;
1128                         slap_mod_free( &mod->sml_mod, 0 );
1129                         ch_free( mod );
1130                 } else {
1131                         modtail = &mod->sml_next;
1132                 }
1133         }
1134
1135         /* Strip out attrs in exattrs list */
1136         for ( modtail = modlist; *modtail ; ) {
1137                 mod = *modtail;
1138                 if ( ldap_charray_inlist( si->si_exattrs,
1139                                         mod->sml_desc->ad_type->sat_cname.bv_val )) {
1140                         *modtail = mod->sml_next;
1141                         slap_mod_free( &mod->sml_mod, 0 );
1142                         ch_free( mod );
1143                 } else {
1144                         modtail = &mod->sml_next;
1145                 }
1146         }
1147         
1148         rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
1149         if( rc != LDAP_SUCCESS ) {
1150                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods2entry (%s)\n",
1151                         text, 0, 0 );
1152         }
1153
1154 done:
1155         ber_free ( ber, 0 );
1156         if ( rc != LDAP_SUCCESS ) {
1157                 if ( e ) {
1158                         entry_free( e );
1159                         *entry = e = NULL;
1160                 }
1161         }
1162
1163         return rc;
1164 }
1165
1166 static struct berval generic_filterstr = BER_BVC("(objectclass=*)");
1167
1168 /* During a refresh, we may get an LDAP_SYNC_ADD for an already existing
1169  * entry if a previous refresh was interrupted before sending us a new
1170  * context state. We try to compare the new entry to the existing entry
1171  * and ignore the new entry if they are the same.
1172  *
1173  * Also, we may get an update where the entryDN has changed, due to
1174  * a ModDn on the provider. We detect this as well, so we can issue
1175  * the corresponding operation locally.
1176  *
1177  * In the case of a modify, we get a list of all the attributes
1178  * in the original entry. Rather than deleting the entry and re-adding it,
1179  * we issue a Modify request that deletes all the attributes and adds all
1180  * the new ones. This avoids the issue of trying to delete/add a non-leaf
1181  * entry.
1182  *
1183  * We don't try to otherwise distinguish ModDN from Modify; in the case of
1184  * a ModDN we will issue both operations on the local database.
1185  */
1186 typedef struct dninfo {
1187         Entry *new_entry;
1188         struct berval dn;
1189         struct berval ndn;
1190         int renamed;    /* Was an existing entry renamed? */
1191         int wasChanged; /* are the attributes changed? */
1192         int attrs;              /* how many attribute types are in the ads list */
1193         AttributeDescription **ads;
1194 } dninfo;
1195
1196 static int
1197 syncrepl_entry(
1198         syncinfo_t* si,
1199         Operation *op,
1200         Entry* entry,
1201         Modifications** modlist,
1202         int syncstate,
1203         struct berval* syncUUID,
1204         struct sync_cookie* syncCookie_req,
1205         struct berval* syncCSN )
1206 {
1207         Backend *be = op->o_bd;
1208         slap_callback   cb = { NULL, NULL, NULL, NULL };
1209         struct berval   *syncuuid_bv = NULL;
1210         struct berval   syncUUID_strrep = BER_BVNULL;
1211         struct berval   uuid_bv = BER_BVNULL;
1212
1213         SlapReply       rs_search = {REP_RESULT};
1214         SlapReply       rs_delete = {REP_RESULT};
1215         SlapReply       rs_add = {REP_RESULT};
1216         SlapReply       rs_modify = {REP_RESULT};
1217         Filter f = {0};
1218 #ifdef LDAP_COMP_MATCH
1219         AttributeAssertion ava = { NULL, BER_BVNULL, NULL };
1220 #else
1221         AttributeAssertion ava = { NULL, BER_BVNULL };
1222 #endif
1223         int rc = LDAP_SUCCESS;
1224         int ret = LDAP_SUCCESS;
1225
1226         struct berval pdn = BER_BVNULL;
1227         dninfo dni = {0};
1228         int     retry = 1;
1229
1230         switch( syncstate ) {
1231         case LDAP_SYNC_PRESENT:
1232                 Debug( LDAP_DEBUG_SYNC, "%s: %s\n",
1233                                         "syncrepl_entry",
1234                                         "LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_PRESENT)", 0 );
1235                 break;
1236         case LDAP_SYNC_ADD:
1237                 Debug( LDAP_DEBUG_SYNC, "%s: %s\n",
1238                                         "syncrepl_entry",
1239                                         "LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_ADD)", 0 );
1240                 break;
1241         case LDAP_SYNC_DELETE:
1242                 Debug( LDAP_DEBUG_SYNC, "%s: %s\n",
1243                                         "syncrepl_entry",
1244                                         "LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_DELETE)", 0 );
1245                 break;
1246         case LDAP_SYNC_MODIFY:
1247                 Debug( LDAP_DEBUG_SYNC, "%s: %s\n",
1248                                         "syncrepl_entry",
1249                                         "LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_MODIFY)", 0 );
1250                 break;
1251         default:
1252                 Debug( LDAP_DEBUG_ANY, "%s: %s\n",
1253                                         "syncrepl_entry",
1254                                         "LDAP_RES_SEARCH_ENTRY(UNKNOWN syncstate)", 0 );
1255         }
1256
1257         if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD )) {
1258                 if ( !si->si_refreshPresent ) {
1259                         syncuuid_bv = ber_dupbv( NULL, syncUUID );
1260                         avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
1261                                 syncuuid_cmp, avl_dup_error );
1262                 }
1263         }
1264
1265         if ( syncstate == LDAP_SYNC_PRESENT ) {
1266                 return 0;
1267         } else if ( syncstate != LDAP_SYNC_DELETE ) {
1268                 if ( entry == NULL ) {
1269                         return 0;
1270                 }
1271         }
1272
1273         f.f_choice = LDAP_FILTER_EQUALITY;
1274         f.f_ava = &ava;
1275         ava.aa_desc = slap_schema.si_ad_entryUUID;
1276         (void)slap_uuidstr_from_normalized( &syncUUID_strrep, syncUUID, op->o_tmpmemctx );
1277         ava.aa_value = *syncUUID;
1278         op->ors_filter = &f;
1279
1280         op->ors_filterstr.bv_len = STRLENOF( "(entryUUID=)" ) + syncUUID->bv_len;
1281         op->ors_filterstr.bv_val = (char *) slap_sl_malloc(
1282                 op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); 
1283         AC_MEMCPY( op->ors_filterstr.bv_val, "(entryUUID=", STRLENOF( "(entryUUID=" ) );
1284         AC_MEMCPY( &op->ors_filterstr.bv_val[STRLENOF( "(entryUUID=" )],
1285                 syncUUID->bv_val, syncUUID->bv_len );
1286         op->ors_filterstr.bv_val[op->ors_filterstr.bv_len - 1] = ')';
1287         op->ors_filterstr.bv_val[op->ors_filterstr.bv_len] = '\0';
1288
1289         op->o_tag = LDAP_REQ_SEARCH;
1290         op->ors_scope = LDAP_SCOPE_SUBTREE;
1291         op->ors_deref = LDAP_DEREF_NEVER;
1292
1293         /* get the entry for this UUID */
1294         op->o_req_dn = si->si_base;
1295         op->o_req_ndn = si->si_base;
1296
1297         op->o_time = slap_get_time();
1298         op->ors_tlimit = SLAP_NO_LIMIT;
1299         op->ors_slimit = 1;
1300
1301         op->ors_attrs = slap_anlist_all_attributes;
1302         op->ors_attrsonly = 0;
1303
1304         /* set callback function */
1305         op->o_callback = &cb;
1306         cb.sc_response = dn_callback;
1307         cb.sc_private = &dni;
1308         dni.new_entry = entry;
1309
1310         if ( limits_check( op, &rs_search ) == 0 ) {
1311                 rc = be->be_search( op, &rs_search );
1312                 Debug( LDAP_DEBUG_SYNC,
1313                                 "syncrepl_entry: %s (%d)\n", 
1314                                 "be_search", rc, 0 );
1315         }
1316
1317         if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
1318                 slap_sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1319         }
1320
1321         cb.sc_response = null_callback;
1322         cb.sc_private = si;
1323
1324         if ( entry && !BER_BVISNULL( &entry->e_name ) ) {
1325                 Debug( LDAP_DEBUG_SYNC,
1326                                 "syncrepl_entry: %s\n",
1327                                 entry->e_name.bv_val, 0, 0 );
1328         } else {
1329                 Debug( LDAP_DEBUG_SYNC,
1330                                 "syncrepl_entry: %s\n",
1331                                 dni.dn.bv_val ? dni.dn.bv_val : "(null)", 0, 0 );
1332         }
1333
1334         if ( syncstate != LDAP_SYNC_DELETE ) {
1335                 Attribute       *a = attr_find( entry->e_attrs, slap_schema.si_ad_entryUUID );
1336
1337                 if ( a == NULL ) {
1338                         /* add if missing */
1339                         attr_merge_one( entry, slap_schema.si_ad_entryUUID,
1340                                 &syncUUID_strrep, syncUUID );
1341
1342                 } else if ( !bvmatch( &a->a_nvals[0], syncUUID ) ) {
1343                         /* replace only if necessary */
1344                         if ( a->a_nvals != a->a_vals ) {
1345                                 ber_memfree( a->a_nvals[0].bv_val );
1346                                 ber_dupbv( &a->a_nvals[0], syncUUID );
1347                         }
1348                         ber_memfree( a->a_vals[0].bv_val );
1349                         ber_dupbv( &a->a_vals[0], &syncUUID_strrep );
1350                 }
1351         }
1352
1353         switch ( syncstate ) {
1354         case LDAP_SYNC_ADD:
1355         case LDAP_SYNC_MODIFY:
1356 retry_add:;
1357                 if ( BER_BVISNULL( &dni.dn )) {
1358
1359                         op->o_req_dn = entry->e_name;
1360                         op->o_req_ndn = entry->e_nname;
1361                         op->o_tag = LDAP_REQ_ADD;
1362                         op->ora_e = entry;
1363
1364                         rc = be->be_add( op, &rs_add );
1365                         Debug( LDAP_DEBUG_SYNC,
1366                                         "syncrepl_entry: %s (%d)\n", 
1367                                         "be_add", rc, 0 );
1368                         switch ( rs_add.sr_err ) {
1369                         case LDAP_SUCCESS:
1370                                 be_entry_release_w( op, entry );
1371                                 ret = 0;
1372                                 break;
1373
1374                         case LDAP_REFERRAL:
1375                         /* we assume that LDAP_NO_SUCH_OBJECT is returned 
1376                          * only if the suffix entry is not present */
1377                         case LDAP_NO_SUCH_OBJECT:
1378                                 syncrepl_add_glue( op, entry );
1379                                 ret = 0;
1380                                 break;
1381
1382                         /* if an entry was added via syncrepl_add_glue(),
1383                          * it likely has no entryUUID, so the previous
1384                          * be_search() doesn't find it.  In this case,
1385                          * give syncrepl a chance to modify it. Also
1386                          * allow for entries that were recreated with the
1387                          * same DN but a different entryUUID.
1388                          */
1389                         case LDAP_ALREADY_EXISTS:
1390                                 if ( retry ) {
1391                                         Operation       op2 = *op;
1392                                         SlapReply       rs2 = { 0 };
1393                                         slap_callback   cb2 = { 0 };
1394
1395                                         op2.o_tag = LDAP_REQ_SEARCH;
1396                                         op2.o_req_dn = entry->e_name;
1397                                         op2.o_req_ndn = entry->e_nname;
1398                                         op2.ors_scope = LDAP_SCOPE_BASE;
1399                                         op2.ors_deref = LDAP_DEREF_NEVER;
1400                                         op2.ors_attrs = slap_anlist_all_attributes;
1401                                         op2.ors_attrsonly = 0;
1402                                         op2.ors_limit = NULL;
1403                                         op2.ors_slimit = 1;
1404                                         op2.ors_tlimit = SLAP_NO_LIMIT;
1405
1406                                         f.f_choice = LDAP_FILTER_PRESENT;
1407                                         f.f_desc = slap_schema.si_ad_objectClass;
1408                                         op2.ors_filter = &f;
1409                                         op2.ors_filterstr = generic_filterstr;
1410
1411                                         op2.o_callback = &cb2;
1412                                         cb2.sc_response = dn_callback;
1413                                         cb2.sc_private = &dni;
1414
1415                                         be->be_search( &op2, &rs2 );
1416
1417                                         retry = 0;
1418                                         goto retry_add;
1419                                 }
1420                                 /* FALLTHRU */
1421
1422                         default:
1423                                 Debug( LDAP_DEBUG_ANY,
1424                                         "syncrepl_entry : be_add failed (%d)\n",
1425                                         rs_add.sr_err, 0, 0 );
1426                                 ret = 1;
1427                                 break;
1428                         }
1429                         goto done;
1430                 }
1431                 /* FALLTHRU */
1432                 op->o_req_dn = dni.dn;
1433                 op->o_req_ndn = dni.ndn;
1434                 if ( dni.renamed ) {
1435                         struct berval noldp, newp, nnewp;
1436
1437                         op->o_tag = LDAP_REQ_MODRDN;
1438                         dnRdn( &entry->e_name, &op->orr_newrdn );
1439                         dnRdn( &entry->e_nname, &op->orr_nnewrdn );
1440
1441                         dnParent( &dni.ndn, &noldp );
1442                         dnParent( &entry->e_nname, &nnewp );
1443                         if ( !dn_match( &noldp, &newp )) {
1444                                 dnParent( &entry->e_name, &newp );
1445                                 op->orr_newSup = &newp;
1446                                 op->orr_nnewSup = &nnewp;
1447                         }
1448                         op->orr_deleteoldrdn = 0;
1449                         rc = be->be_modrdn( op, &rs_modify );
1450                         Debug( LDAP_DEBUG_SYNC,
1451                                         "syncrepl_entry: %s (%d)\n", 
1452                                         "be_modrdn", rc, 0 );
1453                         if ( rs_modify.sr_err == LDAP_SUCCESS ) {
1454                                 op->o_req_dn = entry->e_name;
1455                                 op->o_req_ndn = entry->e_nname;
1456                         } else {
1457                                 ret = 1;
1458                                 goto done;
1459                         }
1460                 }
1461                 if ( dni.wasChanged ) {
1462                         Modifications *mod, *modhead = NULL;
1463                         Modifications *modtail = NULL;
1464                         int i;
1465
1466                         op->o_tag = LDAP_REQ_MODIFY;
1467
1468                         assert( *modlist != NULL );
1469
1470                         /* Delete all the old attrs */
1471                         for ( i = 0; i < dni.attrs; i++ ) {
1472                                 mod = ch_malloc( sizeof( Modifications ) );
1473                                 mod->sml_op = LDAP_MOD_DELETE;
1474                                 mod->sml_flags = 0;
1475                                 mod->sml_desc = dni.ads[i];
1476                                 mod->sml_type = mod->sml_desc->ad_cname;
1477                                 mod->sml_values = NULL;
1478                                 mod->sml_nvalues = NULL;
1479                                 if ( !modhead ) modhead = mod;
1480                                 if ( modtail ) {
1481                                         modtail->sml_next = mod;
1482                                 }
1483                                 modtail = mod;
1484                         }
1485
1486                         /* Append passed in list to ours */
1487                         if ( modtail ) {
1488                                 modtail->sml_next = *modlist;
1489                                 *modlist = modhead;
1490                         } else {
1491                                 mod = *modlist;
1492                         }
1493
1494                         /* Find end of this list */
1495                         for ( ; mod != NULL; mod = mod->sml_next ) {
1496                                 modtail = mod;
1497                         }
1498
1499                         mod = (Modifications *)ch_calloc(1, sizeof(Modifications));
1500                         mod->sml_op = LDAP_MOD_REPLACE;
1501                         mod->sml_flags = 0;
1502                         mod->sml_desc = slap_schema.si_ad_entryUUID;
1503                         mod->sml_type = mod->sml_desc->ad_cname;
1504                         ber_dupbv( &uuid_bv, &syncUUID_strrep );
1505                         ber_bvarray_add( &mod->sml_values, &uuid_bv );
1506                         ber_dupbv( &uuid_bv, syncUUID );
1507                         ber_bvarray_add( &mod->sml_nvalues, &uuid_bv );
1508                         modtail->sml_next = mod;
1509                                         
1510                         op->o_tag = LDAP_REQ_MODIFY;
1511                         op->orm_modlist = *modlist;
1512
1513                         rc = be->be_modify( op, &rs_modify );
1514                         Debug( LDAP_DEBUG_SYNC,
1515                                         "syncrepl_entry: %s (%d)\n", 
1516                                         "be_modify", rc, 0 );
1517                         if ( rs_modify.sr_err != LDAP_SUCCESS ) {
1518                                 Debug( LDAP_DEBUG_ANY,
1519                                         "syncrepl_entry : be_modify failed (%d)\n",
1520                                         rs_modify.sr_err, 0, 0 );
1521                         }
1522                 }
1523                 ret = 1;
1524                 goto done;
1525         case LDAP_SYNC_DELETE :
1526                 if ( !BER_BVISNULL( &dni.dn )) {
1527                         op->o_req_dn = dni.dn;
1528                         op->o_req_ndn = dni.ndn;
1529                         op->o_tag = LDAP_REQ_DELETE;
1530                         rc = be->be_delete( op, &rs_delete );
1531                         Debug( LDAP_DEBUG_SYNC,
1532                                         "syncrepl_entry: %s (%d)\n", 
1533                                         "be_delete", rc, 0 );
1534
1535                         while ( rs_delete.sr_err == LDAP_SUCCESS
1536                                 && op->o_delete_glue_parent ) {
1537                                 op->o_delete_glue_parent = 0;
1538                                 if ( !be_issuffix( op->o_bd, &op->o_req_ndn )) {
1539                                         slap_callback cb = { NULL };
1540                                         cb.sc_response = slap_null_cb;
1541                                         dnParent( &op->o_req_ndn, &pdn );
1542                                         op->o_req_dn = pdn;
1543                                         op->o_req_ndn = pdn;
1544                                         op->o_callback = &cb;
1545                                         op->o_bd->be_delete( op, &rs_delete );
1546                                 } else {
1547                                         break;
1548                                 }
1549                         }
1550                 }
1551                 ret = 0;
1552                 goto done;
1553
1554         default :
1555                 Debug( LDAP_DEBUG_ANY,
1556                         "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1557                 ret = 1;
1558                 goto done;
1559         }
1560
1561 done :
1562         if ( !BER_BVISNULL( &syncUUID_strrep ) ) {
1563                 slap_sl_free( syncUUID_strrep.bv_val, op->o_tmpmemctx );
1564                 BER_BVZERO( &syncUUID_strrep );
1565         }
1566         if ( dni.ads ) {
1567                 op->o_tmpfree( dni.ads, op->o_tmpmemctx );
1568         }
1569         if ( !BER_BVISNULL( &dni.ndn ) ) {
1570                 op->o_tmpfree( dni.ndn.bv_val, op->o_tmpmemctx );
1571         }
1572         if ( !BER_BVISNULL( &dni.dn ) ) {
1573                 op->o_tmpfree( dni.dn.bv_val, op->o_tmpmemctx );
1574         }
1575         return ret;
1576 }
1577
1578 static struct berval gcbva[] = {
1579         BER_BVC("top"),
1580         BER_BVC("glue"),
1581         BER_BVNULL
1582 };
1583
1584 #define NP_DELETE_ONE   2
1585
1586 static void
1587 syncrepl_del_nonpresent(
1588         Operation *op,
1589         syncinfo_t *si,
1590         BerVarray uuids )
1591 {
1592         Backend* be = op->o_bd;
1593         slap_callback   cb = { NULL };
1594         SlapReply       rs_search = {REP_RESULT};
1595         SlapReply       rs_delete = {REP_RESULT};
1596         SlapReply       rs_modify = {REP_RESULT};
1597         struct nonpresent_entry *np_list, *np_prev;
1598         int rc;
1599         AttributeName   an[2];
1600
1601         struct berval pdn = BER_BVNULL;
1602
1603         op->o_req_dn = si->si_base;
1604         op->o_req_ndn = si->si_base;
1605
1606         cb.sc_response = nonpresent_callback;
1607         cb.sc_private = si;
1608
1609         op->o_callback = &cb;
1610         op->o_tag = LDAP_REQ_SEARCH;
1611         op->ors_scope = si->si_scope;
1612         op->ors_deref = LDAP_DEREF_NEVER;
1613         op->o_time = slap_get_time();
1614         op->ors_tlimit = SLAP_NO_LIMIT;
1615
1616
1617         if ( uuids ) {
1618                 Filter uf;
1619 #ifdef LDAP_COMP_MATCH
1620                 AttributeAssertion eq = { NULL, BER_BVNULL, NULL };
1621 #else
1622                 AttributeAssertion eq = { NULL, BER_BVNULL };
1623 #endif
1624                 int i;
1625
1626                 op->ors_attrsonly = 1;
1627                 op->ors_attrs = slap_anlist_no_attrs;
1628                 op->ors_limit = NULL;
1629                 op->ors_filter = &uf;
1630
1631                 uf.f_ava = &eq;
1632                 uf.f_av_desc = slap_schema.si_ad_entryUUID;
1633                 uf.f_next = NULL;
1634                 uf.f_choice = LDAP_FILTER_EQUALITY;
1635                 si->si_refreshDelete |= NP_DELETE_ONE;
1636
1637                 for (i=0; uuids[i].bv_val; i++) {
1638                         op->ors_slimit = 1;
1639                         uf.f_av_value = uuids[i];
1640                         rc = be->be_search( op, &rs_search );
1641                 }
1642                 si->si_refreshDelete ^= NP_DELETE_ONE;
1643         } else {
1644                 memset( &an[0], 0, 2 * sizeof( AttributeName ) );
1645                 an[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
1646                 an[0].an_desc = slap_schema.si_ad_entryUUID;
1647                 op->ors_attrs = an;
1648                 op->ors_slimit = SLAP_NO_LIMIT;
1649                 op->ors_attrsonly = 0;
1650                 op->ors_filter = str2filter_x( op, si->si_filterstr.bv_val );
1651                 op->ors_filterstr = si->si_filterstr;
1652                 op->o_nocaching = 1;
1653
1654                 if ( limits_check( op, &rs_search ) == 0 ) {
1655                         rc = be->be_search( op, &rs_search );
1656                 }
1657                 if ( op->ors_filter ) filter_free_x( op, op->ors_filter );
1658         }
1659
1660         op->o_nocaching = 0;
1661
1662         if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
1663
1664                 slap_queue_csn( op, &si->si_syncCookie.ctxcsn );
1665
1666                 np_list = LDAP_LIST_FIRST( &si->si_nonpresentlist );
1667                 while ( np_list != NULL ) {
1668                         LDAP_LIST_REMOVE( np_list, npe_link );
1669                         np_prev = np_list;
1670                         np_list = LDAP_LIST_NEXT( np_list, npe_link );
1671                         op->o_tag = LDAP_REQ_DELETE;
1672                         op->o_callback = &cb;
1673                         cb.sc_response = null_callback;
1674                         cb.sc_private = si;
1675                         op->o_req_dn = *np_prev->npe_name;
1676                         op->o_req_ndn = *np_prev->npe_nname;
1677                         rc = op->o_bd->be_delete( op, &rs_delete );
1678
1679                         if ( rs_delete.sr_err == LDAP_NOT_ALLOWED_ON_NONLEAF ) {
1680                                 Modifications mod1, mod2;
1681                                 mod1.sml_op = LDAP_MOD_REPLACE;
1682                                 mod1.sml_flags = 0;
1683                                 mod1.sml_desc = slap_schema.si_ad_objectClass;
1684                                 mod1.sml_type = mod1.sml_desc->ad_cname;
1685                                 mod1.sml_values = &gcbva[0];
1686                                 mod1.sml_nvalues = NULL;
1687                                 mod1.sml_next = &mod2;
1688
1689                                 mod2.sml_op = LDAP_MOD_REPLACE;
1690                                 mod2.sml_flags = 0;
1691                                 mod2.sml_desc = slap_schema.si_ad_structuralObjectClass;
1692                                 mod2.sml_type = mod2.sml_desc->ad_cname;
1693                                 mod2.sml_values = &gcbva[1];
1694                                 mod2.sml_nvalues = NULL;
1695                                 mod2.sml_next = NULL;
1696
1697                                 op->o_tag = LDAP_REQ_MODIFY;
1698                                 op->orm_modlist = &mod1;
1699
1700                                 rc = be->be_modify( op, &rs_modify );
1701                         }
1702
1703                         while ( rs_delete.sr_err == LDAP_SUCCESS &&
1704                                         op->o_delete_glue_parent ) {
1705                                 op->o_delete_glue_parent = 0;
1706                                 if ( !be_issuffix( op->o_bd, &op->o_req_ndn )) {
1707                                         slap_callback cb = { NULL };
1708                                         cb.sc_response = slap_null_cb;
1709                                         dnParent( &op->o_req_ndn, &pdn );
1710                                         op->o_req_dn = pdn;
1711                                         op->o_req_ndn = pdn;
1712                                         op->o_callback = &cb;
1713                                         /* give it a root privil ? */
1714                                         op->o_bd->be_delete( op, &rs_delete );
1715                                 } else {
1716                                         break;
1717                             }
1718                         }
1719
1720                         op->o_delete_glue_parent = 0;
1721
1722                         ber_bvfree( np_prev->npe_name );
1723                         ber_bvfree( np_prev->npe_nname );
1724                         ch_free( np_prev );
1725                 }
1726
1727                 slap_graduate_commit_csn( op );
1728         }
1729
1730         return;
1731 }
1732
1733 void
1734 syncrepl_add_glue(
1735         Operation* op,
1736         Entry *e )
1737 {
1738         Backend *be = op->o_bd;
1739         slap_callback cb = { NULL };
1740         Attribute       *a;
1741         int     rc;
1742         int suffrdns;
1743         int i;
1744         struct berval dn = {0, NULL};
1745         struct berval ndn = {0, NULL};
1746         Entry   *glue;
1747         SlapReply       rs_add = {REP_RESULT};
1748         char    *ptr, *comma;
1749
1750         op->o_tag = LDAP_REQ_ADD;
1751         op->o_callback = &cb;
1752         cb.sc_response = null_callback;
1753         cb.sc_private = NULL;
1754
1755         dn = e->e_name;
1756         ndn = e->e_nname;
1757
1758         /* count RDNs in suffix */
1759         if ( !BER_BVISEMPTY( &be->be_nsuffix[0] ) ) {
1760                 for ( i = 0, ptr = be->be_nsuffix[0].bv_val; ptr; ptr = strchr( ptr, ',' ) ) {
1761                         ptr++;
1762                         i++;
1763                 }
1764                 suffrdns = i;
1765         } else {
1766                 /* suffix is "" */
1767                 suffrdns = 0;
1768         }
1769
1770         /* Start with BE suffix */
1771         for ( i = 0, ptr = NULL; i < suffrdns; i++ ) {
1772                 comma = strrchr( dn.bv_val, ',' );
1773                 if ( ptr ) *ptr = ',';
1774                 if ( comma ) *comma = '\0';
1775                 ptr = comma;
1776         }
1777         if ( ptr ) {
1778                 *ptr++ = ',';
1779                 dn.bv_len -= ptr - dn.bv_val;
1780                 dn.bv_val = ptr;
1781         }
1782         /* the normalizedDNs are always the same length, no counting
1783          * required.
1784          */
1785         if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) {
1786                 ndn.bv_val += ndn.bv_len - be->be_nsuffix[0].bv_len;
1787                 ndn.bv_len = be->be_nsuffix[0].bv_len;
1788         }
1789
1790         while ( ndn.bv_val > e->e_nname.bv_val ) {
1791                 glue = (Entry *) ch_calloc( 1, sizeof(Entry) );
1792                 ber_dupbv( &glue->e_name, &dn );
1793                 ber_dupbv( &glue->e_nname, &ndn );
1794
1795                 a = ch_calloc( 1, sizeof( Attribute ));
1796                 a->a_desc = slap_schema.si_ad_objectClass;
1797
1798                 a->a_vals = ch_calloc( 3, sizeof( struct berval ));
1799                 ber_dupbv( &a->a_vals[0], &gcbva[0] );
1800                 ber_dupbv( &a->a_vals[1], &gcbva[1] );
1801                 ber_dupbv( &a->a_vals[2], &gcbva[2] );
1802
1803                 a->a_nvals = a->a_vals;
1804
1805                 a->a_next = glue->e_attrs;
1806                 glue->e_attrs = a;
1807
1808                 a = ch_calloc( 1, sizeof( Attribute ));
1809                 a->a_desc = slap_schema.si_ad_structuralObjectClass;
1810
1811                 a->a_vals = ch_calloc( 2, sizeof( struct berval ));
1812                 ber_dupbv( &a->a_vals[0], &gcbva[1] );
1813                 ber_dupbv( &a->a_vals[1], &gcbva[2] );
1814
1815                 a->a_nvals = a->a_vals;
1816
1817                 a->a_next = glue->e_attrs;
1818                 glue->e_attrs = a;
1819
1820                 op->o_req_dn = glue->e_name;
1821                 op->o_req_ndn = glue->e_nname;
1822                 op->ora_e = glue;
1823                 rc = be->be_add ( op, &rs_add );
1824                 if ( rs_add.sr_err == LDAP_SUCCESS ) {
1825                         be_entry_release_w( op, glue );
1826                 } else {
1827                 /* incl. ALREADY EXIST */
1828                         entry_free( glue );
1829                 }
1830
1831                 /* Move to next child */
1832                 for (ptr = dn.bv_val-2; ptr > e->e_name.bv_val && *ptr != ','; ptr--) {
1833                         /* empty */
1834                 }
1835                 if ( ptr == e->e_name.bv_val ) break;
1836                 dn.bv_val = ++ptr;
1837                 dn.bv_len = e->e_name.bv_len - (ptr-e->e_name.bv_val);
1838                 for( ptr = ndn.bv_val-2;
1839                         ptr > e->e_nname.bv_val && *ptr != ',';
1840                         ptr--)
1841                 {
1842                         /* empty */
1843                 }
1844                 ndn.bv_val = ++ptr;
1845                 ndn.bv_len = e->e_nname.bv_len - (ptr-e->e_nname.bv_val);
1846         }
1847
1848         op->o_req_dn = e->e_name;
1849         op->o_req_ndn = e->e_nname;
1850         op->ora_e = e;
1851         rc = be->be_add ( op, &rs_add );
1852         if ( rs_add.sr_err == LDAP_SUCCESS ) {
1853                 be_entry_release_w( op, e );
1854         } else {
1855                 entry_free( e );
1856         }
1857
1858         return;
1859 }
1860
1861 static void
1862 syncrepl_updateCookie(
1863         syncinfo_t *si,
1864         Operation *op,
1865         struct berval *pdn,
1866         struct sync_cookie *syncCookie )
1867 {
1868         Backend *be = op->o_bd;
1869         Modifications mod = {0};
1870         struct berval vals[2];
1871
1872         int rc;
1873
1874         slap_callback cb = { NULL };
1875         SlapReply       rs_modify = {REP_RESULT};
1876
1877         slap_sync_cookie_free( &si->si_syncCookie, 0 );
1878         slap_dup_sync_cookie( &si->si_syncCookie, syncCookie );
1879
1880         mod.sml_op = LDAP_MOD_REPLACE;
1881         mod.sml_desc = slap_schema.si_ad_contextCSN;
1882         mod.sml_type = mod.sml_desc->ad_cname;
1883         mod.sml_values = vals;
1884         vals[0] = si->si_syncCookie.ctxcsn;
1885         vals[1].bv_val = NULL;
1886         vals[1].bv_len = 0;
1887
1888         slap_queue_csn( op, &si->si_syncCookie.ctxcsn );
1889
1890         op->o_tag = LDAP_REQ_MODIFY;
1891
1892         assert( si->si_rid < 1000 );
1893
1894         cb.sc_response = null_callback;
1895         cb.sc_private = si;
1896
1897         op->o_callback = &cb;
1898         op->o_req_dn = op->o_bd->be_suffix[0];
1899         op->o_req_ndn = op->o_bd->be_nsuffix[0];
1900
1901         /* update contextCSN */
1902         op->o_msgid = SLAP_SYNC_UPDATE_MSGID;
1903         op->orm_modlist = &mod;
1904         rc = be->be_modify( op, &rs_modify );
1905         op->o_msgid = 0;
1906
1907         if ( rs_modify.sr_err != LDAP_SUCCESS ) {
1908                 Debug( LDAP_DEBUG_ANY,
1909                         "be_modify failed (%d)\n", rs_modify.sr_err, 0, 0 );
1910         }
1911
1912         slap_graduate_commit_csn( op );
1913
1914         return;
1915 }
1916
1917 static int
1918 dn_callback(
1919         Operation*      op,
1920         SlapReply*      rs )
1921 {
1922         dninfo *dni = op->o_callback->sc_private;
1923
1924         if ( rs->sr_type == REP_SEARCH ) {
1925                 if ( !BER_BVISNULL( &dni->dn ) ) {
1926                         Debug( LDAP_DEBUG_ANY,
1927                                 "dn_callback : consistency error - "
1928                                 "entryUUID is not unique\n", 0, 0, 0 );
1929                 } else {
1930                         ber_dupbv_x( &dni->dn, &rs->sr_entry->e_name, op->o_tmpmemctx );
1931                         ber_dupbv_x( &dni->ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx );
1932                         /* If there is a new entry, see if it differs from the old.
1933                          * We compare the non-normalized values so that cosmetic changes
1934                          * in the provider are always propagated.
1935                          */
1936                         if ( dni->new_entry ) {
1937                                 Attribute *old, *new;
1938                                 int i;
1939
1940                                 /* Did the DN change? Note that we don't explicitly try to
1941                                  * discover if the deleteOldRdn argument applies here. It
1942                                  * would save an unnecessary Modify if we detected it, but
1943                                  * that's a fair amount of trouble to compare the two attr
1944                                  * lists in detail.
1945                                  */
1946                                 if ( !dn_match( &rs->sr_entry->e_name,
1947                                                 &dni->new_entry->e_name ) )
1948                                 {
1949                                         dni->renamed = 1;
1950                                 }
1951
1952                                 for ( i = 0, old = rs->sr_entry->e_attrs;
1953                                                 old;
1954                                                 i++, old = old->a_next )
1955                                         ;
1956
1957                                 dni->attrs = i;
1958
1959                                 /* We assume that attributes are saved in the same order
1960                                  * in the remote and local databases. So if we walk through
1961                                  * the attributeDescriptions one by one they should match in
1962                                  * lock step. If not, we signal a change. Otherwise we test
1963                                  * all the values...
1964                                  */
1965                                 for ( old = rs->sr_entry->e_attrs, new = dni->new_entry->e_attrs;
1966                                                 old && new;
1967                                                 old = old->a_next, new = new->a_next )
1968                                 {
1969                                         if ( old->a_desc != new->a_desc ) {
1970                                                 dni->wasChanged = 1;
1971                                                 break;
1972                                         }
1973                                         for ( i = 0; ; i++ ) {
1974                                                 int nold, nnew;
1975                                                 nold = BER_BVISNULL( &old->a_vals[i] );
1976                                                 nnew = BER_BVISNULL( &new->a_vals[i] );
1977                                                 /* If both are empty, stop looking */
1978                                                 if ( nold && nnew ) {
1979                                                         break;
1980                                                 }
1981                                                 /* If they are different, stop looking */
1982                                                 if ( nold != nnew ) {
1983                                                         dni->wasChanged = 1;
1984                                                         break;
1985                                                 }
1986                                                 if ( ber_bvcmp( &old->a_vals[i], &new->a_vals[i] )) {
1987                                                         dni->wasChanged = 1;
1988                                                         break;
1989                                                 }
1990                                         }
1991                                         if ( dni->wasChanged ) break;
1992                                 }
1993                                 if ( dni->wasChanged ) {
1994                                         dni->ads = op->o_tmpalloc( dni->attrs *
1995                                                 sizeof(AttributeDescription *), op->o_tmpmemctx );
1996                                         i = 0;
1997                                         for ( old = rs->sr_entry->e_attrs; old; old = old->a_next ) {
1998                                                 dni->ads[i] = old->a_desc;
1999                                                 i++;
2000                                         }
2001                                 }
2002                         }
2003                 }
2004         } else if ( rs->sr_type == REP_RESULT ) {
2005                 if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) {
2006                         Debug( LDAP_DEBUG_ANY,
2007                                 "dn_callback : consistency error - "
2008                                 "entryUUID is not unique\n", 0, 0, 0 );
2009                 }
2010         }
2011
2012         return LDAP_SUCCESS;
2013 }
2014
2015 static int
2016 nonpresent_callback(
2017         Operation*      op,
2018         SlapReply*      rs )
2019 {
2020         syncinfo_t *si = op->o_callback->sc_private;
2021         Attribute *a;
2022         int count = 0;
2023         struct berval* present_uuid = NULL;
2024         struct nonpresent_entry *np_entry;
2025
2026         if ( rs->sr_type == REP_RESULT ) {
2027                 count = avl_free( si->si_presentlist, avl_ber_bvfree );
2028                 si->si_presentlist = NULL;
2029
2030         } else if ( rs->sr_type == REP_SEARCH ) {
2031                 if ( !(si->si_refreshDelete & NP_DELETE_ONE )) {
2032                         a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
2033
2034                         if ( a == NULL ) return 0;
2035
2036                         present_uuid = avl_find( si->si_presentlist, &a->a_nvals[0],
2037                                 syncuuid_cmp );
2038                 }
2039
2040                 if ( present_uuid == NULL ) {
2041                         np_entry = (struct nonpresent_entry *)
2042                                 ch_calloc( 1, sizeof( struct nonpresent_entry ));
2043                         np_entry->npe_name = ber_dupbv( NULL, &rs->sr_entry->e_name );
2044                         np_entry->npe_nname = ber_dupbv( NULL, &rs->sr_entry->e_nname );
2045                         LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link );
2046
2047                 } else {
2048                         avl_delete( &si->si_presentlist,
2049                                         &a->a_nvals[0], syncuuid_cmp );
2050                         ch_free( present_uuid->bv_val );
2051                         ch_free( present_uuid );
2052                 }
2053         }
2054         return LDAP_SUCCESS;
2055 }
2056
2057 static int
2058 null_callback(
2059         Operation*      op,
2060         SlapReply*      rs )
2061 {
2062         if ( rs->sr_err != LDAP_SUCCESS &&
2063                 rs->sr_err != LDAP_REFERRAL &&
2064                 rs->sr_err != LDAP_ALREADY_EXISTS &&
2065                 rs->sr_err != LDAP_NO_SUCH_OBJECT &&
2066                 rs->sr_err != LDAP_NOT_ALLOWED_ON_NONLEAF )
2067         {
2068                 Debug( LDAP_DEBUG_ANY,
2069                         "null_callback : error code 0x%x\n",
2070                         rs->sr_err, 0, 0 );
2071         }
2072         return LDAP_SUCCESS;
2073 }
2074
2075 static struct berval *
2076 slap_uuidstr_from_normalized(
2077         struct berval* uuidstr,
2078         struct berval* normalized,
2079         void *ctx )
2080 {
2081         struct berval *new;
2082         unsigned char nibble;
2083         int i, d = 0;
2084
2085         if ( normalized == NULL ) return NULL;
2086         if ( normalized->bv_len != 16 ) return NULL;
2087
2088         if ( uuidstr ) {
2089                 new = uuidstr;
2090         } else {
2091                 new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx );
2092                 if ( new == NULL ) {
2093                         return NULL;
2094                 }
2095         }
2096
2097         new->bv_len = 36;
2098
2099         if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) {
2100                 if ( new != uuidstr ) {
2101                         slap_sl_free( new, ctx );
2102                 }
2103                 return NULL;
2104         }
2105
2106         for ( i = 0; i < 16; i++ ) {
2107                 if ( i == 4 || i == 6 || i == 8 || i == 10 ) {
2108                         new->bv_val[(i<<1)+d] = '-';
2109                         d += 1;
2110                 }
2111
2112                 nibble = (normalized->bv_val[i] >> 4) & 0xF;
2113                 if ( nibble < 10 ) {
2114                         new->bv_val[(i<<1)+d] = nibble + '0';
2115                 } else {
2116                         new->bv_val[(i<<1)+d] = nibble - 10 + 'a';
2117                 }
2118
2119                 nibble = (normalized->bv_val[i]) & 0xF;
2120                 if ( nibble < 10 ) {
2121                         new->bv_val[(i<<1)+d+1] = nibble + '0';
2122                 } else {
2123                         new->bv_val[(i<<1)+d+1] = nibble - 10 + 'a';
2124                 }
2125         }
2126
2127         new->bv_val[new->bv_len] = '\0';
2128         return new;
2129 }
2130
2131 static int
2132 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
2133 {
2134         const struct berval *uuid1 = v_uuid1;
2135         const struct berval *uuid2 = v_uuid2;
2136         int rc = uuid1->bv_len - uuid2->bv_len;
2137         if ( rc ) return rc;
2138         return ( memcmp( uuid1->bv_val, uuid2->bv_val, uuid1->bv_len ) );
2139 }
2140
2141 static void
2142 avl_ber_bvfree( void *v_bv )
2143 {
2144         struct berval   *bv = (struct berval *)v_bv;
2145         
2146         if( v_bv == NULL ) return;
2147         if ( !BER_BVISNULL( bv ) ) {
2148                 ch_free( bv->bv_val );
2149         }
2150         ch_free( (char *) bv );
2151 }
2152
2153 void
2154 syncinfo_free( syncinfo_t *sie )
2155 {
2156         ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
2157         if ( !BER_BVISNULL( &sie->si_provideruri ) ) {
2158                 ch_free( sie->si_provideruri.bv_val );
2159         }
2160
2161         bindconf_free( &sie->si_bindconf );
2162
2163         if ( sie->si_filterstr.bv_val ) {
2164                 ch_free( sie->si_filterstr.bv_val );
2165         }
2166         if ( sie->si_base.bv_val ) {
2167                 ch_free( sie->si_base.bv_val );
2168         }
2169         if ( sie->si_attrs ) {
2170                 int i = 0;
2171                 while ( sie->si_attrs[i] != NULL ) {
2172                         ch_free( sie->si_attrs[i] );
2173                         i++;
2174                 }
2175                 ch_free( sie->si_attrs );
2176         }
2177         if ( sie->si_exattrs ) {
2178                 int i = 0;
2179                 while ( sie->si_exattrs[i] != NULL ) {
2180                         ch_free( sie->si_exattrs[i] );
2181                         i++;
2182                 }
2183                 ch_free( sie->si_exattrs );
2184         }
2185         if ( sie->si_anlist ) {
2186                 int i = 0;
2187                 while ( sie->si_anlist[i].an_name.bv_val != NULL ) {
2188                         ch_free( sie->si_anlist[i].an_name.bv_val );
2189                         i++;
2190                 }
2191                 ch_free( sie->si_anlist );
2192         }
2193         if ( sie->si_exanlist ) {
2194                 int i = 0;
2195                 while ( sie->si_exanlist[i].an_name.bv_val != NULL ) {
2196                         ch_free( sie->si_exanlist[i].an_name.bv_val );
2197                         i++;
2198                 }
2199                 ch_free( sie->si_exanlist );
2200         }
2201         if ( sie->si_retryinterval ) {
2202                 ch_free( sie->si_retryinterval );
2203         }
2204         if ( sie->si_retrynum ) {
2205                 ch_free( sie->si_retrynum );
2206         }
2207         if ( sie->si_retrynum_init ) {
2208                 ch_free( sie->si_retrynum_init );
2209         }
2210         slap_sync_cookie_free( &sie->si_syncCookie, 0 );
2211         if ( sie->si_presentlist ) {
2212             avl_free( sie->si_presentlist, avl_ber_bvfree );
2213         }
2214         if ( sie->si_ld ) {
2215                 ldap_ld_free( sie->si_ld, 1, NULL, NULL );
2216         }
2217         while ( !LDAP_LIST_EMPTY( &sie->si_nonpresentlist )) {
2218                 struct nonpresent_entry* npe;
2219                 npe = LDAP_LIST_FIRST( &sie->si_nonpresentlist );
2220                 LDAP_LIST_REMOVE( npe, npe_link );
2221                 if ( npe->npe_name ) {
2222                         if ( npe->npe_name->bv_val ) {
2223                                 ch_free( npe->npe_name->bv_val );
2224                         }
2225                         ch_free( npe->npe_name );
2226                 }
2227                 if ( npe->npe_nname ) {
2228                         if ( npe->npe_nname->bv_val ) {
2229                                 ch_free( npe->npe_nname->bv_val );
2230                         }
2231                         ch_free( npe->npe_nname );
2232                 }
2233                 ch_free( npe );
2234         }
2235         ch_free( sie );
2236 }
2237
2238
2239
2240 /* NOTE: used & documented in slapd.conf(5) */
2241 #define IDSTR                   "rid"
2242 #define PROVIDERSTR             "provider"
2243 #define SCHEMASTR               "schemachecking"
2244 #define FILTERSTR               "filter"
2245 #define SEARCHBASESTR           "searchbase"
2246 #define SCOPESTR                "scope"
2247 #define ATTRSONLYSTR            "attrsonly"
2248 #define ATTRSSTR                "attrs"
2249 #define TYPESTR                 "type"
2250 #define INTERVALSTR             "interval"
2251 #define RETRYSTR                "retry"
2252 #define SLIMITSTR               "sizelimit"
2253 #define TLIMITSTR               "timelimit"
2254
2255 /* FIXME: undocumented */
2256 #define OLDAUTHCSTR             "bindprincipal"
2257 #define EXATTRSSTR              "exattrs"
2258 #define MANAGEDSAITSTR          "manageDSAit"
2259
2260 /* FIXME: unused */
2261 #define LASTMODSTR              "lastmod"
2262 #define LMGENSTR                "gen"
2263 #define LMNOSTR                 "no"
2264 #define LMREQSTR                "req"
2265 #define SRVTABSTR               "srvtab"
2266 #define SUFFIXSTR               "suffix"
2267
2268 /* mandatory */
2269 #define GOT_ID                  0x0001
2270 #define GOT_PROVIDER            0x0002
2271
2272 /* check */
2273 #define GOT_ALL                 (GOT_ID|GOT_PROVIDER)
2274
2275 static struct {
2276         struct berval key;
2277         int val;
2278 } scopes[] = {
2279         { BER_BVC("base"), LDAP_SCOPE_BASE },
2280         { BER_BVC("one"), LDAP_SCOPE_ONELEVEL },
2281         { BER_BVC("onelevel"), LDAP_SCOPE_ONELEVEL },   /* OpenLDAP extension */
2282 #ifdef LDAP_SCOPE_SUBORDINATE
2283         { BER_BVC("children"), LDAP_SCOPE_SUBORDINATE },
2284         { BER_BVC("subordinate"), LDAP_SCOPE_SUBORDINATE },
2285 #endif
2286         { BER_BVC("sub"), LDAP_SCOPE_SUBTREE },
2287         { BER_BVC("subtree"), LDAP_SCOPE_SUBTREE },     /* OpenLDAP extension */
2288         { BER_BVNULL, 0 }
2289 };
2290
2291 static int
2292 parse_syncrepl_line(
2293         char            **cargv,
2294         int             cargc,
2295         syncinfo_t      *si
2296 )
2297 {
2298         int     gots = 0;
2299         int     i;
2300         char    *val;
2301
2302         for ( i = 1; i < cargc; i++ ) {
2303                 if ( !strncasecmp( cargv[ i ], IDSTR "=",
2304                                         STRLENOF( IDSTR "=" ) ) )
2305                 {
2306                         int tmp;
2307                         /* '\0' string terminator accounts for '=' */
2308                         val = cargv[ i ] + STRLENOF( IDSTR "=" );
2309                         tmp= atoi( val );
2310                         if ( tmp >= 1000 || tmp < 0 ) {
2311                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2312                                          "syncrepl id %d is out of range [0..999]\n", tmp );
2313                                 return -1;
2314                         }
2315                         si->si_rid = tmp;
2316                         gots |= GOT_ID;
2317                 } else if ( !strncasecmp( cargv[ i ], PROVIDERSTR "=",
2318                                         STRLENOF( PROVIDERSTR "=" ) ) )
2319                 {
2320                         val = cargv[ i ] + STRLENOF( PROVIDERSTR "=" );
2321                         ber_str2bv( val, 0, 1, &si->si_provideruri );
2322                         gots |= GOT_PROVIDER;
2323                 } else if ( !strncasecmp( cargv[ i ], SCHEMASTR "=",
2324                                         STRLENOF( SCHEMASTR "=" ) ) )
2325                 {
2326                         val = cargv[ i ] + STRLENOF( SCHEMASTR "=" );
2327                         if ( !strncasecmp( val, "on", STRLENOF( "on" ) )) {
2328                                 si->si_schemachecking = 1;
2329                         } else if ( !strncasecmp( val, "off", STRLENOF( "off" ) ) ) {
2330                                 si->si_schemachecking = 0;
2331                         } else {
2332                                 si->si_schemachecking = 1;
2333                         }
2334                 } else if ( !strncasecmp( cargv[ i ], FILTERSTR "=",
2335                                         STRLENOF( FILTERSTR "=" ) ) )
2336                 {
2337                         val = cargv[ i ] + STRLENOF( FILTERSTR "=" );
2338                         ber_str2bv( val, 0, 1, &si->si_filterstr );
2339                 } else if ( !strncasecmp( cargv[ i ], SEARCHBASESTR "=",
2340                                         STRLENOF( SEARCHBASESTR "=" ) ) )
2341                 {
2342                         struct berval   bv;
2343                         int             rc;
2344
2345                         val = cargv[ i ] + STRLENOF( SEARCHBASESTR "=" );
2346                         if ( si->si_base.bv_val ) {
2347                                 ch_free( si->si_base.bv_val );
2348                         }
2349                         ber_str2bv( val, 0, 0, &bv );
2350                         rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_base, NULL );
2351                         if ( rc != LDAP_SUCCESS ) {
2352                                 fprintf( stderr, "Invalid base DN \"%s\": %d (%s)\n",
2353                                         val, rc, ldap_err2string( rc ) );
2354                                 return -1;
2355                         }
2356                 } else if ( !strncasecmp( cargv[ i ], SCOPESTR "=",
2357                                         STRLENOF( SCOPESTR "=" ) ) )
2358                 {
2359                         int j;
2360                         val = cargv[ i ] + STRLENOF( SCOPESTR "=" );
2361                         for ( j=0; !BER_BVISNULL(&scopes[j].key); j++ ) {
2362                                 if (!strcasecmp( val, scopes[j].key.bv_val )) {
2363                                         si->si_scope = scopes[j].val;
2364                                         break;
2365                                 }
2366                         }
2367                         if ( BER_BVISNULL(&scopes[j].key) ) {
2368                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2369                                         "unknown scope \"%s\"\n", val);
2370                                 return -1;
2371                         }
2372                 } else if ( !strncasecmp( cargv[ i ], ATTRSONLYSTR "=",
2373                                         STRLENOF( ATTRSONLYSTR "=" ) ) )
2374                 {
2375                         si->si_attrsonly = 1;
2376                 } else if ( !strncasecmp( cargv[ i ], ATTRSSTR "=",
2377                                         STRLENOF( ATTRSSTR "=" ) ) )
2378                 {
2379                         val = cargv[ i ] + STRLENOF( ATTRSSTR "=" );
2380                         if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) {
2381                                 char *attr_fname;
2382                                 attr_fname = ch_strdup( val + STRLENOF(":include:") );
2383                                 si->si_anlist = file2anlist( si->si_anlist, attr_fname, " ,\t" );
2384                                 if ( si->si_anlist == NULL ) {
2385                                         ch_free( attr_fname );
2386                                         return -1;
2387                                 }
2388                                 si->si_anfile = attr_fname;
2389                         } else {
2390                                 char *str, *s, *next;
2391                                 char delimstr[] = " ,\t";
2392                                 str = ch_strdup( val );
2393                                 for ( s = ldap_pvt_strtok( str, delimstr, &next );
2394                                                 s != NULL;
2395                                                 s = ldap_pvt_strtok( NULL, delimstr, &next ) )
2396                                 {
2397                                         if ( strlen(s) == 1 && *s == '*' ) {
2398                                                 si->si_allattrs = 1;
2399                                                 *(val + ( s - str )) = delimstr[0];
2400                                         }
2401                                         if ( strlen(s) == 1 && *s == '+' ) {
2402                                                 si->si_allopattrs = 1;
2403                                                 *(val + ( s - str )) = delimstr[0];
2404                                         }
2405                                 }
2406                                 ch_free( str );
2407                                 si->si_anlist = str2anlist( si->si_anlist, val, " ,\t" );
2408                                 if ( si->si_anlist == NULL ) {
2409                                         return -1;
2410                                 }
2411                         }
2412                 } else if ( !strncasecmp( cargv[ i ], EXATTRSSTR "=",
2413                                         STRLENOF( EXATTRSSTR "=" ) ) )
2414                 {
2415                         val = cargv[ i ] + STRLENOF( EXATTRSSTR "=" );
2416                         if ( !strncasecmp( val, ":include:", STRLENOF(":include:") )) {
2417                                 char *attr_fname;
2418                                 attr_fname = ch_strdup( val + STRLENOF(":include:") );
2419                                 si->si_exanlist = file2anlist(
2420                                                                         si->si_exanlist, attr_fname, " ,\t" );
2421                                 if ( si->si_exanlist == NULL ) {
2422                                         ch_free( attr_fname );
2423                                         return -1;
2424                                 }
2425                                 ch_free( attr_fname );
2426                         } else {
2427                                 si->si_exanlist = str2anlist( si->si_exanlist, val, " ,\t" );
2428                                 if ( si->si_exanlist == NULL ) {
2429                                         return -1;
2430                                 }
2431                         }
2432                 } else if ( !strncasecmp( cargv[ i ], TYPESTR "=",
2433                                         STRLENOF( TYPESTR "=" ) ) )
2434                 {
2435                         val = cargv[ i ] + STRLENOF( TYPESTR "=" );
2436                         if ( !strncasecmp( val, "refreshOnly",
2437                                                 STRLENOF("refreshOnly") ))
2438                         {
2439                                 si->si_type = LDAP_SYNC_REFRESH_ONLY;
2440                         } else if ( !strncasecmp( val, "refreshAndPersist",
2441                                                 STRLENOF("refreshAndPersist") ))
2442                         {
2443                                 si->si_type = LDAP_SYNC_REFRESH_AND_PERSIST;
2444                                 si->si_interval = 60;
2445                         } else {
2446                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2447                                         "unknown sync type \"%s\"\n", val);
2448                                 return -1;
2449                         }
2450                 } else if ( !strncasecmp( cargv[ i ], INTERVALSTR "=",
2451                                         STRLENOF( INTERVALSTR "=" ) ) )
2452                 {
2453                         val = cargv[ i ] + STRLENOF( INTERVALSTR "=" );
2454                         if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
2455                                 si->si_interval = 0;
2456                         } else {
2457                                 char *hstr;
2458                                 char *mstr;
2459                                 char *dstr;
2460                                 char *sstr;
2461                                 int dd, hh, mm, ss;
2462                                 dstr = val;
2463                                 hstr = strchr( dstr, ':' );
2464                                 if ( hstr == NULL ) {
2465                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2466                                                 "invalid interval \"%s\"\n", val );
2467                                         return -1;
2468                                 }
2469                                 *hstr++ = '\0';
2470                                 mstr = strchr( hstr, ':' );
2471                                 if ( mstr == NULL ) {
2472                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2473                                                 "invalid interval \"%s\"\n", val );
2474                                         return -1;
2475                                 }
2476                                 *mstr++ = '\0';
2477                                 sstr = strchr( mstr, ':' );
2478                                 if ( sstr == NULL ) {
2479                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2480                                                 "invalid interval \"%s\"\n", val );
2481                                         return -1;
2482                                 }
2483                                 *sstr++ = '\0';
2484
2485                                 dd = atoi( dstr );
2486                                 hh = atoi( hstr );
2487                                 mm = atoi( mstr );
2488                                 ss = atoi( sstr );
2489                                 if (( hh > 24 ) || ( hh < 0 ) ||
2490                                         ( mm > 60 ) || ( mm < 0 ) ||
2491                                         ( ss > 60 ) || ( ss < 0 ) || ( dd < 0 )) {
2492                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2493                                                 "invalid interval \"%s\"\n", val );
2494                                         return -1;
2495                                 }
2496                                 si->si_interval = (( dd * 24 + hh ) * 60 + mm ) * 60 + ss;
2497                         }
2498                         if ( si->si_interval < 0 ) {
2499                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2500                                         "invalid interval \"%ld\"\n",
2501                                         (long) si->si_interval);
2502                                 return -1;
2503                         }
2504                 } else if ( !strncasecmp( cargv[ i ], RETRYSTR "=",
2505                                         STRLENOF( RETRYSTR "=" ) ) )
2506                 {
2507                         char **retry_list;
2508                         int j, k, n;
2509
2510                         val = cargv[ i ] + STRLENOF( RETRYSTR "=" );
2511                         retry_list = (char **) ch_calloc( 1, sizeof( char * ));
2512                         retry_list[0] = NULL;
2513
2514                         slap_str2clist( &retry_list, val, " ,\t" );
2515
2516                         for ( k = 0; retry_list && retry_list[k]; k++ ) ;
2517                         n = k / 2;
2518                         if ( k % 2 ) {
2519                                 fprintf( stderr,
2520                                                 "Error: incomplete syncrepl retry list\n" );
2521                                 for ( k = 0; retry_list && retry_list[k]; k++ ) {
2522                                         ch_free( retry_list[k] );
2523                                 }
2524                                 ch_free( retry_list );
2525                                 exit( EXIT_FAILURE );
2526                         }
2527                         si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t ));
2528                         si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int ));
2529                         si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int ));
2530                         for ( j = 0; j < n; j++ ) {
2531                                 si->si_retryinterval[j] = atoi( retry_list[j*2] );
2532                                 if ( *retry_list[j*2+1] == '+' ) {
2533                                         si->si_retrynum_init[j] = -1;
2534                                         si->si_retrynum[j] = -1;
2535                                         j++;
2536                                         break;
2537                                 } else {
2538                                         si->si_retrynum_init[j] = atoi( retry_list[j*2+1] );
2539                                         si->si_retrynum[j] = atoi( retry_list[j*2+1] );
2540                                 }
2541                         }
2542                         si->si_retrynum_init[j] = -2;
2543                         si->si_retrynum[j] = -2;
2544                         si->si_retryinterval[j] = 0;
2545                         
2546                         for ( k = 0; retry_list && retry_list[k]; k++ ) {
2547                                 ch_free( retry_list[k] );
2548                         }
2549                         ch_free( retry_list );
2550                 } else if ( !strncasecmp( cargv[ i ], MANAGEDSAITSTR "=",
2551                                         STRLENOF( MANAGEDSAITSTR "=" ) ) )
2552                 {
2553                         val = cargv[ i ] + STRLENOF( MANAGEDSAITSTR "=" );
2554                         si->si_manageDSAit = atoi( val );
2555                 } else if ( !strncasecmp( cargv[ i ], SLIMITSTR "=",
2556                                         STRLENOF( SLIMITSTR "=") ) )
2557                 {
2558                         val = cargv[ i ] + STRLENOF( SLIMITSTR "=" );
2559                         si->si_slimit = atoi( val );
2560                 } else if ( !strncasecmp( cargv[ i ], TLIMITSTR "=",
2561                                         STRLENOF( TLIMITSTR "=" ) ) )
2562                 {
2563                         val = cargv[ i ] + STRLENOF( TLIMITSTR "=" );
2564                         si->si_tlimit = atoi( val );
2565                 } else if ( bindconf_parse( cargv[i], &si->si_bindconf )) {
2566                         fprintf( stderr, "Error: parse_syncrepl_line: "
2567                                 "unknown keyword \"%s\"\n", cargv[ i ] );
2568                         return -1;
2569                 }
2570         }
2571
2572         if ( gots != GOT_ALL ) {
2573                 fprintf( stderr,
2574                         "Error: Malformed \"syncrepl\" line in slapd config file" );
2575                 return -1;
2576         }
2577
2578         return 0;
2579 }
2580
2581 static int
2582 add_syncrepl(
2583         Backend *be,
2584         char    **cargv,
2585         int     cargc
2586 )
2587 {
2588         syncinfo_t *si;
2589         int     rc = 0;
2590
2591         if ( !( be->be_search && be->be_add && be->be_modify && be->be_delete )) {
2592                 Debug( LDAP_DEBUG_ANY, "database %s does not support operations "
2593                         "required for syncrepl\n", be->be_type, 0, 0 );
2594                 return 1;
2595         }
2596         si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) );
2597
2598         if ( si == NULL ) {
2599                 Debug( LDAP_DEBUG_ANY, "out of memory in add_syncrepl\n", 0, 0, 0 );
2600                 return 1;
2601         }
2602
2603         si->si_bindconf.sb_tls = SB_TLS_OFF;
2604         si->si_bindconf.sb_method = LDAP_AUTH_SIMPLE;
2605         si->si_schemachecking = 0;
2606         ber_str2bv( "(objectclass=*)", STRLENOF("(objectclass=*)"), 1,
2607                 &si->si_filterstr );
2608         si->si_base.bv_val = NULL;
2609         si->si_scope = LDAP_SCOPE_SUBTREE;
2610         si->si_attrsonly = 0;
2611         si->si_anlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ));
2612         si->si_exanlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ));
2613         si->si_attrs = NULL;
2614         si->si_allattrs = 0;
2615         si->si_allopattrs = 0;
2616         si->si_exattrs = NULL;
2617         si->si_type = LDAP_SYNC_REFRESH_ONLY;
2618         si->si_interval = 86400;
2619         si->si_retryinterval = NULL;
2620         si->si_retrynum_init = NULL;
2621         si->si_retrynum = NULL;
2622         si->si_manageDSAit = 0;
2623         si->si_tlimit = 0;
2624         si->si_slimit = 0;
2625
2626         si->si_presentlist = NULL;
2627         LDAP_LIST_INIT( &si->si_nonpresentlist );
2628         ldap_pvt_thread_mutex_init( &si->si_mutex );
2629
2630         rc = parse_syncrepl_line( cargv, cargc, si );
2631
2632         if ( rc == 0 ) {
2633                 si->si_be = be;
2634                 init_syncrepl( si );
2635                 si->si_re = ldap_pvt_runqueue_insert( &slapd_rq, si->si_interval,
2636                         do_syncrepl, si, "do_syncrepl", be->be_suffix[0].bv_val );
2637                 if ( !si->si_re )
2638                         rc = -1;
2639         }
2640         if ( rc < 0 ) {
2641                 Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n", 0, 0, 0 );
2642                 syncinfo_free( si );    
2643                 return 1;
2644         } else {
2645                 Debug( LDAP_DEBUG_CONFIG,
2646                         "Config: ** successfully added syncrepl \"%s\"\n",
2647                         BER_BVISNULL( &si->si_provideruri ) ?
2648                         "(null)" : si->si_provideruri.bv_val, 0, 0 );
2649                 if ( !si->si_schemachecking ) {
2650                         SLAP_DBFLAGS(be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK;
2651                 }
2652                 be->be_syncinfo = si;
2653                 return 0;
2654         }
2655 }
2656
2657 static void
2658 syncrepl_unparse( syncinfo_t *si, struct berval *bv )
2659 {
2660         struct berval bc;
2661         char buf[BUFSIZ*2], *ptr;
2662         int i;
2663
2664         bindconf_unparse( &si->si_bindconf, &bc );
2665         ptr = buf;
2666         ptr += sprintf( ptr, IDSTR "=%03ld " PROVIDERSTR "=%s",
2667                 si->si_rid, si->si_provideruri.bv_val );
2668         if ( !BER_BVISNULL( &bc )) {
2669                 ptr = lutil_strcopy( ptr, bc.bv_val );
2670                 free( bc.bv_val );
2671         }
2672         if ( !BER_BVISEMPTY( &si->si_filterstr )) {
2673                 ptr = lutil_strcopy( ptr, " " FILTERSTR "=\"" );
2674                 ptr = lutil_strcopy( ptr, si->si_filterstr.bv_val );
2675                 *ptr++ = '"';
2676         }
2677         if ( !BER_BVISNULL( &si->si_base )) {
2678                 ptr = lutil_strcopy( ptr, " " SEARCHBASESTR "=\"" );
2679                 ptr = lutil_strcopy( ptr, si->si_base.bv_val );
2680                 *ptr++ = '"';
2681         }
2682         for (i=0; !BER_BVISNULL(&scopes[i].key);i++) {
2683                 if ( si->si_scope == scopes[i].val ) {
2684                         ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
2685                         ptr = lutil_strcopy( ptr, scopes[i].key.bv_val );
2686                         break;
2687                 }
2688         }
2689         if ( si->si_attrsonly ) {
2690                 ptr = lutil_strcopy( ptr, " " ATTRSONLYSTR "=yes" );
2691         }
2692         if ( si->si_anfile ) {
2693                 ptr = lutil_strcopy( ptr, " " ATTRSSTR "=:include:" );
2694                 ptr = lutil_strcopy( ptr, si->si_anfile );
2695         } else if ( si->si_allattrs || si->si_allopattrs ||
2696                 ( si->si_anlist && !BER_BVISNULL(&si->si_anlist[0].an_name) )) {
2697                 char *old;
2698                 ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" );
2699                 old = ptr;
2700                 ptr = anlist_unparse( si->si_anlist, ptr );
2701                 if ( si->si_allattrs ) {
2702                         if ( old != ptr ) *ptr++ = ',';
2703                         *ptr++ = '*';
2704                 }
2705                 if ( si->si_allopattrs ) {
2706                         if ( old != ptr ) *ptr++ = ',';
2707                         *ptr++ = '+';
2708                 }
2709                 *ptr++ = '"';
2710         }
2711         if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) {
2712                 ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" );
2713                 ptr = anlist_unparse( si->si_exanlist, ptr );
2714         }
2715         ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" );
2716         ptr = lutil_strcopy( ptr, si->si_schemachecking ? "on" : "off" );
2717         
2718         ptr = lutil_strcopy( ptr, " " TYPESTR "=" );
2719         ptr = lutil_strcopy( ptr, si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ?
2720                 "refreshAndPersist" : "refreshOnly" );
2721
2722         if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
2723                 int dd, hh, mm, ss;
2724
2725                 dd = si->si_interval;
2726                 ss = dd % 60;
2727                 dd /= 60;
2728                 mm = dd % 60;
2729                 dd /= 60;
2730                 hh = dd % 24;
2731                 dd /= 24;
2732                 ptr = lutil_strcopy( ptr, " " INTERVALSTR "=" );
2733                 ptr += sprintf( ptr, "%02d:%02d:%02d:%02d", dd, hh, mm, ss );
2734         } else if ( si->si_retryinterval ) {
2735                 int space=0;
2736                 ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" );
2737                 for (i=0; si->si_retryinterval[i]; i++) {
2738                         if ( space ) *ptr++ = ' ';
2739                         space = 1;
2740                         ptr += sprintf( ptr, "%ld ", (long) si->si_retryinterval[i] );
2741                         if ( si->si_retrynum_init[i] == -1 )
2742                                 *ptr++ = '+';
2743                         else
2744                                 ptr += sprintf( ptr, "%d", si->si_retrynum_init[i] );
2745                 }
2746                 *ptr++ = '"';
2747         }
2748
2749         if ( si->si_slimit ) {
2750                 ptr = lutil_strcopy( ptr, " " SLIMITSTR "=" );
2751                 ptr += sprintf( ptr, "%d", si->si_slimit );
2752         }
2753
2754         if ( si->si_tlimit ) {
2755                 ptr = lutil_strcopy( ptr, " " TLIMITSTR "=" );
2756                 ptr += sprintf( ptr, "%d", si->si_tlimit );
2757         }
2758         bc.bv_len = ptr - buf;
2759         bc.bv_val = buf;
2760         ber_dupbv( bv, &bc );
2761 }
2762
2763 int
2764 syncrepl_config(ConfigArgs *c) {
2765         if (c->op == SLAP_CONFIG_EMIT) {
2766                 if ( c->be->be_syncinfo ) {
2767                         struct berval bv;
2768                         syncrepl_unparse( c->be->be_syncinfo, &bv ); 
2769                         ber_bvarray_add( &c->rvalue_vals, &bv );
2770                         return 0;
2771                 }
2772                 return 1;
2773         } else if ( c->op == LDAP_MOD_DELETE ) {
2774                 struct re_s *re;
2775
2776                 if ( c->be->be_syncinfo ) {
2777                         re = c->be->be_syncinfo->si_re;
2778                         if ( re ) {
2779                                 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ))
2780                                         ldap_pvt_runqueue_stoptask( &slapd_rq, re );
2781                                 ldap_pvt_runqueue_remove( &slapd_rq, re );
2782                         }
2783                         syncinfo_free( c->be->be_syncinfo );
2784                         c->be->be_syncinfo = NULL;
2785                 }
2786                 SLAP_DBFLAGS(c->be) &= ~(SLAP_DBFLAG_SHADOW|SLAP_DBFLAG_SYNC_SHADOW);
2787                 return 0;
2788         }
2789         if(SLAP_SHADOW(c->be)) {
2790                 Debug(LDAP_DEBUG_ANY, "%s: "
2791                         "syncrepl: database already shadowed.\n",
2792                         c->log, 0, 0);
2793                 return(1);
2794         } else if(add_syncrepl(c->be, c->argv, c->argc)) {
2795                 return(1);
2796         }
2797         SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SYNC_SHADOW);
2798         return(0);
2799 }