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