]> git.sur5r.net Git - openldap/blob - servers/slapd/syncrepl.c
Initial round of changes for 2.3 beta
[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 = { 0 };
539         struct sync_cookie      syncCookie_req = { 0 };
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 );
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 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_next = NULL;
1098                 mod->sml_desc = NULL;
1099                 mod->sml_type = tmp.sml_type;
1100                 mod->sml_values = tmp.sml_values;
1101                 mod->sml_nvalues = NULL;
1102
1103                 *modtail = mod;
1104                 modtail = &mod->sml_next;
1105         }
1106
1107         if ( *modlist == NULL ) {
1108                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: no attributes\n",
1109                         0, 0, 0 );
1110                 rc = -1;
1111                 goto done;
1112         }
1113
1114         rc = slap_mods_check( *modlist, &text, txtbuf, textlen, NULL );
1115
1116         if ( rc != LDAP_SUCCESS ) {
1117                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods check (%s)\n",
1118                         text, 0, 0 );
1119                 goto done;
1120         }
1121
1122         /* Strip out dynamically generated attrs */
1123         for ( modtail = modlist; *modtail ; ) {
1124                 mod = *modtail;
1125                 if ( mod->sml_desc->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
1126                         *modtail = mod->sml_next;
1127                         slap_mod_free( &mod->sml_mod, 0 );
1128                         ch_free( mod );
1129                 } else {
1130                         modtail = &mod->sml_next;
1131                 }
1132         }
1133
1134         /* Strip out attrs in exattrs list */
1135         for ( modtail = modlist; *modtail ; ) {
1136                 mod = *modtail;
1137                 if ( ldap_charray_inlist( si->si_exattrs,
1138                                         mod->sml_desc->ad_type->sat_cname.bv_val )) {
1139                         *modtail = mod->sml_next;
1140                         slap_mod_free( &mod->sml_mod, 0 );
1141                         ch_free( mod );
1142                 } else {
1143                         modtail = &mod->sml_next;
1144                 }
1145         }
1146         
1147         rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
1148         if( rc != LDAP_SUCCESS ) {
1149                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods2entry (%s)\n",
1150                         text, 0, 0 );
1151         }
1152
1153 done:
1154         ber_free ( ber, 0 );
1155         if ( rc != LDAP_SUCCESS ) {
1156                 if ( e ) {
1157                         entry_free( e );
1158                         *entry = e = NULL;
1159                 }
1160         }
1161
1162         return rc;
1163 }
1164
1165 static struct berval generic_filterstr = BER_BVC("(objectclass=*)");
1166
1167 /* During a refresh, we may get an LDAP_SYNC_ADD for an already existing
1168  * entry if a previous refresh was interrupted before sending us a new
1169  * context state. We try to compare the new entry to the existing entry
1170  * and ignore the new entry if they are the same.
1171  *
1172  * Also, we may get an update where the entryDN has changed, due to
1173  * a ModDn on the provider. We detect this as well, so we can issue
1174  * the corresponding operation locally.
1175  *
1176  * In the case of a modify, we get a list of all the attributes
1177  * in the original entry. Rather than deleting the entry and re-adding it,
1178  * we issue a Modify request that deletes all the attributes and adds all
1179  * the new ones. This avoids the issue of trying to delete/add a non-leaf
1180  * entry.
1181  *
1182  * We don't try to otherwise distinguish ModDN from Modify; in the case of
1183  * a ModDN we will issue both operations on the local database.
1184  */
1185 typedef struct dninfo {
1186         Entry *new_entry;
1187         struct berval dn;
1188         struct berval ndn;
1189         int renamed;    /* Was an existing entry renamed? */
1190         int wasChanged; /* are the attributes changed? */
1191         int attrs;              /* how many attribute types are in the ads list */
1192         AttributeDescription **ads;
1193 } dninfo;
1194
1195 int
1196 syncrepl_entry(
1197         syncinfo_t* si,
1198         Operation *op,
1199         Entry* entry,
1200         Modifications** modlist,
1201         int syncstate,
1202         struct berval* syncUUID,
1203         struct sync_cookie* syncCookie_req,
1204         struct berval* syncCSN )
1205 {
1206         Backend *be = op->o_bd;
1207         slap_callback   cb = { NULL };
1208         struct berval   *syncuuid_bv = NULL;
1209         struct berval   syncUUID_strrep = BER_BVNULL;
1210         struct berval   uuid_bv = BER_BVNULL;
1211
1212         SlapReply       rs_search = {REP_RESULT};
1213         SlapReply       rs_delete = {REP_RESULT};
1214         SlapReply       rs_add = {REP_RESULT};
1215         SlapReply       rs_modify = {REP_RESULT};
1216         Filter f = {0};
1217 #ifdef LDAP_COMP_MATCH
1218         AttributeAssertion ava = { NULL, BER_BVNULL, NULL };
1219 #else
1220         AttributeAssertion ava = { NULL, BER_BVNULL };
1221 #endif
1222         int rc = LDAP_SUCCESS;
1223         int ret = LDAP_SUCCESS;
1224
1225         struct berval pdn = BER_BVNULL;
1226         dninfo dni = {0};
1227         int     retry = 1;
1228
1229         switch( syncstate ) {
1230         case LDAP_SYNC_PRESENT:
1231                 Debug( LDAP_DEBUG_SYNC, "%s: %s\n",
1232                                         "syncrepl_entry",
1233                                         "LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_PRESENT)", 0 );
1234                 break;
1235         case LDAP_SYNC_ADD:
1236                 Debug( LDAP_DEBUG_SYNC, "%s: %s\n",
1237                                         "syncrepl_entry",
1238                                         "LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_ADD)", 0 );
1239                 break;
1240         case LDAP_SYNC_DELETE:
1241                 Debug( LDAP_DEBUG_SYNC, "%s: %s\n",
1242                                         "syncrepl_entry",
1243                                         "LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_DELETE)", 0 );
1244                 break;
1245         case LDAP_SYNC_MODIFY:
1246                 Debug( LDAP_DEBUG_SYNC, "%s: %s\n",
1247                                         "syncrepl_entry",
1248                                         "LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_MODIFY)", 0 );
1249                 break;
1250         default:
1251                 Debug( LDAP_DEBUG_ANY, "%s: %s\n",
1252                                         "syncrepl_entry",
1253                                         "LDAP_RES_SEARCH_ENTRY(UNKNOWN syncstate)", 0 );
1254         }
1255
1256         if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD )) {
1257                 if ( !si->si_refreshPresent ) {
1258                         syncuuid_bv = ber_dupbv( NULL, syncUUID );
1259                         avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
1260                                 syncuuid_cmp, avl_dup_error );
1261                 }
1262         }
1263
1264         if ( syncstate == LDAP_SYNC_PRESENT ) {
1265                 return 0;
1266         } else if ( syncstate != LDAP_SYNC_DELETE ) {
1267                 if ( entry == NULL ) {
1268                         return 0;
1269                 }
1270         }
1271
1272         f.f_choice = LDAP_FILTER_EQUALITY;
1273         f.f_ava = &ava;
1274         ava.aa_desc = slap_schema.si_ad_entryUUID;
1275         (void)slap_uuidstr_from_normalized( &syncUUID_strrep, syncUUID, op->o_tmpmemctx );
1276         ava.aa_value = *syncUUID;
1277         op->ors_filter = &f;
1278
1279         op->ors_filterstr.bv_len = STRLENOF( "(entryUUID=)" ) + syncUUID->bv_len;
1280         op->ors_filterstr.bv_val = (char *) slap_sl_malloc(
1281                 op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); 
1282         AC_MEMCPY( op->ors_filterstr.bv_val, "(entryUUID=", STRLENOF( "(entryUUID=" ) );
1283         AC_MEMCPY( &op->ors_filterstr.bv_val[STRLENOF( "(entryUUID=" )],
1284                 syncUUID->bv_val, syncUUID->bv_len );
1285         op->ors_filterstr.bv_val[op->ors_filterstr.bv_len - 1] = ')';
1286         op->ors_filterstr.bv_val[op->ors_filterstr.bv_len] = '\0';
1287
1288         op->o_tag = LDAP_REQ_SEARCH;
1289         op->ors_scope = LDAP_SCOPE_SUBTREE;
1290         op->ors_deref = LDAP_DEREF_NEVER;
1291
1292         /* get the entry for this UUID */
1293         op->o_req_dn = si->si_base;
1294         op->o_req_ndn = si->si_base;
1295
1296         op->o_time = slap_get_time();
1297         op->ors_tlimit = SLAP_NO_LIMIT;
1298         op->ors_slimit = 1;
1299
1300         op->ors_attrs = slap_anlist_all_attributes;
1301         op->ors_attrsonly = 0;
1302
1303         /* set callback function */
1304         op->o_callback = &cb;
1305         cb.sc_response = dn_callback;
1306         cb.sc_private = &dni;
1307         dni.new_entry = entry;
1308
1309         if ( limits_check( op, &rs_search ) == 0 ) {
1310                 rc = be->be_search( op, &rs_search );
1311                 Debug( LDAP_DEBUG_SYNC,
1312                                 "syncrepl_entry: %s (%d)\n", 
1313                                 "be_search", rc, 0 );
1314         }
1315
1316         if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
1317                 slap_sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1318         }
1319
1320         cb.sc_response = null_callback;
1321         cb.sc_private = si;
1322
1323         if ( entry && !BER_BVISNULL( &entry->e_name ) ) {
1324                 Debug( LDAP_DEBUG_SYNC,
1325                                 "syncrepl_entry: %s\n",
1326                                 entry->e_name.bv_val, 0, 0 );
1327         } else {
1328                 Debug( LDAP_DEBUG_SYNC,
1329                                 "syncrepl_entry: %s\n",
1330                                 dni.dn.bv_val ? dni.dn.bv_val : "(null)", 0, 0 );
1331         }
1332
1333         if ( syncstate != LDAP_SYNC_DELETE ) {
1334                 Attribute       *a = attr_find( entry->e_attrs, slap_schema.si_ad_entryUUID );
1335
1336                 if ( a == NULL ) {
1337                         /* add if missing */
1338                         attr_merge_one( entry, slap_schema.si_ad_entryUUID,
1339                                 &syncUUID_strrep, syncUUID );
1340
1341                 } else if ( !bvmatch( &a->a_nvals[0], syncUUID ) ) {
1342                         /* replace only if necessary */
1343                         if ( a->a_nvals != a->a_vals ) {
1344                                 ber_memfree( a->a_nvals[0].bv_val );
1345                                 ber_dupbv( &a->a_nvals[0], syncUUID );
1346                         }
1347                         ber_memfree( a->a_vals[0].bv_val );
1348                         ber_dupbv( &a->a_vals[0], &syncUUID_strrep );
1349                 }
1350         }
1351
1352         switch ( syncstate ) {
1353         case LDAP_SYNC_ADD:
1354         case LDAP_SYNC_MODIFY:
1355 retry_add:;
1356                 if ( BER_BVISNULL( &dni.dn )) {
1357
1358                         op->o_req_dn = entry->e_name;
1359                         op->o_req_ndn = entry->e_nname;
1360                         op->o_tag = LDAP_REQ_ADD;
1361                         op->ora_e = entry;
1362
1363                         rc = be->be_add( op, &rs_add );
1364                         Debug( LDAP_DEBUG_SYNC,
1365                                         "syncrepl_entry: %s (%d)\n", 
1366                                         "be_add", rc, 0 );
1367                         switch ( rs_add.sr_err ) {
1368                         case LDAP_SUCCESS:
1369                                 be_entry_release_w( op, entry );
1370                                 ret = 0;
1371                                 break;
1372
1373                         case LDAP_REFERRAL:
1374                         /* we assume that LDAP_NO_SUCH_OBJECT is returned 
1375                          * only if the suffix entry is not present */
1376                         case LDAP_NO_SUCH_OBJECT:
1377                                 syncrepl_add_glue( op, entry );
1378                                 ret = 0;
1379                                 break;
1380
1381                         /* if an entry was added via syncrepl_add_glue(),
1382                          * it likely has no entryUUID, so the previous
1383                          * be_search() doesn't find it.  In this case,
1384                          * give syncrepl a chance to modify it. Also
1385                          * allow for entries that were recreated with the
1386                          * same DN but a different entryUUID.
1387                          */
1388                         case LDAP_ALREADY_EXISTS:
1389                                 if ( retry ) {
1390                                         Operation       op2 = *op;
1391                                         SlapReply       rs2 = { 0 };
1392                                         slap_callback   cb2 = { 0 };
1393
1394                                         op2.o_tag = LDAP_REQ_SEARCH;
1395                                         op2.o_req_dn = entry->e_name;
1396                                         op2.o_req_ndn = entry->e_nname;
1397                                         op2.ors_scope = LDAP_SCOPE_BASE;
1398                                         op2.ors_deref = LDAP_DEREF_NEVER;
1399                                         op2.ors_attrs = slap_anlist_all_attributes;
1400                                         op2.ors_attrsonly = 0;
1401                                         op2.ors_limit = NULL;
1402                                         op2.ors_slimit = 1;
1403                                         op2.ors_tlimit = SLAP_NO_LIMIT;
1404
1405                                         f.f_choice = LDAP_FILTER_PRESENT;
1406                                         f.f_desc = slap_schema.si_ad_objectClass;
1407                                         op2.ors_filter = &f;
1408                                         op2.ors_filterstr = generic_filterstr;
1409
1410                                         op2.o_callback = &cb2;
1411                                         cb2.sc_response = dn_callback;
1412                                         cb2.sc_private = &dni;
1413
1414                                         be->be_search( &op2, &rs2 );
1415
1416                                         retry = 0;
1417                                         goto retry_add;
1418                                 }
1419                                 /* FALLTHRU */
1420
1421                         default:
1422                                 Debug( LDAP_DEBUG_ANY,
1423                                         "syncrepl_entry : be_add failed (%d)\n",
1424                                         rs_add.sr_err, 0, 0 );
1425                                 ret = 1;
1426                                 break;
1427                         }
1428                         goto done;
1429                 }
1430                 /* FALLTHRU */
1431                 op->o_req_dn = dni.dn;
1432                 op->o_req_ndn = dni.ndn;
1433                 if ( dni.renamed ) {
1434                         struct berval noldp, newp, nnewp;
1435
1436                         op->o_tag = LDAP_REQ_MODRDN;
1437                         dnRdn( &entry->e_name, &op->orr_newrdn );
1438                         dnRdn( &entry->e_nname, &op->orr_nnewrdn );
1439
1440                         dnParent( &dni.ndn, &noldp );
1441                         dnParent( &entry->e_nname, &nnewp );
1442                         if ( !dn_match( &noldp, &newp )) {
1443                                 dnParent( &entry->e_name, &newp );
1444                                 op->orr_newSup = &newp;
1445                                 op->orr_nnewSup = &nnewp;
1446                         }
1447                         op->orr_deleteoldrdn = 0;
1448                         rc = be->be_modrdn( op, &rs_modify );
1449                         Debug( LDAP_DEBUG_SYNC,
1450                                         "syncrepl_entry: %s (%d)\n", 
1451                                         "be_modrdn", rc, 0 );
1452                         if ( rs_modify.sr_err == LDAP_SUCCESS ) {
1453                                 op->o_req_dn = entry->e_name;
1454                                 op->o_req_ndn = entry->e_nname;
1455                         } else {
1456                                 ret = 1;
1457                                 goto done;
1458                         }
1459                 }
1460                 if ( dni.wasChanged ) {
1461                         Modifications *mod, *modhead = NULL;
1462                         Modifications *modtail = NULL;
1463                         int i;
1464
1465                         op->o_tag = LDAP_REQ_MODIFY;
1466
1467                         assert( *modlist );
1468
1469                         /* Delete all the old attrs */
1470                         for ( i = 0; i < dni.attrs; i++ ) {
1471                                 mod = ch_malloc( sizeof( Modifications ) );
1472                                 mod->sml_op = LDAP_MOD_DELETE;
1473                                 mod->sml_desc = dni.ads[i];
1474                                 mod->sml_type = mod->sml_desc->ad_cname;
1475                                 mod->sml_values = NULL;
1476                                 mod->sml_nvalues = NULL;
1477                                 if ( !modhead ) modhead = mod;
1478                                 if ( modtail ) {
1479                                         modtail->sml_next = mod;
1480                                 }
1481                                 modtail = mod;
1482                         }
1483
1484                         /* Append passed in list to ours */
1485                         if ( modtail ) {
1486                                 modtail->sml_next = *modlist;
1487                                 *modlist = modhead;
1488                         } else {
1489                                 mod = *modlist;
1490                         }
1491
1492                         /* Find end of this list */
1493                         for ( ; mod != NULL; mod = mod->sml_next ) {
1494                                 modtail = mod;
1495                         }
1496
1497                         mod = (Modifications *)ch_calloc(1, sizeof(Modifications));
1498                         mod->sml_op = LDAP_MOD_REPLACE;
1499                         mod->sml_desc = slap_schema.si_ad_entryUUID;
1500                         mod->sml_type = mod->sml_desc->ad_cname;
1501                         ber_dupbv( &uuid_bv, &syncUUID_strrep );
1502                         ber_bvarray_add( &mod->sml_values, &uuid_bv );
1503                         ber_dupbv( &uuid_bv, syncUUID );
1504                         ber_bvarray_add( &mod->sml_nvalues, &uuid_bv );
1505                         modtail->sml_next = mod;
1506                                         
1507                         op->o_tag = LDAP_REQ_MODIFY;
1508                         op->orm_modlist = *modlist;
1509
1510                         rc = be->be_modify( op, &rs_modify );
1511                         Debug( LDAP_DEBUG_SYNC,
1512                                         "syncrepl_entry: %s (%d)\n", 
1513                                         "be_modify", rc, 0 );
1514                         if ( rs_modify.sr_err != LDAP_SUCCESS ) {
1515                                 Debug( LDAP_DEBUG_ANY,
1516                                         "syncrepl_entry : be_modify failed (%d)\n",
1517                                         rs_modify.sr_err, 0, 0 );
1518                         }
1519                 }
1520                 ret = 1;
1521                 goto done;
1522         case LDAP_SYNC_DELETE :
1523                 if ( !BER_BVISNULL( &dni.dn )) {
1524                         op->o_req_dn = dni.dn;
1525                         op->o_req_ndn = dni.ndn;
1526                         op->o_tag = LDAP_REQ_DELETE;
1527                         rc = be->be_delete( op, &rs_delete );
1528                         Debug( LDAP_DEBUG_SYNC,
1529                                         "syncrepl_entry: %s (%d)\n", 
1530                                         "be_delete", rc, 0 );
1531
1532                         while ( rs_delete.sr_err == LDAP_SUCCESS
1533                                 && op->o_delete_glue_parent ) {
1534                                 op->o_delete_glue_parent = 0;
1535                                 if ( !be_issuffix( op->o_bd, &op->o_req_ndn )) {
1536                                         slap_callback cb = { NULL };
1537                                         cb.sc_response = slap_null_cb;
1538                                         dnParent( &op->o_req_ndn, &pdn );
1539                                         op->o_req_dn = pdn;
1540                                         op->o_req_ndn = pdn;
1541                                         op->o_callback = &cb;
1542                                         op->o_bd->be_delete( op, &rs_delete );
1543                                 } else {
1544                                         break;
1545                                 }
1546                         }
1547                 }
1548                 ret = 0;
1549                 goto done;
1550
1551         default :
1552                 Debug( LDAP_DEBUG_ANY,
1553                         "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1554                 ret = 1;
1555                 goto done;
1556         }
1557
1558 done :
1559         if ( !BER_BVISNULL( &syncUUID_strrep ) ) {
1560                 slap_sl_free( syncUUID_strrep.bv_val, op->o_tmpmemctx );
1561                 BER_BVZERO( &syncUUID_strrep );
1562         }
1563         if ( dni.ads ) {
1564                 op->o_tmpfree( dni.ads, op->o_tmpmemctx );
1565         }
1566         if ( !BER_BVISNULL( &dni.ndn ) ) {
1567                 op->o_tmpfree( dni.ndn.bv_val, op->o_tmpmemctx );
1568         }
1569         if ( !BER_BVISNULL( &dni.dn ) ) {
1570                 op->o_tmpfree( dni.dn.bv_val, op->o_tmpmemctx );
1571         }
1572         return ret;
1573 }
1574
1575 static struct berval gcbva[] = {
1576         BER_BVC("top"),
1577         BER_BVC("glue"),
1578         BER_BVNULL
1579 };
1580
1581 #define NP_DELETE_ONE   2
1582
1583 static void
1584 syncrepl_del_nonpresent(
1585         Operation *op,
1586         syncinfo_t *si,
1587         BerVarray uuids )
1588 {
1589         Backend* be = op->o_bd;
1590         slap_callback   cb = { NULL };
1591         SlapReply       rs_search = {REP_RESULT};
1592         SlapReply       rs_delete = {REP_RESULT};
1593         SlapReply       rs_modify = {REP_RESULT};
1594         struct nonpresent_entry *np_list, *np_prev;
1595         int rc;
1596         AttributeName   an[2];
1597
1598         struct berval pdn = BER_BVNULL;
1599
1600         op->o_req_dn = si->si_base;
1601         op->o_req_ndn = si->si_base;
1602
1603         cb.sc_response = nonpresent_callback;
1604         cb.sc_private = si;
1605
1606         op->o_callback = &cb;
1607         op->o_tag = LDAP_REQ_SEARCH;
1608         op->ors_scope = si->si_scope;
1609         op->ors_deref = LDAP_DEREF_NEVER;
1610         op->o_time = slap_get_time();
1611         op->ors_tlimit = SLAP_NO_LIMIT;
1612
1613
1614         if ( uuids ) {
1615                 Filter uf;
1616 #ifdef LDAP_COMP_MATCH
1617                 AttributeAssertion eq = { NULL, BER_BVNULL, NULL };
1618 #else
1619                 AttributeAssertion eq = { NULL, BER_BVNULL };
1620 #endif
1621                 int i;
1622
1623                 op->ors_attrsonly = 1;
1624                 op->ors_attrs = slap_anlist_no_attrs;
1625                 op->ors_limit = NULL;
1626                 op->ors_filter = &uf;
1627
1628                 uf.f_ava = &eq;
1629                 uf.f_av_desc = slap_schema.si_ad_entryUUID;
1630                 uf.f_next = NULL;
1631                 uf.f_choice = LDAP_FILTER_EQUALITY;
1632                 si->si_refreshDelete |= NP_DELETE_ONE;
1633
1634                 for (i=0; uuids[i].bv_val; i++) {
1635                         op->ors_slimit = 1;
1636                         uf.f_av_value = uuids[i];
1637                         rc = be->be_search( op, &rs_search );
1638                 }
1639                 si->si_refreshDelete ^= NP_DELETE_ONE;
1640         } else {
1641                 memset( &an[0], 0, 2 * sizeof( AttributeName ) );
1642                 an[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
1643                 an[0].an_desc = slap_schema.si_ad_entryUUID;
1644                 op->ors_attrs = an;
1645                 op->ors_slimit = SLAP_NO_LIMIT;
1646                 op->ors_attrsonly = 0;
1647                 op->ors_filter = str2filter_x( op, si->si_filterstr.bv_val );
1648                 op->ors_filterstr = si->si_filterstr;
1649                 op->o_nocaching = 1;
1650
1651                 if ( limits_check( op, &rs_search ) == 0 ) {
1652                         rc = be->be_search( op, &rs_search );
1653                 }
1654                 if ( op->ors_filter ) filter_free_x( op, op->ors_filter );
1655         }
1656
1657         op->o_nocaching = 0;
1658
1659         if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
1660
1661                 slap_queue_csn( op, &si->si_syncCookie.ctxcsn );
1662
1663                 np_list = LDAP_LIST_FIRST( &si->si_nonpresentlist );
1664                 while ( np_list != NULL ) {
1665                         LDAP_LIST_REMOVE( np_list, npe_link );
1666                         np_prev = np_list;
1667                         np_list = LDAP_LIST_NEXT( np_list, npe_link );
1668                         op->o_tag = LDAP_REQ_DELETE;
1669                         op->o_callback = &cb;
1670                         cb.sc_response = null_callback;
1671                         cb.sc_private = si;
1672                         op->o_req_dn = *np_prev->npe_name;
1673                         op->o_req_ndn = *np_prev->npe_nname;
1674                         rc = op->o_bd->be_delete( op, &rs_delete );
1675
1676                         if ( rs_delete.sr_err == LDAP_NOT_ALLOWED_ON_NONLEAF ) {
1677                                 Modifications mod1, mod2;
1678                                 mod1.sml_op = LDAP_MOD_REPLACE;
1679                                 mod1.sml_desc = slap_schema.si_ad_objectClass;
1680                                 mod1.sml_type = mod1.sml_desc->ad_cname;
1681                                 mod1.sml_values = &gcbva[0];
1682                                 mod1.sml_nvalues = NULL;
1683                                 mod1.sml_next = &mod2;
1684
1685                                 mod2.sml_op = LDAP_MOD_REPLACE;
1686                                 mod2.sml_desc = slap_schema.si_ad_structuralObjectClass;
1687                                 mod2.sml_type = mod2.sml_desc->ad_cname;
1688                                 mod2.sml_values = &gcbva[1];
1689                                 mod2.sml_nvalues = NULL;
1690                                 mod2.sml_next = NULL;
1691
1692                                 op->o_tag = LDAP_REQ_MODIFY;
1693                                 op->orm_modlist = &mod1;
1694
1695                                 rc = be->be_modify( op, &rs_modify );
1696                         }
1697
1698                         while ( rs_delete.sr_err == LDAP_SUCCESS &&
1699                                         op->o_delete_glue_parent ) {
1700                                 op->o_delete_glue_parent = 0;
1701                                 if ( !be_issuffix( op->o_bd, &op->o_req_ndn )) {
1702                                         slap_callback cb = { NULL };
1703                                         cb.sc_response = slap_null_cb;
1704                                         dnParent( &op->o_req_ndn, &pdn );
1705                                         op->o_req_dn = pdn;
1706                                         op->o_req_ndn = pdn;
1707                                         op->o_callback = &cb;
1708                                         /* give it a root privil ? */
1709                                         op->o_bd->be_delete( op, &rs_delete );
1710                                 } else {
1711                                         break;
1712                             }
1713                         }
1714
1715                         op->o_delete_glue_parent = 0;
1716
1717                         ber_bvfree( np_prev->npe_name );
1718                         ber_bvfree( np_prev->npe_nname );
1719                         ch_free( np_prev );
1720                 }
1721
1722                 slap_graduate_commit_csn( op );
1723         }
1724
1725         return;
1726 }
1727
1728 void
1729 syncrepl_add_glue(
1730         Operation* op,
1731         Entry *e )
1732 {
1733         Backend *be = op->o_bd;
1734         slap_callback cb = { NULL };
1735         Attribute       *a;
1736         int     rc;
1737         int suffrdns;
1738         int i;
1739         struct berval dn = {0, NULL};
1740         struct berval ndn = {0, NULL};
1741         Entry   *glue;
1742         SlapReply       rs_add = {REP_RESULT};
1743         char    *ptr, *comma;
1744
1745         op->o_tag = LDAP_REQ_ADD;
1746         op->o_callback = &cb;
1747         cb.sc_response = null_callback;
1748         cb.sc_private = NULL;
1749
1750         dn = e->e_name;
1751         ndn = e->e_nname;
1752
1753         /* count RDNs in suffix */
1754         if ( !BER_BVISEMPTY( &be->be_nsuffix[0] ) ) {
1755                 for ( i = 0, ptr = be->be_nsuffix[0].bv_val; ptr; ptr = strchr( ptr, ',' ) ) {
1756                         ptr++;
1757                         i++;
1758                 }
1759                 suffrdns = i;
1760         } else {
1761                 /* suffix is "" */
1762                 suffrdns = 0;
1763         }
1764
1765         /* Start with BE suffix */
1766         for ( i = 0, ptr = NULL; i < suffrdns; i++ ) {
1767                 comma = strrchr( dn.bv_val, ',' );
1768                 if ( ptr ) *ptr = ',';
1769                 if ( comma ) *comma = '\0';
1770                 ptr = comma;
1771         }
1772         if ( ptr ) {
1773                 *ptr++ = ',';
1774                 dn.bv_len -= ptr - dn.bv_val;
1775                 dn.bv_val = ptr;
1776         }
1777         /* the normalizedDNs are always the same length, no counting
1778          * required.
1779          */
1780         if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) {
1781                 ndn.bv_val += ndn.bv_len - be->be_nsuffix[0].bv_len;
1782                 ndn.bv_len = be->be_nsuffix[0].bv_len;
1783         }
1784
1785         while ( ndn.bv_val > e->e_nname.bv_val ) {
1786                 glue = (Entry *) ch_calloc( 1, sizeof(Entry) );
1787                 ber_dupbv( &glue->e_name, &dn );
1788                 ber_dupbv( &glue->e_nname, &ndn );
1789
1790                 a = ch_calloc( 1, sizeof( Attribute ));
1791                 a->a_desc = slap_schema.si_ad_objectClass;
1792
1793                 a->a_vals = ch_calloc( 3, sizeof( struct berval ));
1794                 ber_dupbv( &a->a_vals[0], &gcbva[0] );
1795                 ber_dupbv( &a->a_vals[1], &gcbva[1] );
1796                 ber_dupbv( &a->a_vals[2], &gcbva[2] );
1797
1798                 a->a_nvals = a->a_vals;
1799
1800                 a->a_next = glue->e_attrs;
1801                 glue->e_attrs = a;
1802
1803                 a = ch_calloc( 1, sizeof( Attribute ));
1804                 a->a_desc = slap_schema.si_ad_structuralObjectClass;
1805
1806                 a->a_vals = ch_calloc( 2, sizeof( struct berval ));
1807                 ber_dupbv( &a->a_vals[0], &gcbva[1] );
1808                 ber_dupbv( &a->a_vals[1], &gcbva[2] );
1809
1810                 a->a_nvals = a->a_vals;
1811
1812                 a->a_next = glue->e_attrs;
1813                 glue->e_attrs = a;
1814
1815                 op->o_req_dn = glue->e_name;
1816                 op->o_req_ndn = glue->e_nname;
1817                 op->ora_e = glue;
1818                 rc = be->be_add ( op, &rs_add );
1819                 if ( rs_add.sr_err == LDAP_SUCCESS ) {
1820                         be_entry_release_w( op, glue );
1821                 } else {
1822                 /* incl. ALREADY EXIST */
1823                         entry_free( glue );
1824                 }
1825
1826                 /* Move to next child */
1827                 for (ptr = dn.bv_val-2; ptr > e->e_name.bv_val && *ptr != ','; ptr--) {
1828                         /* empty */
1829                 }
1830                 if ( ptr == e->e_name.bv_val ) break;
1831                 dn.bv_val = ++ptr;
1832                 dn.bv_len = e->e_name.bv_len - (ptr-e->e_name.bv_val);
1833                 for( ptr = ndn.bv_val-2;
1834                         ptr > e->e_nname.bv_val && *ptr != ',';
1835                         ptr--)
1836                 {
1837                         /* empty */
1838                 }
1839                 ndn.bv_val = ++ptr;
1840                 ndn.bv_len = e->e_nname.bv_len - (ptr-e->e_nname.bv_val);
1841         }
1842
1843         op->o_req_dn = e->e_name;
1844         op->o_req_ndn = e->e_nname;
1845         op->ora_e = e;
1846         rc = be->be_add ( op, &rs_add );
1847         if ( rs_add.sr_err == LDAP_SUCCESS ) {
1848                 be_entry_release_w( op, e );
1849         } else {
1850                 entry_free( e );
1851         }
1852
1853         return;
1854 }
1855
1856 void
1857 syncrepl_updateCookie(
1858         syncinfo_t *si,
1859         Operation *op,
1860         struct berval *pdn,
1861         struct sync_cookie *syncCookie )
1862 {
1863         Backend *be = op->o_bd;
1864         Modifications mod = {0};
1865         struct berval vals[2];
1866
1867         int rc;
1868
1869         slap_callback cb = { NULL };
1870         SlapReply       rs_modify = {REP_RESULT};
1871
1872         slap_sync_cookie_free( &si->si_syncCookie, 0 );
1873         slap_dup_sync_cookie( &si->si_syncCookie, syncCookie );
1874
1875         mod.sml_op = LDAP_MOD_REPLACE;
1876         mod.sml_desc = slap_schema.si_ad_contextCSN;
1877         mod.sml_type = mod.sml_desc->ad_cname;
1878         mod.sml_values = vals;
1879         vals[0] = si->si_syncCookie.ctxcsn;
1880         vals[1].bv_val = NULL;
1881         vals[1].bv_len = 0;
1882
1883         slap_queue_csn( op, &si->si_syncCookie.ctxcsn );
1884
1885         op->o_tag = LDAP_REQ_MODIFY;
1886
1887         assert( si->si_rid < 1000 );
1888
1889         cb.sc_response = null_callback;
1890         cb.sc_private = si;
1891
1892         op->o_callback = &cb;
1893         op->o_req_dn = op->o_bd->be_suffix[0];
1894         op->o_req_ndn = op->o_bd->be_nsuffix[0];
1895
1896         /* update contextCSN */
1897         op->o_msgid = SLAP_SYNC_UPDATE_MSGID;
1898         op->orm_modlist = &mod;
1899         rc = be->be_modify( op, &rs_modify );
1900         op->o_msgid = 0;
1901
1902         if ( rs_modify.sr_err != LDAP_SUCCESS ) {
1903                 Debug( LDAP_DEBUG_ANY,
1904                         "be_modify failed (%d)\n", rs_modify.sr_err, 0, 0 );
1905         }
1906
1907         slap_graduate_commit_csn( op );
1908
1909         return;
1910 }
1911
1912 static int
1913 dn_callback(
1914         Operation*      op,
1915         SlapReply*      rs )
1916 {
1917         dninfo *dni = op->o_callback->sc_private;
1918
1919         if ( rs->sr_type == REP_SEARCH ) {
1920                 if ( !BER_BVISNULL( &dni->dn ) ) {
1921                         Debug( LDAP_DEBUG_ANY,
1922                                 "dn_callback : consistency error - "
1923                                 "entryUUID is not unique\n", 0, 0, 0 );
1924                 } else {
1925                         ber_dupbv_x( &dni->dn, &rs->sr_entry->e_name, op->o_tmpmemctx );
1926                         ber_dupbv_x( &dni->ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx );
1927                         /* If there is a new entry, see if it differs from the old.
1928                          * We compare the non-normalized values so that cosmetic changes
1929                          * in the provider are always propagated.
1930                          */
1931                         if ( dni->new_entry ) {
1932                                 Attribute *old, *new;
1933                                 int i;
1934
1935                                 /* Did the DN change? Note that we don't explicitly try to
1936                                  * discover if the deleteOldRdn argument applies here. It
1937                                  * would save an unnecessary Modify if we detected it, but
1938                                  * that's a fair amount of trouble to compare the two attr
1939                                  * lists in detail.
1940                                  */
1941                                 if ( !dn_match( &rs->sr_entry->e_name,
1942                                                 &dni->new_entry->e_name ) )
1943                                 {
1944                                         dni->renamed = 1;
1945                                 }
1946
1947                                 for ( i = 0, old = rs->sr_entry->e_attrs;
1948                                                 old;
1949                                                 i++, old = old->a_next )
1950                                         ;
1951
1952                                 dni->attrs = i;
1953
1954                                 /* We assume that attributes are saved in the same order
1955                                  * in the remote and local databases. So if we walk through
1956                                  * the attributeDescriptions one by one they should match in
1957                                  * lock step. If not, we signal a change. Otherwise we test
1958                                  * all the values...
1959                                  */
1960                                 for ( old = rs->sr_entry->e_attrs, new = dni->new_entry->e_attrs;
1961                                                 old && new;
1962                                                 old = old->a_next, new = new->a_next )
1963                                 {
1964                                         if ( old->a_desc != new->a_desc ) {
1965                                                 dni->wasChanged = 1;
1966                                                 break;
1967                                         }
1968                                         for ( i = 0; ; i++ ) {
1969                                                 int nold, nnew;
1970                                                 nold = BER_BVISNULL( &old->a_vals[i] );
1971                                                 nnew = BER_BVISNULL( &new->a_vals[i] );
1972                                                 /* If both are empty, stop looking */
1973                                                 if ( nold && nnew ) {
1974                                                         break;
1975                                                 }
1976                                                 /* If they are different, stop looking */
1977                                                 if ( nold != nnew ) {
1978                                                         dni->wasChanged = 1;
1979                                                         break;
1980                                                 }
1981                                                 if ( ber_bvcmp( &old->a_vals[i], &new->a_vals[i] )) {
1982                                                         dni->wasChanged = 1;
1983                                                         break;
1984                                                 }
1985                                         }
1986                                         if ( dni->wasChanged ) break;
1987                                 }
1988                                 if ( dni->wasChanged ) {
1989                                         dni->ads = op->o_tmpalloc( dni->attrs *
1990                                                 sizeof(AttributeDescription *), op->o_tmpmemctx );
1991                                         i = 0;
1992                                         for ( old = rs->sr_entry->e_attrs; old; old = old->a_next ) {
1993                                                 dni->ads[i] = old->a_desc;
1994                                                 i++;
1995                                         }
1996                                 }
1997                         }
1998                 }
1999         } else if ( rs->sr_type == REP_RESULT ) {
2000                 if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) {
2001                         Debug( LDAP_DEBUG_ANY,
2002                                 "dn_callback : consistency error - "
2003                                 "entryUUID is not unique\n", 0, 0, 0 );
2004                 }
2005         }
2006
2007         return LDAP_SUCCESS;
2008 }
2009
2010 static int
2011 nonpresent_callback(
2012         Operation*      op,
2013         SlapReply*      rs )
2014 {
2015         syncinfo_t *si = op->o_callback->sc_private;
2016         Attribute *a;
2017         int count = 0;
2018         struct berval* present_uuid = NULL;
2019         struct nonpresent_entry *np_entry;
2020
2021         if ( rs->sr_type == REP_RESULT ) {
2022                 count = avl_free( si->si_presentlist, avl_ber_bvfree );
2023                 si->si_presentlist = NULL;
2024
2025         } else if ( rs->sr_type == REP_SEARCH ) {
2026                 if ( !(si->si_refreshDelete & NP_DELETE_ONE )) {
2027                         a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
2028
2029                         if ( a == NULL ) return 0;
2030
2031                         present_uuid = avl_find( si->si_presentlist, &a->a_nvals[0],
2032                                 syncuuid_cmp );
2033                 }
2034
2035                 if ( present_uuid == NULL ) {
2036                         np_entry = (struct nonpresent_entry *)
2037                                 ch_calloc( 1, sizeof( struct nonpresent_entry ));
2038                         np_entry->npe_name = ber_dupbv( NULL, &rs->sr_entry->e_name );
2039                         np_entry->npe_nname = ber_dupbv( NULL, &rs->sr_entry->e_nname );
2040                         LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link );
2041
2042                 } else {
2043                         avl_delete( &si->si_presentlist,
2044                                         &a->a_nvals[0], syncuuid_cmp );
2045                         ch_free( present_uuid->bv_val );
2046                         ch_free( present_uuid );
2047                 }
2048         }
2049         return LDAP_SUCCESS;
2050 }
2051
2052 static int
2053 null_callback(
2054         Operation*      op,
2055         SlapReply*      rs )
2056 {
2057         if ( rs->sr_err != LDAP_SUCCESS &&
2058                 rs->sr_err != LDAP_REFERRAL &&
2059                 rs->sr_err != LDAP_ALREADY_EXISTS &&
2060                 rs->sr_err != LDAP_NO_SUCH_OBJECT &&
2061                 rs->sr_err != LDAP_NOT_ALLOWED_ON_NONLEAF )
2062         {
2063                 Debug( LDAP_DEBUG_ANY,
2064                         "null_callback : error code 0x%x\n",
2065                         rs->sr_err, 0, 0 );
2066         }
2067         return LDAP_SUCCESS;
2068 }
2069
2070 struct berval *
2071 slap_uuidstr_from_normalized(
2072         struct berval* uuidstr,
2073         struct berval* normalized,
2074         void *ctx )
2075 {
2076         struct berval *new;
2077         unsigned char nibble;
2078         int i, d = 0;
2079
2080         if ( normalized == NULL ) return NULL;
2081         if ( normalized->bv_len != 16 ) return NULL;
2082
2083         if ( uuidstr ) {
2084                 new = uuidstr;
2085         } else {
2086                 new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx );
2087                 if ( new == NULL ) {
2088                         return NULL;
2089                 }
2090         }
2091
2092         new->bv_len = 36;
2093
2094         if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) {
2095                 if ( new != uuidstr ) {
2096                         slap_sl_free( new, ctx );
2097                 }
2098                 return NULL;
2099         }
2100
2101         for ( i = 0; i < 16; i++ ) {
2102                 if ( i == 4 || i == 6 || i == 8 || i == 10 ) {
2103                         new->bv_val[(i<<1)+d] = '-';
2104                         d += 1;
2105                 }
2106
2107                 nibble = (normalized->bv_val[i] >> 4) & 0xF;
2108                 if ( nibble < 10 ) {
2109                         new->bv_val[(i<<1)+d] = nibble + '0';
2110                 } else {
2111                         new->bv_val[(i<<1)+d] = nibble - 10 + 'a';
2112                 }
2113
2114                 nibble = (normalized->bv_val[i]) & 0xF;
2115                 if ( nibble < 10 ) {
2116                         new->bv_val[(i<<1)+d+1] = nibble + '0';
2117                 } else {
2118                         new->bv_val[(i<<1)+d+1] = nibble - 10 + 'a';
2119                 }
2120         }
2121
2122         new->bv_val[new->bv_len] = '\0';
2123         return new;
2124 }
2125
2126 static int
2127 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
2128 {
2129         const struct berval *uuid1 = v_uuid1;
2130         const struct berval *uuid2 = v_uuid2;
2131         int rc = uuid1->bv_len - uuid2->bv_len;
2132         if ( rc ) return rc;
2133         return ( memcmp( uuid1->bv_val, uuid2->bv_val, uuid1->bv_len ) );
2134 }
2135
2136 static void
2137 avl_ber_bvfree( void *v_bv )
2138 {
2139         struct berval   *bv = (struct berval *)v_bv;
2140         
2141         if( v_bv == NULL ) return;
2142         if ( !BER_BVISNULL( bv ) ) {
2143                 ch_free( bv->bv_val );
2144         }
2145         ch_free( (char *) bv );
2146 }
2147
2148 void
2149 syncinfo_free( syncinfo_t *sie )
2150 {
2151         ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
2152         if ( !BER_BVISNULL( &sie->si_provideruri ) ) {
2153                 ch_free( sie->si_provideruri.bv_val );
2154         }
2155
2156         bindconf_free( &sie->si_bindconf );
2157
2158         if ( sie->si_filterstr.bv_val ) {
2159                 ch_free( sie->si_filterstr.bv_val );
2160         }
2161         if ( sie->si_base.bv_val ) {
2162                 ch_free( sie->si_base.bv_val );
2163         }
2164         if ( sie->si_attrs ) {
2165                 int i = 0;
2166                 while ( sie->si_attrs[i] != NULL ) {
2167                         ch_free( sie->si_attrs[i] );
2168                         i++;
2169                 }
2170                 ch_free( sie->si_attrs );
2171         }
2172         if ( sie->si_exattrs ) {
2173                 int i = 0;
2174                 while ( sie->si_exattrs[i] != NULL ) {
2175                         ch_free( sie->si_exattrs[i] );
2176                         i++;
2177                 }
2178                 ch_free( sie->si_exattrs );
2179         }
2180         if ( sie->si_anlist ) {
2181                 int i = 0;
2182                 while ( sie->si_anlist[i].an_name.bv_val != NULL ) {
2183                         ch_free( sie->si_anlist[i].an_name.bv_val );
2184                         i++;
2185                 }
2186                 ch_free( sie->si_anlist );
2187         }
2188         if ( sie->si_exanlist ) {
2189                 int i = 0;
2190                 while ( sie->si_exanlist[i].an_name.bv_val != NULL ) {
2191                         ch_free( sie->si_exanlist[i].an_name.bv_val );
2192                         i++;
2193                 }
2194                 ch_free( sie->si_exanlist );
2195         }
2196         if ( sie->si_retryinterval ) {
2197                 ch_free( sie->si_retryinterval );
2198         }
2199         if ( sie->si_retrynum ) {
2200                 ch_free( sie->si_retrynum );
2201         }
2202         if ( sie->si_retrynum_init ) {
2203                 ch_free( sie->si_retrynum_init );
2204         }
2205         slap_sync_cookie_free( &sie->si_syncCookie, 0 );
2206         if ( sie->si_presentlist ) {
2207             avl_free( sie->si_presentlist, avl_ber_bvfree );
2208         }
2209         if ( sie->si_ld ) {
2210                 ldap_ld_free( sie->si_ld, 1, NULL, NULL );
2211         }
2212         while ( !LDAP_LIST_EMPTY( &sie->si_nonpresentlist )) {
2213                 struct nonpresent_entry* npe;
2214                 npe = LDAP_LIST_FIRST( &sie->si_nonpresentlist );
2215                 LDAP_LIST_REMOVE( npe, npe_link );
2216                 if ( npe->npe_name ) {
2217                         if ( npe->npe_name->bv_val ) {
2218                                 ch_free( npe->npe_name->bv_val );
2219                         }
2220                         ch_free( npe->npe_name );
2221                 }
2222                 if ( npe->npe_nname ) {
2223                         if ( npe->npe_nname->bv_val ) {
2224                                 ch_free( npe->npe_nname->bv_val );
2225                         }
2226                         ch_free( npe->npe_nname );
2227                 }
2228                 ch_free( npe );
2229         }
2230         ch_free( sie );
2231 }
2232
2233
2234
2235 /* NOTE: used & documented in slapd.conf(5) */
2236 #define IDSTR                   "rid"
2237 #define PROVIDERSTR             "provider"
2238 #define TYPESTR                 "type"
2239 #define INTERVALSTR             "interval"
2240 #define SEARCHBASESTR           "searchbase"
2241 #define FILTERSTR               "filter"
2242 #define SCOPESTR                "scope"
2243 #define ATTRSSTR                "attrs"
2244 #define ATTRSONLYSTR            "attrsonly"
2245 #define SLIMITSTR               "sizelimit"
2246 #define TLIMITSTR               "timelimit"
2247 #define SCHEMASTR               "schemachecking"
2248
2249 /* FIXME: undocumented */
2250 #define OLDAUTHCSTR             "bindprincipal"
2251 #define EXATTRSSTR              "exattrs"
2252 #define RETRYSTR                "retry"
2253
2254 /* FIXME: unused */
2255 #define LASTMODSTR              "lastmod"
2256 #define LMGENSTR                "gen"
2257 #define LMNOSTR                 "no"
2258 #define LMREQSTR                "req"
2259 #define SRVTABSTR               "srvtab"
2260 #define SUFFIXSTR               "suffix"
2261 #define MANAGEDSAITSTR          "manageDSAit"
2262
2263 /* mandatory */
2264 #define GOT_ID                  0x0001
2265 #define GOT_PROVIDER            0x0002
2266
2267 /* check */
2268 #define GOT_ALL                 (GOT_ID|GOT_PROVIDER)
2269
2270 static struct {
2271         struct berval key;
2272         int val;
2273 } scopes[] = {
2274         { BER_BVC("base"), LDAP_SCOPE_BASE },
2275         { BER_BVC("one"), LDAP_SCOPE_ONELEVEL },
2276 #ifdef LDAP_SCOPE_SUBORDINATE
2277         { BER_BVC("children"), LDAP_SCOPE_SUBORDINATE },
2278         { BER_BVC("subordinate"), 0 },
2279 #endif
2280         { BER_BVC("sub"), LDAP_SCOPE_SUBTREE },
2281         { BER_BVNULL, 0 }
2282 };
2283
2284 static int
2285 parse_syncrepl_line(
2286         char            **cargv,
2287         int             cargc,
2288         syncinfo_t      *si
2289 )
2290 {
2291         int     gots = 0;
2292         int     i;
2293         char    *val;
2294
2295         for ( i = 1; i < cargc; i++ ) {
2296                 if ( !strncasecmp( cargv[ i ], IDSTR "=",
2297                                         STRLENOF( IDSTR "=" ) ) )
2298                 {
2299                         int tmp;
2300                         /* '\0' string terminator accounts for '=' */
2301                         val = cargv[ i ] + STRLENOF( IDSTR "=" );
2302                         tmp= atoi( val );
2303                         if ( tmp >= 1000 || tmp < 0 ) {
2304                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2305                                          "syncrepl id %d is out of range [0..999]\n", tmp );
2306                                 return -1;
2307                         }
2308                         si->si_rid = tmp;
2309                         gots |= GOT_ID;
2310                 } else if ( !strncasecmp( cargv[ i ], PROVIDERSTR "=",
2311                                         STRLENOF( PROVIDERSTR "=" ) ) )
2312                 {
2313                         val = cargv[ i ] + STRLENOF( PROVIDERSTR "=" );
2314                         ber_str2bv( val, 0, 1, &si->si_provideruri );
2315                         gots |= GOT_PROVIDER;
2316                 } else if ( !strncasecmp( cargv[ i ], SCHEMASTR "=",
2317                                         STRLENOF( SCHEMASTR "=" ) ) )
2318                 {
2319                         val = cargv[ i ] + STRLENOF( SCHEMASTR "=" );
2320                         if ( !strncasecmp( val, "on", STRLENOF( "on" ) )) {
2321                                 si->si_schemachecking = 1;
2322                         } else if ( !strncasecmp( val, "off", STRLENOF( "off" ) ) ) {
2323                                 si->si_schemachecking = 0;
2324                         } else {
2325                                 si->si_schemachecking = 1;
2326                         }
2327                 } else if ( !strncasecmp( cargv[ i ], FILTERSTR "=",
2328                                         STRLENOF( FILTERSTR "=" ) ) )
2329                 {
2330                         val = cargv[ i ] + STRLENOF( FILTERSTR "=" );
2331                         ber_str2bv( val, 0, 1, &si->si_filterstr );
2332                 } else if ( !strncasecmp( cargv[ i ], SEARCHBASESTR "=",
2333                                         STRLENOF( SEARCHBASESTR "=" ) ) )
2334                 {
2335                         struct berval   bv;
2336                         int             rc;
2337
2338                         val = cargv[ i ] + STRLENOF( SEARCHBASESTR "=" );
2339                         if ( si->si_base.bv_val ) {
2340                                 ch_free( si->si_base.bv_val );
2341                         }
2342                         ber_str2bv( val, 0, 0, &bv );
2343                         rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_base, NULL );
2344                         if ( rc != LDAP_SUCCESS ) {
2345                                 fprintf( stderr, "Invalid base DN \"%s\": %d (%s)\n",
2346                                         val, rc, ldap_err2string( rc ) );
2347                                 return -1;
2348                         }
2349                 } else if ( !strncasecmp( cargv[ i ], SCOPESTR "=",
2350                                         STRLENOF( SCOPESTR "=" ) ) )
2351                 {
2352                         int j;
2353                         val = cargv[ i ] + STRLENOF( SCOPESTR "=" );
2354                         for ( j=0; !BER_BVISNULL(&scopes[j].key); j++ ) {
2355                                 if (!strncasecmp( val, scopes[j].key.bv_val,
2356                                         scopes[j].key.bv_len )) {
2357                                         while (!scopes[j].val) j--;
2358                                         si->si_scope = scopes[j].val;
2359                                         break;
2360                                 }
2361                         }
2362                         if ( BER_BVISNULL(&scopes[j].key) ) {
2363                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2364                                         "unknown scope \"%s\"\n", val);
2365                                 return -1;
2366                         }
2367                 } else if ( !strncasecmp( cargv[ i ], ATTRSONLYSTR "=",
2368                                         STRLENOF( ATTRSONLYSTR "=" ) ) )
2369                 {
2370                         si->si_attrsonly = 1;
2371                 } else if ( !strncasecmp( cargv[ i ], ATTRSSTR "=",
2372                                         STRLENOF( ATTRSSTR "=" ) ) )
2373                 {
2374                         val = cargv[ i ] + STRLENOF( ATTRSSTR "=" );
2375                         if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) {
2376                                 char *attr_fname;
2377                                 attr_fname = ch_strdup( val + STRLENOF(":include:") );
2378                                 si->si_anlist = file2anlist( si->si_anlist, attr_fname, " ,\t" );
2379                                 if ( si->si_anlist == NULL ) {
2380                                         ch_free( attr_fname );
2381                                         return -1;
2382                                 }
2383                                 si->si_anfile = attr_fname;
2384                         } else {
2385                                 char *str, *s, *next;
2386                                 char delimstr[] = " ,\t";
2387                                 str = ch_strdup( val );
2388                                 for ( s = ldap_pvt_strtok( str, delimstr, &next );
2389                                                 s != NULL;
2390                                                 s = ldap_pvt_strtok( NULL, delimstr, &next ) )
2391                                 {
2392                                         if ( strlen(s) == 1 && *s == '*' ) {
2393                                                 si->si_allattrs = 1;
2394                                                 *(val + ( s - str )) = delimstr[0];
2395                                         }
2396                                         if ( strlen(s) == 1 && *s == '+' ) {
2397                                                 si->si_allopattrs = 1;
2398                                                 *(val + ( s - str )) = delimstr[0];
2399                                         }
2400                                 }
2401                                 ch_free( str );
2402                                 si->si_anlist = str2anlist( si->si_anlist, val, " ,\t" );
2403                                 if ( si->si_anlist == NULL ) {
2404                                         return -1;
2405                                 }
2406                         }
2407                 } else if ( !strncasecmp( cargv[ i ], EXATTRSSTR "=",
2408                                         STRLENOF( EXATTRSSTR "=" ) ) )
2409                 {
2410                         val = cargv[ i ] + STRLENOF( EXATTRSSTR "=" );
2411                         if ( !strncasecmp( val, ":include:", STRLENOF(":include:") )) {
2412                                 char *attr_fname;
2413                                 attr_fname = ch_strdup( val + STRLENOF(":include:") );
2414                                 si->si_exanlist = file2anlist(
2415                                                                         si->si_exanlist, attr_fname, " ,\t" );
2416                                 if ( si->si_exanlist == NULL ) {
2417                                         ch_free( attr_fname );
2418                                         return -1;
2419                                 }
2420                                 ch_free( attr_fname );
2421                         } else {
2422                                 si->si_exanlist = str2anlist( si->si_exanlist, val, " ,\t" );
2423                                 if ( si->si_exanlist == NULL ) {
2424                                         return -1;
2425                                 }
2426                         }
2427                 } else if ( !strncasecmp( cargv[ i ], TYPESTR "=",
2428                                         STRLENOF( TYPESTR "=" ) ) )
2429                 {
2430                         val = cargv[ i ] + STRLENOF( TYPESTR "=" );
2431                         if ( !strncasecmp( val, "refreshOnly",
2432                                                 STRLENOF("refreshOnly") ))
2433                         {
2434                                 si->si_type = LDAP_SYNC_REFRESH_ONLY;
2435                         } else if ( !strncasecmp( val, "refreshAndPersist",
2436                                                 STRLENOF("refreshAndPersist") ))
2437                         {
2438                                 si->si_type = LDAP_SYNC_REFRESH_AND_PERSIST;
2439                                 si->si_interval = 60;
2440                         } else {
2441                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2442                                         "unknown sync type \"%s\"\n", val);
2443                                 return -1;
2444                         }
2445                 } else if ( !strncasecmp( cargv[ i ], INTERVALSTR "=",
2446                                         STRLENOF( INTERVALSTR "=" ) ) )
2447                 {
2448                         val = cargv[ i ] + STRLENOF( INTERVALSTR "=" );
2449                         if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) {
2450                                 si->si_interval = 0;
2451                         } else {
2452                                 char *hstr;
2453                                 char *mstr;
2454                                 char *dstr;
2455                                 char *sstr;
2456                                 int dd, hh, mm, ss;
2457                                 dstr = val;
2458                                 hstr = strchr( dstr, ':' );
2459                                 if ( hstr == NULL ) {
2460                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2461                                                 "invalid interval \"%s\"\n", val );
2462                                         return -1;
2463                                 }
2464                                 *hstr++ = '\0';
2465                                 mstr = strchr( hstr, ':' );
2466                                 if ( mstr == NULL ) {
2467                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2468                                                 "invalid interval \"%s\"\n", val );
2469                                         return -1;
2470                                 }
2471                                 *mstr++ = '\0';
2472                                 sstr = strchr( mstr, ':' );
2473                                 if ( sstr == NULL ) {
2474                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2475                                                 "invalid interval \"%s\"\n", val );
2476                                         return -1;
2477                                 }
2478                                 *sstr++ = '\0';
2479
2480                                 dd = atoi( dstr );
2481                                 hh = atoi( hstr );
2482                                 mm = atoi( mstr );
2483                                 ss = atoi( sstr );
2484                                 if (( hh > 24 ) || ( hh < 0 ) ||
2485                                         ( mm > 60 ) || ( mm < 0 ) ||
2486                                         ( ss > 60 ) || ( ss < 0 ) || ( dd < 0 )) {
2487                                         fprintf( stderr, "Error: parse_syncrepl_line: "
2488                                                 "invalid interval \"%s\"\n", val );
2489                                         return -1;
2490                                 }
2491                                 si->si_interval = (( dd * 24 + hh ) * 60 + mm ) * 60 + ss;
2492                         }
2493                         if ( si->si_interval < 0 ) {
2494                                 fprintf( stderr, "Error: parse_syncrepl_line: "
2495                                         "invalid interval \"%ld\"\n",
2496                                         (long) si->si_interval);
2497                                 return -1;
2498                         }
2499                 } else if ( !strncasecmp( cargv[ i ], RETRYSTR "=",
2500                                         STRLENOF( RETRYSTR "=" ) ) )
2501                 {
2502                         char **retry_list;
2503                         int j, k, n;
2504
2505                         val = cargv[ i ] + STRLENOF( RETRYSTR "=" );
2506                         retry_list = (char **) ch_calloc( 1, sizeof( char * ));
2507                         retry_list[0] = NULL;
2508
2509                         slap_str2clist( &retry_list, val, " ,\t" );
2510
2511                         for ( k = 0; retry_list && retry_list[k]; k++ ) ;
2512                         n = k / 2;
2513                         if ( k % 2 ) {
2514                                 fprintf( stderr,
2515                                                 "Error: incomplete syncrepl retry list\n" );
2516                                 for ( k = 0; retry_list && retry_list[k]; k++ ) {
2517                                         ch_free( retry_list[k] );
2518                                 }
2519                                 ch_free( retry_list );
2520                                 exit( EXIT_FAILURE );
2521                         }
2522                         si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t ));
2523                         si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int ));
2524                         si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int ));
2525                         for ( j = 0; j < n; j++ ) {
2526                                 si->si_retryinterval[j] = atoi( retry_list[j*2] );
2527                                 if ( *retry_list[j*2+1] == '+' ) {
2528                                         si->si_retrynum_init[j] = -1;
2529                                         si->si_retrynum[j] = -1;
2530                                         j++;
2531                                         break;
2532                                 } else {
2533                                         si->si_retrynum_init[j] = atoi( retry_list[j*2+1] );
2534                                         si->si_retrynum[j] = atoi( retry_list[j*2+1] );
2535                                 }
2536                         }
2537                         si->si_retrynum_init[j] = -2;
2538                         si->si_retrynum[j] = -2;
2539                         si->si_retryinterval[j] = 0;
2540                         
2541                         for ( k = 0; retry_list && retry_list[k]; k++ ) {
2542                                 ch_free( retry_list[k] );
2543                         }
2544                         ch_free( retry_list );
2545                 } else if ( !strncasecmp( cargv[ i ], MANAGEDSAITSTR "=",
2546                                         STRLENOF( MANAGEDSAITSTR "=" ) ) )
2547                 {
2548                         val = cargv[ i ] + STRLENOF( MANAGEDSAITSTR "=" );
2549                         si->si_manageDSAit = atoi( val );
2550                 } else if ( !strncasecmp( cargv[ i ], SLIMITSTR "=",
2551                                         STRLENOF( SLIMITSTR "=") ) )
2552                 {
2553                         val = cargv[ i ] + STRLENOF( SLIMITSTR "=" );
2554                         si->si_slimit = atoi( val );
2555                 } else if ( !strncasecmp( cargv[ i ], TLIMITSTR "=",
2556                                         STRLENOF( TLIMITSTR "=" ) ) )
2557                 {
2558                         val = cargv[ i ] + STRLENOF( TLIMITSTR "=" );
2559                         si->si_tlimit = atoi( val );
2560                 } else if ( bindconf_parse( cargv[i], &si->si_bindconf )) {
2561                         fprintf( stderr, "Error: parse_syncrepl_line: "
2562                                 "unknown keyword \"%s\"\n", cargv[ i ] );
2563                         return -1;
2564                 }
2565         }
2566
2567         if ( gots != GOT_ALL ) {
2568                 fprintf( stderr,
2569                         "Error: Malformed \"syncrepl\" line in slapd config file" );
2570                 return -1;
2571         }
2572
2573         return 0;
2574 }
2575
2576 static int
2577 add_syncrepl(
2578         Backend *be,
2579         char    **cargv,
2580         int     cargc
2581 )
2582 {
2583         syncinfo_t *si;
2584         int     rc = 0;
2585
2586         if ( !( be->be_search && be->be_add && be->be_modify && be->be_delete )) {
2587                 Debug( LDAP_DEBUG_ANY, "database %s does not support operations "
2588                         "required for syncrepl\n", be->be_type, 0, 0 );
2589                 return 1;
2590         }
2591         si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) );
2592
2593         if ( si == NULL ) {
2594                 Debug( LDAP_DEBUG_ANY, "out of memory in add_syncrepl\n", 0, 0, 0 );
2595                 return 1;
2596         }
2597
2598         si->si_bindconf.sb_tls = SB_TLS_OFF;
2599         si->si_bindconf.sb_method = LDAP_AUTH_SIMPLE;
2600         si->si_schemachecking = 0;
2601         ber_str2bv( "(objectclass=*)", STRLENOF("(objectclass=*)"), 1,
2602                 &si->si_filterstr );
2603         si->si_base.bv_val = NULL;
2604         si->si_scope = LDAP_SCOPE_SUBTREE;
2605         si->si_attrsonly = 0;
2606         si->si_anlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ));
2607         si->si_exanlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ));
2608         si->si_attrs = NULL;
2609         si->si_allattrs = 0;
2610         si->si_allopattrs = 0;
2611         si->si_exattrs = NULL;
2612         si->si_type = LDAP_SYNC_REFRESH_ONLY;
2613         si->si_interval = 86400;
2614         si->si_retryinterval = NULL;
2615         si->si_retrynum_init = NULL;
2616         si->si_retrynum = NULL;
2617         si->si_manageDSAit = 0;
2618         si->si_tlimit = 0;
2619         si->si_slimit = 0;
2620
2621         si->si_presentlist = NULL;
2622         LDAP_LIST_INIT( &si->si_nonpresentlist );
2623         ldap_pvt_thread_mutex_init( &si->si_mutex );
2624
2625         rc = parse_syncrepl_line( cargv, cargc, si );
2626
2627         if ( rc == 0 ) {
2628                 si->si_be = be;
2629                 init_syncrepl( si );
2630                 si->si_re = ldap_pvt_runqueue_insert( &slapd_rq, si->si_interval,
2631                         do_syncrepl, si, "do_syncrepl", be->be_suffix[0].bv_val );
2632                 if ( !si->si_re )
2633                         rc = -1;
2634         }
2635         if ( rc < 0 ) {
2636                 Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n", 0, 0, 0 );
2637                 syncinfo_free( si );    
2638                 return 1;
2639         } else {
2640                 Debug( LDAP_DEBUG_CONFIG,
2641                         "Config: ** successfully added syncrepl \"%s\"\n",
2642                         BER_BVISNULL( &si->si_provideruri ) ?
2643                         "(null)" : si->si_provideruri.bv_val, 0, 0 );
2644                 if ( !si->si_schemachecking ) {
2645                         SLAP_DBFLAGS(be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK;
2646                 }
2647                 be->be_syncinfo = si;
2648                 return 0;
2649         }
2650 }
2651
2652 static void
2653 syncrepl_unparse( syncinfo_t *si, struct berval *bv )
2654 {
2655         struct berval bc;
2656         char buf[BUFSIZ*2], *ptr;
2657         int i, len;
2658
2659         bindconf_unparse( &si->si_bindconf, &bc );
2660         ptr = buf;
2661         ptr += sprintf( ptr, IDSTR "=%03d " PROVIDERSTR "=%s",
2662                 si->si_rid, si->si_provideruri.bv_val );
2663         if ( !BER_BVISNULL( &bc )) {
2664                 ptr = lutil_strcopy( ptr, bc.bv_val );
2665                 free( bc.bv_val );
2666         }
2667         if ( !BER_BVISEMPTY( &si->si_filterstr )) {
2668                 ptr = lutil_strcopy( ptr, " " FILTERSTR "=\"" );
2669                 ptr = lutil_strcopy( ptr, si->si_filterstr.bv_val );
2670                 *ptr++ = '"';
2671         }
2672         if ( !BER_BVISNULL( &si->si_base )) {
2673                 ptr = lutil_strcopy( ptr, " " SEARCHBASESTR "=\"" );
2674                 ptr = lutil_strcopy( ptr, si->si_base.bv_val );
2675                 *ptr++ = '"';
2676         }
2677         for (i=0; !BER_BVISNULL(&scopes[i].key);i++) {
2678                 if ( si->si_scope == scopes[i].val ) {
2679                         ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
2680                         ptr = lutil_strcopy( ptr, scopes[i].key.bv_val );
2681                         break;
2682                 }
2683         }
2684         if ( si->si_attrsonly ) {
2685                 ptr = lutil_strcopy( ptr, " " ATTRSONLYSTR "=yes" );
2686         }
2687         if ( si->si_anfile ) {
2688                 ptr = lutil_strcopy( ptr, " " ATTRSSTR "=:include:" );
2689                 ptr = lutil_strcopy( ptr, si->si_anfile );
2690         } else if ( si->si_allattrs || si->si_allopattrs ||
2691                 ( si->si_anlist && !BER_BVISNULL(&si->si_anlist[0].an_name) )) {
2692                 char *old;
2693                 ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" );
2694                 old = ptr;
2695                 ptr = anlist_unparse( si->si_anlist, ptr );
2696                 if ( si->si_allattrs ) {
2697                         if ( old != ptr ) *ptr++ = ',';
2698                         *ptr++ = '*';
2699                 }
2700                 if ( si->si_allopattrs ) {
2701                         if ( old != ptr ) *ptr++ = ',';
2702                         *ptr++ = '+';
2703                 }
2704                 *ptr++ = '"';
2705         }
2706         if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) {
2707                 ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" );
2708                 ptr = anlist_unparse( si->si_exanlist, ptr );
2709         }
2710         ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" );
2711         ptr = lutil_strcopy( ptr, si->si_schemachecking ? "on" : "off" );
2712         
2713         ptr = lutil_strcopy( ptr, " " TYPESTR "=" );
2714         ptr = lutil_strcopy( ptr, si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ?
2715                 "refreshAndPersist" : "refreshOnly" );
2716
2717         if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
2718                 int dd, hh, mm, ss;
2719
2720                 dd = si->si_interval;
2721                 ss = dd % 60;
2722                 dd /= 60;
2723                 mm = dd % 60;
2724                 dd /= 60;
2725                 hh = dd % 24;
2726                 dd /= 24;
2727                 ptr = lutil_strcopy( ptr, " " INTERVALSTR "=" );
2728                 ptr += sprintf( ptr, "%02d:%02d:%02d:%02d", dd, hh, mm, ss );
2729         } else if ( si->si_retryinterval ) {
2730                 int space=0;
2731                 ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" );
2732                 for (i=0; si->si_retryinterval[i]; i++) {
2733                         if ( space ) *ptr++ = ' ';
2734                         space = 1;
2735                         ptr += sprintf( ptr, "%d", si->si_retryinterval[i] );
2736                         if ( si->si_retrynum_init[i] == -1 )
2737                                 *ptr++ = '+';
2738                         else
2739                                 ptr += sprintf( ptr, "%d", si->si_retrynum_init );
2740                 }
2741                 *ptr++ = '"';
2742         }
2743
2744         if ( si->si_slimit ) {
2745                 ptr = lutil_strcopy( ptr, " " SLIMITSTR "=" );
2746                 ptr += sprintf( ptr, "%d", si->si_slimit );
2747         }
2748
2749         if ( si->si_tlimit ) {
2750                 ptr = lutil_strcopy( ptr, " " TLIMITSTR "=" );
2751                 ptr += sprintf( ptr, "%d", si->si_tlimit );
2752         }
2753         bc.bv_len = ptr - buf;
2754         bc.bv_val = buf;
2755         ber_dupbv( bv, &bc );
2756 }
2757
2758 int
2759 syncrepl_config(ConfigArgs *c) {
2760         if (c->op == SLAP_CONFIG_EMIT) {
2761                 if ( c->be->be_syncinfo ) {
2762                         struct berval bv;
2763                         syncrepl_unparse( c->be->be_syncinfo, &bv ); 
2764                         ber_bvarray_add( &c->rvalue_vals, &bv );
2765                         return 0;
2766                 }
2767                 return 1;
2768         } else if ( c->op == LDAP_MOD_DELETE ) {
2769                 struct re_s *re;
2770
2771                 if ( c->be->be_syncinfo ) {
2772                         re = c->be->be_syncinfo->si_re;
2773                         if ( re ) {
2774                                 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ))
2775                                         ldap_pvt_runqueue_stoptask( &slapd_rq, re );
2776                                 ldap_pvt_runqueue_remove( &slapd_rq, re );
2777                         }
2778                         syncinfo_free( c->be->be_syncinfo );
2779                         c->be->be_syncinfo = NULL;
2780                 }
2781                 SLAP_DBFLAGS(c->be) &= ~(SLAP_DBFLAG_SHADOW|SLAP_DBFLAG_SYNC_SHADOW);
2782                 return 0;
2783         }
2784         if(SLAP_SHADOW(c->be)) {
2785                 Debug(LDAP_DEBUG_ANY, "%s: "
2786                         "syncrepl: database already shadowed.\n",
2787                         c->log, 0, 0);
2788                 return(1);
2789         } else if(add_syncrepl(c->be, c->argv, c->argc)) {
2790                 return(1);
2791         }
2792         SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SYNC_SHADOW);
2793         return(0);
2794 }