]> git.sur5r.net Git - openldap/blob - servers/slapd/syncrepl.c
7346da5cd342ae03970dab9bc21b121d9b664fb3
[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-2004 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 "ldap_pvt.h"
27 #include "lutil.h"
28 #include "slap.h"
29 #include "lutil_ldap.h"
30
31 #include "ldap_rq.h"
32
33 #define SYNCREPL_STR    "syncreplxxx"
34 #define CN_STR  "cn="
35
36 static const struct berval slap_syncrepl_bvc = BER_BVC(SYNCREPL_STR);
37 static const struct berval slap_syncrepl_cn_bvc = BER_BVC(CN_STR SYNCREPL_STR);
38
39 static int syncuuid_cmp( const void *, const void * );
40 static void avl_ber_bvfree( void * );
41 static void syncrepl_del_nonpresent( Operation *, syncinfo_t * );
42
43 /* callback functions */
44 static int dn_callback( struct slap_op *, struct slap_rep * );
45 static int nonpresent_callback( struct slap_op *, struct slap_rep * );
46 static int null_callback( struct slap_op *, struct slap_rep * );
47
48 static AttributeDescription *sync_descs[4];
49
50 struct runqueue_s syncrepl_rq;
51
52 void
53 init_syncrepl(syncinfo_t *si)
54 {
55         int i, j, k, l, n;
56         char **attrs, **exattrs;
57         ObjectClass *oc;
58
59         if ( !sync_descs[0] ) {
60                 sync_descs[0] = slap_schema.si_ad_objectClass;
61                 sync_descs[1] = slap_schema.si_ad_structuralObjectClass;
62                 sync_descs[2] = slap_schema.si_ad_entryCSN;
63                 sync_descs[3] = NULL;
64         }
65
66         if ( si->si_allattrs && si->si_allopattrs )
67                 attrs = NULL;
68         else
69                 attrs = anlist2attrs( si->si_anlist );
70
71         if ( attrs ) {
72
73                 if ( si->si_allattrs ) {
74                         i = 0;
75                         while ( attrs[i] ) {
76                                 if ( !is_at_operational( at_find( attrs[i] ))) {
77                                         for ( j = i; attrs[j] != NULL; j++ ) {
78                                                 if ( j == i )
79                                                         ch_free( attrs[i] );
80                                                 attrs[j] = attrs[j+1];
81                                         }
82                                 } else {
83                                         i++;
84                                 }
85                         }
86                         attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ));
87                         attrs[i] = ch_strdup("*");
88                         attrs[i + 1] = NULL;
89                 } else if ( si->si_allopattrs ) {
90                         i = 0;
91                         while ( attrs[i] ) {
92                                 if ( is_at_operational( at_find( attrs[i] ))) {
93                                         for ( j = i; attrs[j] != NULL; j++ ) {
94                                                 if ( j == i )
95                                                         ch_free( attrs[i] );
96                                                 attrs[j] = attrs[j+1];
97                                         }
98                                 } else {
99                                         i++;
100                                 }
101                         }
102                         attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ));
103                         attrs[i] = ch_strdup("+");
104                         attrs[i + 1] = NULL;
105                 }
106
107                 if ( !si->si_allopattrs ) {
108                         for ( i = 0; sync_descs[i] != NULL; i++ ) {
109                                 j = 0;
110                                 while ( attrs[j] ) {
111                                         if ( !strcmp( attrs[j], sync_descs[i]->ad_cname.bv_val )) {
112                                                 for ( k = j; attrs[k] != NULL; k++ ) {
113                                                         if ( k == j )
114                                                                 ch_free( attrs[k] );
115                                                         attrs[k] = attrs[k+1];
116                                                 }
117                                         } else {
118                                                 j++;
119                                         }
120                                 }
121
122                         }
123                         for ( n = 0; attrs[ n ] != NULL; n++ ) /* empty */;
124                         attrs = ( char ** ) ch_realloc( attrs, (n + 4)*sizeof( char * ));
125                         if ( attrs == NULL ) {
126                                 Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
127                         }
128         
129                         /* Add Attributes */
130                         for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
131                                 attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
132                                 attrs[ n ] = NULL;
133                         }
134                 }
135
136         } else {
137                 attrs = ( char ** ) ch_realloc( attrs, 3 * sizeof( char * ));
138                 if ( attrs == NULL ) {
139                         Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
140                 }
141                 attrs[0] = ch_strdup( "*" );
142                 attrs[1] = ch_strdup( "+" );
143                 attrs[2] = NULL;
144         }
145         
146         si->si_attrs = attrs;
147
148         exattrs = anlist2attrs( si->si_exanlist );
149
150
151         if ( exattrs ) {
152
153                 for ( n = 0; exattrs[n] != NULL; n++ ) ;
154
155                 for ( i = 0; sync_descs[i] != NULL; i++ ) {
156                         j = 0;
157                         while ( exattrs[j] != NULL ) {
158                                 if ( !strcmp( exattrs[j], sync_descs[i]->ad_cname.bv_val )) {
159                                         for ( k = j; exattrs[k] != NULL; k++ ) {
160                                                 if ( k == j )
161                                                         ch_free( exattrs[k] );
162                                                 exattrs[k] = exattrs[k+1];
163                                         }
164                                 } else {
165                                         j++;
166                                 }
167                         }
168                 }
169
170                 for ( i = 0; exattrs[i] != NULL; i++ ) {
171                         for ( j = 0; si->si_anlist[j].an_name.bv_val; j++ ) {
172                                 if ( oc = si->si_anlist[j].an_oc ) {
173                                         k = 0;
174                                         while ( oc->soc_required[k] ) {
175                                                 if ( !strcmp( exattrs[i],
176                                                          oc->soc_required[k]->sat_cname.bv_val )) {
177                                                         for ( l = i; exattrs[l]; l++ ) {
178                                                                 if ( l == i )
179                                                                         ch_free( exattrs[i] );
180                                                                 exattrs[l] = exattrs[l+1];
181                                                         }
182                                                 } else {
183                                                         k++;
184                                                 }
185                                         }
186                                 }
187                         }
188                 }
189
190                 for ( i = 0; exattrs[i] != NULL; i++ ) ;
191
192                 if ( i != n )
193                         exattrs = (char **) ch_realloc( exattrs, (i + 1)*sizeof(char *));
194         }
195
196         si->si_exattrs = exattrs;       
197 }
198
199 static int
200 ldap_sync_search(
201         syncinfo_t *si,
202         void *ctx )
203 {
204         BerElementBuffer berbuf;
205         BerElement *ber = (BerElement *)&berbuf;
206         LDAPControl c[2], *ctrls[3];
207         struct timeval timeout;
208         ber_int_t       msgid;
209         int rc;
210
211         /* setup LDAP SYNC control */
212         ber_init2( ber, NULL, LBER_USE_DER );
213         ber_set_option( ber, LBER_OPT_BER_MEMCTX, &ctx );
214
215         if ( si->si_syncCookie.octet_str &&
216                 si->si_syncCookie.octet_str[0].bv_val )
217         {
218                 ber_printf( ber, "{eO}",
219                         abs(si->si_type),
220                         &si->si_syncCookie.octet_str[0] );
221         } else {
222                 ber_printf( ber, "{e}",
223                         abs(si->si_type) );
224         }
225
226         if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 )) == LBER_ERROR ) {
227                 ber_free_buf( ber );
228                 return rc;
229         }
230
231         c[0].ldctl_oid = LDAP_CONTROL_SYNC;
232         c[0].ldctl_iscritical = si->si_type < 0;
233         ctrls[0] = &c[0];
234
235         if ( si->si_authzId ) {
236                 c[1].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
237                 ber_str2bv( si->si_authzId, 0, 0, &c[1].ldctl_value );
238                 c[1].ldctl_iscritical = 1;
239                 ctrls[1] = &c[1];
240                 ctrls[2] = NULL;
241         } else {
242                 ctrls[1] = NULL;
243         }
244
245         timeout.tv_sec = si->si_tlimit;
246         timeout.tv_usec = 0;
247
248         rc = ldap_search_ext( si->si_ld, si->si_base.bv_val, si->si_scope,
249                 si->si_filterstr.bv_val, si->si_attrs, si->si_attrsonly,
250                 ctrls, NULL, si->si_tlimit > 0 ? &timeout : NULL,
251                 si->si_slimit, &msgid );
252         ber_free_buf( ber );
253         return rc;
254 }
255
256 static int
257 do_syncrep1(
258         Operation *op,
259         syncinfo_t *si )
260 {
261         int     rc;
262         int cmdline_cookie_found = 0;
263
264         char syncrepl_cbuf[sizeof(CN_STR SYNCREPL_STR)];
265         struct berval syncrepl_cn_bv;
266         struct sync_cookie      *sc = NULL;
267         struct sync_cookie      syncCookie = { NULL, -1, NULL };
268         struct berval   *psub;
269 #ifdef HAVE_TLS
270         void    *ssl;
271 #endif
272
273         psub = &si->si_be->be_nsuffix[0];
274
275         /* Init connection to master */
276         rc = ldap_initialize( &si->si_ld, si->si_provideruri );
277         if ( rc != LDAP_SUCCESS ) {
278                 Debug( LDAP_DEBUG_ANY,
279                         "do_syncrep1: ldap_initialize failed (%s)\n",
280                         si->si_provideruri, 0, 0 );
281                 return rc;
282         }
283
284         op->o_protocol = LDAP_VERSION3;
285         ldap_set_option( si->si_ld, LDAP_OPT_PROTOCOL_VERSION, &op->o_protocol );
286
287         /* Bind to master */
288
289         if ( si->si_tls ) {
290                 rc = ldap_start_tls_s( si->si_ld, NULL, NULL );
291                 if( rc != LDAP_SUCCESS ) {
292                         Debug( LDAP_DEBUG_ANY,
293                                 "%s: ldap_start_tls failed (%d)\n",
294                                 si->si_tls == SYNCINFO_TLS_CRITICAL ? "Error" : "Warning",
295                                 rc, 0 );
296                         if( si->si_tls == SYNCINFO_TLS_CRITICAL ) goto done;
297                 }
298         }
299
300         if ( si->si_bindmethod == LDAP_AUTH_SASL ) {
301 #ifdef HAVE_CYRUS_SASL
302                 void *defaults;
303
304                 if ( si->si_secprops != NULL ) {
305                         rc = ldap_set_option( si->si_ld,
306                                 LDAP_OPT_X_SASL_SECPROPS, si->si_secprops);
307
308                         if( rc != LDAP_OPT_SUCCESS ) {
309                                 Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
310                                         "(%s,SECPROPS,\"%s\") failed!\n",
311                                         si->si_provideruri, si->si_secprops, 0 );
312                                 goto done;
313                         }
314                 }
315
316                 defaults = lutil_sasl_defaults( si->si_ld, si->si_saslmech,
317                         si->si_realm, si->si_authcId, si->si_passwd, si->si_authzId );
318
319                 rc = ldap_sasl_interactive_bind_s( si->si_ld,
320                                 si->si_binddn,
321                                 si->si_saslmech,
322                                 NULL, NULL,
323                                 LDAP_SASL_QUIET,
324                                 lutil_sasl_interact,
325                                 defaults );
326
327                 lutil_sasl_freedefs( defaults );
328
329                 /* FIXME: different error behaviors according to
330                  *      1) return code
331                  *      2) on err policy : exit, retry, backoff ...
332                  */
333                 if ( rc != LDAP_SUCCESS ) {
334                         Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
335                                 "ldap_sasl_interactive_bind_s failed (%d)\n",
336                                 rc, 0, 0 );
337
338                         /* FIXME (see above comment) */
339                         /* if Kerberos credentials cache is not active, retry */
340                         if ( strcmp( si->si_saslmech, "GSSAPI" ) == 0 &&
341                                 rc == LDAP_LOCAL_ERROR )
342                         {
343                                 rc = LDAP_SERVER_DOWN;
344                         }
345
346                         goto done;
347                 }
348 #else /* HAVE_CYRUS_SASL */
349                 /* Should never get here, we trapped this at config time */
350                 assert(0);
351                 fprintf( stderr, "not compiled with SASL support\n" );
352                 rc = LDAP_OTHER;
353                 goto done;
354 #endif
355
356         } else {
357                 rc = ldap_bind_s( si->si_ld,
358                         si->si_binddn, si->si_passwd, si->si_bindmethod );
359                 if ( rc != LDAP_SUCCESS ) {
360                         Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
361                                 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
362                         goto done;
363                 }
364         }
365
366         /* Set SSF to strongest of TLS, SASL SSFs */
367         op->o_sasl_ssf = 0;
368         op->o_tls_ssf = 0;
369         op->o_transport_ssf = 0;
370 #ifdef HAVE_TLS
371         if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl )
372                 == LDAP_SUCCESS && ssl != NULL )
373         {
374                 op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
375         }
376 #endif /* HAVE_TLS */
377         ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &op->o_sasl_ssf );
378         op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
379                 ?  op->o_sasl_ssf : op->o_tls_ssf;
380
381         /* get syncrepl cookie of shadow replica from subentry */
382         assert( si->si_rid < 1000 );
383         syncrepl_cn_bv.bv_val = syncrepl_cbuf;
384         syncrepl_cn_bv.bv_len = snprintf(syncrepl_cbuf, sizeof(syncrepl_cbuf),
385                 CN_STR "syncrepl%ld", si->si_rid );
386         build_new_dn( &op->o_req_ndn, psub, &syncrepl_cn_bv, op->o_tmpmemctx );
387         op->o_req_dn = op->o_req_ndn;
388
389         LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) {
390                 if ( si->si_rid == sc->rid ) {
391                         cmdline_cookie_found = 1;
392                         break;
393                 }
394         }
395
396         if ( cmdline_cookie_found ) {
397                 /* cookie is supplied in the command line */
398                 BerVarray cookie = NULL;
399                 struct berval cookie_bv;
400
401                 LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next );
402                 slap_sync_cookie_free( &si->si_syncCookie, 0 );
403
404                 /* read stored cookie if it exists */
405                 backend_attribute( op, NULL, &op->o_req_ndn,
406                         slap_schema.si_ad_syncreplCookie, &cookie, ACL_READ );
407
408                 if ( !cookie ) {
409                         /* no stored cookie */
410                         if ( sc->ctxcsn == NULL ||
411                                  sc->ctxcsn->bv_val == NULL ) {
412                                 /* if cmdline cookie does not have ctxcsn */
413                                 /* component, set it to an initial value */
414                                 slap_init_sync_cookie_ctxcsn( sc );
415                         }
416                         slap_dup_sync_cookie( &si->si_syncCookie, sc );
417                         slap_sync_cookie_free( sc, 1 );
418                         sc = NULL;
419
420                 } else {
421                         /* stored cookie */
422                         struct berval newcookie = BER_BVNULL;
423                         ber_dupbv( &cookie_bv, &cookie[0] );
424                         ber_bvarray_add( &si->si_syncCookie.octet_str, &cookie_bv );
425                         slap_parse_sync_cookie( &si->si_syncCookie );
426                         ber_bvarray_free( si->si_syncCookie.octet_str );
427                         si->si_syncCookie.octet_str = NULL;
428                         ber_bvarray_free_x( cookie, op->o_tmpmemctx );
429                         if ( sc->sid != -1 ) {
430                                 /* command line cookie wins */
431                                 si->si_syncCookie.sid = sc->sid;
432                         }
433                         if ( sc->ctxcsn != NULL ) {
434                                 /* command line cookie wins */
435                                 if ( si->si_syncCookie.ctxcsn ) {
436                                         ber_bvarray_free( si->si_syncCookie.ctxcsn );
437                                         si->si_syncCookie.ctxcsn = NULL;
438                                 }
439                                 ber_dupbv( &cookie_bv, &sc->ctxcsn[0] );
440                                 ber_bvarray_add( &si->si_syncCookie.ctxcsn, &cookie_bv );
441                         }
442                         if ( sc->rid != -1 ) {
443                                 /* command line cookie wins */
444                                 si->si_syncCookie.rid = sc->rid;
445                         }
446                         slap_sync_cookie_free( sc, 1 );
447                         sc = NULL;
448                         slap_compose_sync_cookie( NULL, &newcookie,
449                                         &si->si_syncCookie.ctxcsn[0],
450                                         si->si_syncCookie.sid, si->si_syncCookie.rid );
451                         ber_bvarray_add( &si->si_syncCookie.octet_str, &newcookie );
452                 }
453
454         } else {
455                 /* no command line cookie is specified */
456                 if ( si->si_syncCookie.octet_str == NULL ) {
457                         BerVarray cookie = NULL;
458                         struct berval cookie_bv;
459                         /* try to read stored cookie */
460                         backend_attribute( op, NULL, &op->o_req_ndn,
461                                 slap_schema.si_ad_syncreplCookie, &cookie, ACL_READ );
462                         if ( cookie ) {
463                                 ber_dupbv( &cookie_bv, &cookie[0] );
464                                 ber_bvarray_add( &si->si_syncCookie.octet_str, &cookie_bv );
465                                 slap_parse_sync_cookie( &si->si_syncCookie );
466                                 ber_bvarray_free_x( cookie, op->o_tmpmemctx );
467                         }
468                 }
469         }
470
471         rc = ldap_sync_search( si, op->o_tmpmemctx );
472
473         if( rc != LDAP_SUCCESS ) {
474                 Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
475                         "ldap_search_ext: %s (%d)\n", ldap_err2string( rc ), rc, 0 );
476         }
477
478 done:
479         if ( rc ) {
480                 if ( si->si_ld ) {
481                         ldap_unbind( si->si_ld );
482                         si->si_ld = NULL;
483                 }
484         }
485
486         slap_sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx );
487
488         return rc;
489 }
490
491 static int
492 do_syncrep2(
493         Operation *op,
494         syncinfo_t *si )
495 {
496         LDAPControl     **rctrls = NULL;
497         LDAPControl     *rctrlp;
498
499         BerElementBuffer berbuf;
500         BerElement      *ber = (BerElement *)&berbuf;
501
502         LDAPMessage     *res = NULL;
503         LDAPMessage     *msg = NULL;
504
505         char            *retoid = NULL;
506         struct berval   *retdata = NULL;
507
508         Entry           *entry = NULL;
509
510         int             syncstate;
511         struct berval   syncUUID = BER_BVNULL;
512         struct sync_cookie      syncCookie = { NULL, -1, NULL };
513         struct sync_cookie      syncCookie_req = { NULL, -1, NULL };
514         struct berval           cookie = BER_BVNULL;
515
516         int     rc, err, i;
517         ber_len_t       len;
518
519         int rc_efree = 1;
520
521         struct berval   *psub;
522         Modifications   *modlist = NULL;
523
524         const char              *text;
525         int                             match;
526
527         struct timeval *tout_p = NULL;
528         struct timeval tout = { 0, 0 };
529
530         int             refreshDeletes = 0;
531         int             refreshDone = 1;
532         BerVarray syncUUIDs = NULL;
533         ber_tag_t si_tag;
534
535         if ( slapd_shutdown ) {
536                 rc = -2;
537                 goto done;
538         }
539
540         ber_init2( ber, NULL, LBER_USE_DER );
541         ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
542
543         Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2\n", 0, 0, 0 );
544
545         psub = &si->si_be->be_nsuffix[0];
546
547         slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
548
549         if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
550                 tout_p = &tout;
551         } else {
552                 tout_p = NULL;
553         }
554
555         while (( rc = ldap_result( si->si_ld, LDAP_RES_ANY, LDAP_MSG_ONE,
556                 tout_p, &res )) > 0 )
557         {
558                 if ( slapd_shutdown ) {
559                         rc = -2;
560                         goto done;
561                 }
562                 for( msg = ldap_first_message( si->si_ld, res );
563                         msg != NULL;
564                         msg = ldap_next_message( si->si_ld, msg ) )
565                 {
566                         switch( ldap_msgtype( msg ) ) {
567                         case LDAP_RES_SEARCH_ENTRY:
568                                 ldap_get_entry_controls( si->si_ld, msg, &rctrls );
569                                 /* we can't work without the control */
570                                 if ( !rctrls ) {
571                                         rc = -1;
572                                         goto done;
573                                 }
574                                 rctrlp = *rctrls;
575                                 ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
576                                 ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID );
577                                 if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
578                                         ber_scanf( ber, /*"{"*/ "m}", &cookie );
579                                         if ( cookie.bv_val ) {
580                                                 struct berval tmp_bv;
581                                                 ber_dupbv( &tmp_bv, &cookie );
582                                                 ber_bvarray_add( &syncCookie.octet_str, &tmp_bv );
583                                         }
584                                         if ( syncCookie.octet_str &&
585                                                         syncCookie.octet_str[0].bv_val )
586                                                 slap_parse_sync_cookie( &syncCookie );
587                                 }
588                                 if ( syncrepl_message_to_entry( si, op, msg,
589                                         &modlist, &entry, syncstate ) == LDAP_SUCCESS ) {
590                                         rc_efree = syncrepl_entry( si, op, entry, modlist,
591                                                 syncstate, &syncUUID, &syncCookie_req );
592                                         if ( syncCookie.octet_str &&
593                                                 syncCookie.octet_str[0].bv_val )
594                                         {
595                                                 syncrepl_updateCookie( si, op, psub, &syncCookie );
596                                         }
597                                 }
598                                 ldap_controls_free( rctrls );
599                                 if ( modlist ) {
600                                         slap_mods_free( modlist );
601                                 }
602                                 if ( rc_efree && entry ) {
603                                         entry_free( entry );
604                                 }
605                                 entry = NULL;
606                                 break;
607
608                         case LDAP_RES_SEARCH_REFERENCE:
609                                 Debug( LDAP_DEBUG_ANY,
610                                         "do_syncrep2 : reference received\n", 0, 0, 0 );
611                                 break;
612
613                         case LDAP_RES_SEARCH_RESULT:
614                                 ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
615                                         &rctrls, 0 );
616                                 if ( rctrls ) {
617                                         rctrlp = *rctrls;
618                                         ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
619
620                                         ber_scanf( ber, "{" /*"}"*/);
621                                         if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
622                                                 ber_scanf( ber, "m", &cookie );
623                                                 if ( cookie.bv_val ) {
624                                                         struct berval tmp_bv;
625                                                         ber_dupbv( &tmp_bv, &cookie );
626                                                         ber_bvarray_add( &syncCookie.octet_str, &tmp_bv);
627                                                 }
628                                                 if ( syncCookie.octet_str &&
629                                                         syncCookie.octet_str[0].bv_val )
630                                                 {
631                                                         slap_parse_sync_cookie( &syncCookie );
632                                                 }
633                                         }
634                                         if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
635                                         {
636                                                 ber_scanf( ber, "b", &refreshDeletes );
637                                         }
638                                         ber_scanf( ber, /*"{"*/ "}" );
639                                 }
640                                 if ( syncCookie_req.ctxcsn == NULL ) {
641                                         match = -1;
642                                 } else if ( syncCookie.ctxcsn == NULL ) {
643                                         match = 1;
644                                 } else {
645                                         value_match( &match, slap_schema.si_ad_entryCSN,
646                                                 slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
647                                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
648                                                 &syncCookie_req.ctxcsn[0], &syncCookie.ctxcsn[0],
649                                                 &text );
650                                 }
651                                 if ( syncCookie.octet_str && syncCookie.octet_str->bv_val &&
652                                         match < 0 && err == LDAP_SUCCESS )
653                                 {
654                                         syncrepl_updateCookie( si, op, psub, &syncCookie );
655                                 }
656                                 if ( rctrls ) {
657                                         ldap_controls_free( rctrls );
658                                 }
659                                 if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
660                                         /* FIXME : different error behaviors according to
661                                          *      1) err code : LDAP_BUSY ...
662                                          *      2) on err policy : stop service, stop sync, retry
663                                          */
664                                         if ( refreshDeletes == 0 && match < 0 &&
665                                                 err == LDAP_SUCCESS )
666                                         {
667                                                 syncrepl_del_nonpresent( op, si );
668                                         } else {
669                                                 avl_free( si->si_presentlist, avl_ber_bvfree );
670                                                 si->si_presentlist = NULL;
671                                         }
672                                 }
673                                 rc = -2;
674                                 goto done;
675                                 break;
676
677                         case LDAP_RES_INTERMEDIATE:
678                                 rc = ldap_parse_intermediate( si->si_ld, msg,
679                                         &retoid, &retdata, NULL, 0 );
680                                 if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
681                                         int             si_refreshDelete = 0;
682                                         int             si_refreshPresent = 0;
683                                         ber_init2( ber, retdata, LBER_USE_DER );
684
685                                         switch ( si_tag = ber_peek_tag( ber, &len )) {
686                                         ber_tag_t tag;
687                                         case LDAP_TAG_SYNC_NEW_COOKIE:
688                                                 ber_scanf( ber, "tm", &tag, &cookie );
689                                                 break;
690                                         case LDAP_TAG_SYNC_REFRESH_DELETE:
691                                                 si_refreshDelete = 1;
692                                         case LDAP_TAG_SYNC_REFRESH_PRESENT:
693                                                 si_refreshPresent = 1;
694                                                 ber_scanf( ber, "t{" /*"}"*/, &tag );
695                                                 if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE )
696                                                 {
697                                                         ber_scanf( ber, "m", &cookie );
698                                                         if ( cookie.bv_val ) {
699                                                                 struct berval tmp_bv;
700                                                                 ber_dupbv( &tmp_bv, &cookie );
701                                                                 ber_bvarray_add( &syncCookie.octet_str,
702                                                                         &tmp_bv);
703                                                         }
704                                                         if ( syncCookie.octet_str &&
705                                                                 syncCookie.octet_str[0].bv_val )
706                                                         {
707                                                                 slap_parse_sync_cookie( &syncCookie );
708                                                         }
709                                                 }
710                                                 if ( ber_peek_tag( ber, &len ) ==
711                                                         LDAP_TAG_REFRESHDONE )
712                                                 {
713                                                         ber_scanf( ber, "b", &refreshDone );
714                                                 }
715                                                 ber_scanf( ber, /*"{"*/ "}" );
716                                                 break;
717                                         case LDAP_TAG_SYNC_ID_SET:
718                                                 ber_scanf( ber, "t{" /*"}"*/, &tag );
719                                                 if ( ber_peek_tag( ber, &len ) ==
720                                                         LDAP_TAG_SYNC_COOKIE )
721                                                 {
722                                                         ber_scanf( ber, "m", &cookie );
723                                                         if ( cookie.bv_val ) {
724                                                                 struct berval tmp_bv;
725                                                                 ber_dupbv( &tmp_bv, &cookie );
726                                                                 ber_bvarray_add( &syncCookie.octet_str,
727                                                                         &tmp_bv );
728                                                         }
729                                                         if ( syncCookie.octet_str &&
730                                                                 syncCookie.octet_str[0].bv_val )
731                                                         {
732                                                                 slap_parse_sync_cookie( &syncCookie );
733                                                         }
734                                                 }
735                                                 if ( ber_peek_tag( ber, &len ) ==
736                                                         LDAP_TAG_REFRESHDELETES )
737                                                 {
738                                                         ber_scanf( ber, "b", &refreshDeletes );
739                                                 }
740                                                 ber_scanf( ber, "[W]", &syncUUIDs );
741                                                 ber_scanf( ber, /*"{"*/ "}" );
742                                                 for ( i = 0; syncUUIDs[i].bv_val; i++ ) {
743                                                         struct berval *syncuuid_bv;
744                                                         syncuuid_bv = ber_dupbv( NULL, &syncUUIDs[i] );
745                                                         slap_sl_free( syncUUIDs[i].bv_val,op->o_tmpmemctx );
746                                                         avl_insert( &si->si_presentlist,
747                                                                 (caddr_t) syncuuid_bv,
748                                                                 syncuuid_cmp, avl_dup_error );
749                                                 }
750                                                 slap_sl_free( syncUUIDs, op->o_tmpmemctx );
751                                                 break;
752                                         default:
753                                         Debug( LDAP_DEBUG_ANY,
754                                                 "do_syncrep2 : unknown syncinfo tag (%ld)\n",
755                                                 (long) si_tag, 0, 0 );
756                                                 ldap_memfree( retoid );
757                                                 ber_bvfree( retdata );
758                                                 continue;
759                                         }
760
761                                         if ( syncCookie_req.ctxcsn == NULL ) {
762                                                 match = -1;
763                                         } else if ( syncCookie.ctxcsn == NULL ) {
764                                                 match = 1;
765                                         } else {
766                                                 value_match( &match, slap_schema.si_ad_entryCSN,
767                                                         slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
768                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
769                                                         &syncCookie_req.ctxcsn[0],
770                                                         &syncCookie.ctxcsn[0], &text );
771                                         }
772
773                                         if ( syncCookie.ctxcsn && syncCookie.ctxcsn[0].bv_val &&
774                                                 match < 0 )
775                                         {
776                                                 syncrepl_updateCookie( si, op, psub, &syncCookie);
777                                         }
778
779                                         if ( si_refreshPresent == 1 ) {
780                                                 if ( match < 0 ) {
781                                                         syncrepl_del_nonpresent( op, si );
782                                                 }
783                                         } 
784
785                                         ldap_memfree( retoid );
786                                         ber_bvfree( retdata );
787                                         break;
788
789                                 } else {
790                                         Debug( LDAP_DEBUG_ANY, "do_syncrep2 : "
791                                                 "unknown intermediate response (%d)\n",
792                                                 rc, 0, 0 );
793                                         ldap_memfree( retoid );
794                                         ber_bvfree( retdata );
795                                         break;
796                                 }
797                                 break;
798
799                         default:
800                                 Debug( LDAP_DEBUG_ANY, "do_syncrep2 : "
801                                         "unknown message\n", 0, 0, 0 );
802                                 break;
803
804                         }
805                         if ( syncCookie.octet_str ) {
806                                 slap_sync_cookie_free( &syncCookie_req, 0 );
807                                 slap_dup_sync_cookie( &syncCookie_req, &syncCookie );
808                                 slap_sync_cookie_free( &syncCookie, 0 );
809                         }
810                 }
811                 ldap_msgfree( res );
812                 res = NULL;
813         }
814
815         if ( rc == -1 ) {
816                 const char *errstr;
817
818                 ldap_get_option( si->si_ld, LDAP_OPT_ERROR_NUMBER, &rc );
819                 errstr = ldap_err2string( rc );
820                 
821                 Debug( LDAP_DEBUG_ANY,
822                         "do_syncrep2 : %s\n", errstr, 0, 0 );
823         }
824
825 done:
826         slap_sync_cookie_free( &syncCookie, 0 );
827         slap_sync_cookie_free( &syncCookie_req, 0 );
828
829         if ( res ) ldap_msgfree( res );
830
831         if ( rc && si->si_ld ) {
832                 ldap_unbind( si->si_ld );
833                 si->si_ld = NULL;
834         }
835
836         return rc;
837 }
838
839 void *
840 do_syncrepl(
841         void    *ctx,
842         void    *arg )
843 {
844         struct re_s* rtask = arg;
845         syncinfo_t *si = ( syncinfo_t * ) rtask->arg;
846         Connection conn = {0};
847         Operation op = {0};
848         int rc = LDAP_SUCCESS;
849         int first = 0;
850         int dostop = 0;
851         ber_socket_t s;
852         int i, defer = 1;
853         Backend *be;
854
855         Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl\n", 0, 0, 0 );
856
857         if ( si == NULL )
858                 return NULL;
859
860         switch( abs( si->si_type )) {
861         case LDAP_SYNC_REFRESH_ONLY:
862         case LDAP_SYNC_REFRESH_AND_PERSIST:
863                 break;
864         default:
865                 return NULL;
866         }
867
868         if ( slapd_shutdown && si->si_ld ) {
869                 ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
870                 connection_client_stop( s );
871                 ldap_unbind( si->si_ld );
872                 si->si_ld = NULL;
873                 return NULL;
874         }
875
876         connection_fake_init( &conn, &op, ctx );
877
878         /* use global malloc for now */
879         op.o_tmpmemctx = NULL;
880         op.o_tmpmfuncs = &ch_mfuncs;
881
882         op.o_dn = si->si_updatedn;
883         op.o_ndn = si->si_updatedn;
884         op.o_managedsait = 1;
885         op.o_bd = be = si->si_be;
886
887         op.o_sync_state.ctxcsn = NULL;
888         op.o_sync_state.sid = -1;
889         op.o_sync_state.octet_str = NULL;
890         op.o_sync_slog_size = -1;
891         LDAP_STAILQ_FIRST( &op.o_sync_slog_list ) = NULL;
892         op.o_sync_slog_list.stqh_last = &LDAP_STAILQ_FIRST(&op.o_sync_slog_list);
893
894         /* Establish session, do search */
895         if ( !si->si_ld ) {
896                 first = 1;
897                 rc = do_syncrep1( &op, si );
898         }
899
900         /* Process results */
901         if ( rc == LDAP_SUCCESS ) {
902                 ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
903
904                 rc = do_syncrep2( &op, si );
905
906                 if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
907                         /* If we succeeded, enable the connection for further listening.
908                          * If we failed, tear down the connection and reschedule.
909                          */
910                         if ( rc == LDAP_SUCCESS ) {
911                                 if ( first ) {
912                                         rc = connection_client_setup( s, do_syncrepl, arg );
913                                 } else {
914                                         connection_client_enable( s );
915                                 } 
916                         } else if ( !first ) {
917                                 dostop = 1;
918                         }
919                 } else {
920                         if ( rc == -2 ) rc = 0;
921                 }
922         }
923
924         /* At this point, we have 4 cases:
925          * 1) for any hard failure, give up and remove this task
926          * 2) for ServerDown, reschedule this task to run
927          * 3) for Refresh and Success, reschedule to run
928          * 4) for Persist and Success, reschedule to defer
929          */
930         ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
931
932         if ( ldap_pvt_runqueue_isrunning( &syncrepl_rq, rtask )) {
933                 ldap_pvt_runqueue_stoptask( &syncrepl_rq, rtask );
934         }
935
936         if ( dostop ) {
937                 connection_client_stop( s );
938         }
939
940         if ( rc == LDAP_SUCCESS ) {
941                 if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
942                         defer = 0;
943                 }
944                 rtask->interval.tv_sec = si->si_interval;
945                 ldap_pvt_runqueue_resched( &syncrepl_rq, rtask, defer );
946                 if ( si->si_retrynum ) {
947                         for ( i = 0; si->si_retrynum_init[i] != -2; i++ ) {
948                                 si->si_retrynum[i] = si->si_retrynum_init[i];
949                         }
950                         si->si_retrynum[i] = -2;
951                 }
952         } else {
953                 for ( i = 0; si->si_retrynum && si->si_retrynum[i] <= 0; i++ ) {
954                         if ( si->si_retrynum[i] == -1  || si->si_retrynum[i] == -2 )
955                                 break;
956                 }
957
958                 if ( !si->si_retrynum || si->si_retrynum[i] == -2 ) {
959                         ldap_pvt_runqueue_remove( &syncrepl_rq, rtask );
960                         LDAP_STAILQ_REMOVE( &be->be_syncinfo, si, syncinfo_s, si_next );
961                         syncinfo_free( si );
962                 } else if ( si->si_retrynum[i] >= -1 ) {
963                         if ( si->si_retrynum[i] > 0 )
964                                 si->si_retrynum[i]--;
965                         rtask->interval.tv_sec = si->si_retryinterval[i];
966                         ldap_pvt_runqueue_resched( &syncrepl_rq, rtask, 0 );
967                         slap_wake_listener();
968                 }
969         }
970         
971         ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
972
973         return NULL;
974 }
975
976 int
977 syncrepl_message_to_entry(
978         syncinfo_t      *si,
979         Operation       *op,
980         LDAPMessage     *msg,
981         Modifications   **modlist,
982         Entry                   **entry,
983         int             syncstate
984 )
985 {
986         Entry           *e = NULL;
987         BerElement      *ber = NULL;
988         Modifications   tmp;
989         Modifications   *mod;
990         Modifications   **modtail = modlist;
991
992         const char      *text;
993         char txtbuf[SLAP_TEXT_BUFLEN];
994         size_t textlen = sizeof txtbuf;
995
996         struct berval   bdn = {0, NULL}, dn, ndn;
997         int             rc;
998
999         *modlist = NULL;
1000
1001         if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
1002                 Debug( LDAP_DEBUG_ANY,
1003                         "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
1004                 return -1;
1005         }
1006
1007         op->o_tag = LDAP_REQ_ADD;
1008
1009         rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
1010
1011         if ( rc != LDAP_SUCCESS ) {
1012                 Debug( LDAP_DEBUG_ANY,
1013                         "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
1014                 return rc;
1015         }
1016
1017         dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
1018         ber_dupbv( &op->o_req_dn, &dn );
1019         ber_dupbv( &op->o_req_ndn, &ndn );
1020         slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
1021         slap_sl_free( dn.bv_val, op->o_tmpmemctx );
1022
1023         if ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_DELETE ) {
1024                 if ( entry )
1025                         *entry = NULL;
1026                 return LDAP_SUCCESS;
1027         }
1028
1029         if ( entry == NULL ) {
1030                 return -1;
1031         }
1032
1033         e = ( Entry * ) ch_calloc( 1, sizeof( Entry ) );
1034         *entry = e;
1035         e->e_name = op->o_req_dn;
1036         e->e_nname = op->o_req_ndn;
1037
1038         while ( ber_remaining( ber ) ) {
1039                 if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) ==
1040                         LBER_ERROR ) || ( tmp.sml_type.bv_val == NULL ))
1041                 {
1042                         break;
1043                 }
1044
1045                 mod  = (Modifications *) ch_malloc( sizeof( Modifications ));
1046
1047                 mod->sml_op = LDAP_MOD_REPLACE;
1048                 mod->sml_next = NULL;
1049                 mod->sml_desc = NULL;
1050                 mod->sml_type = tmp.sml_type;
1051                 mod->sml_values = tmp.sml_values;
1052                 mod->sml_nvalues = NULL;
1053
1054                 *modtail = mod;
1055                 modtail = &mod->sml_next;
1056         }
1057
1058         if ( *modlist == NULL ) {
1059                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: no attributes\n",
1060                         0, 0, 0 );
1061                 rc = -1;
1062                 goto done;
1063         }
1064
1065         rc = slap_mods_check( *modlist, 1, &text, txtbuf, textlen, NULL );
1066
1067         if ( rc != LDAP_SUCCESS ) {
1068                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods check (%s)\n",
1069                         text, 0, 0 );
1070                 goto done;
1071         }
1072
1073         /* Strip out dynamically generated attrs */
1074         for ( modtail = modlist; *modtail ; ) {
1075                 mod = *modtail;
1076                 if ( mod->sml_desc->ad_type->sat_flags & SLAP_AT_DYNAMIC ) {
1077                         *modtail = mod->sml_next;
1078                         slap_mod_free( &mod->sml_mod, 0 );
1079                         ch_free( mod );
1080                 } else {
1081                         modtail = &mod->sml_next;
1082                 }
1083         }
1084
1085         /* Strip out attrs in exattrs list */
1086         for ( modtail = modlist; *modtail ; ) {
1087                 mod = *modtail;
1088                 if ( ldap_charray_inlist( si->si_exattrs,
1089                                         mod->sml_desc->ad_type->sat_cname.bv_val )) {
1090                         *modtail = mod->sml_next;
1091                         slap_mod_free( &mod->sml_mod, 0 );
1092                         ch_free( mod );
1093                 } else {
1094                         modtail = &mod->sml_next;
1095                 }
1096         }
1097         
1098         rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
1099         if( rc != LDAP_SUCCESS ) {
1100                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods2entry (%s)\n",
1101                         text, 0, 0 );
1102         }
1103
1104 done:
1105         ber_free ( ber, 0 );
1106         if ( rc != LDAP_SUCCESS ) {
1107                 if ( e ) {
1108                         entry_free( e );
1109                         *entry = e = NULL;
1110                 }
1111         }
1112
1113         return rc;
1114 }
1115
1116 int
1117 syncrepl_entry(
1118         syncinfo_t* si,
1119         Operation *op,
1120         Entry* entry,
1121         Modifications* modlist,
1122         int syncstate,
1123         struct berval* syncUUID,
1124         struct sync_cookie* syncCookie_req )
1125 {
1126         Backend *be = op->o_bd;
1127         slap_callback   cb = { NULL };
1128         struct berval   *syncuuid_bv = NULL;
1129         struct berval   syncUUID_strrep = BER_BVNULL;
1130         struct berval   uuid_bv = BER_BVNULL;
1131
1132         SlapReply       rs_search = {REP_RESULT};
1133         SlapReply       rs_delete = {REP_RESULT};
1134         SlapReply       rs_add = {REP_RESULT};
1135         SlapReply       rs_modify = {REP_RESULT};
1136         Filter f = {0};
1137         AttributeAssertion ava = {0};
1138         int rc = LDAP_SUCCESS;
1139         int ret = LDAP_SUCCESS;
1140         const char *text;
1141
1142         struct berval pdn = BER_BVNULL;
1143         struct berval org_req_dn = BER_BVNULL;
1144         struct berval org_req_ndn = BER_BVNULL;
1145         struct berval org_dn = BER_BVNULL;
1146         struct berval org_ndn = BER_BVNULL;
1147         int     org_managedsait;
1148
1149         if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD )) {
1150                 syncuuid_bv = ber_dupbv( NULL, syncUUID );
1151                 avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
1152                         syncuuid_cmp, avl_dup_error );
1153         }
1154
1155         if ( syncstate == LDAP_SYNC_PRESENT ) {
1156                 return 0;
1157         } else if ( syncstate != LDAP_SYNC_DELETE ) {
1158                 if ( entry == NULL ) {
1159                         return 0;
1160                 }
1161         }
1162
1163         f.f_choice = LDAP_FILTER_EQUALITY;
1164         f.f_ava = &ava;
1165         ava.aa_desc = slap_schema.si_ad_entryUUID;
1166         slap_uuidstr_from_normalized( &syncUUID_strrep, syncUUID, op->o_tmpmemctx );
1167         ava.aa_value = *syncUUID;
1168         op->ors_filter = &f;
1169
1170         op->ors_filterstr.bv_len = (sizeof("entryUUID=")-1) + syncUUID->bv_len;
1171         op->ors_filterstr.bv_val = (char *) slap_sl_malloc(
1172                 op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); 
1173         AC_MEMCPY( op->ors_filterstr.bv_val, "entryUUID=", sizeof("entryUUID=")-1 );
1174         AC_MEMCPY( &op->ors_filterstr.bv_val[sizeof("entryUUID=")-1],
1175                 syncUUID->bv_val, syncUUID->bv_len );
1176         op->ors_filterstr.bv_val[op->ors_filterstr.bv_len] = '\0';
1177
1178         op->o_tag = LDAP_REQ_SEARCH;
1179         op->ors_scope = LDAP_SCOPE_SUBTREE;
1180
1181         /* get syncrepl cookie of shadow replica from subentry */
1182         op->o_req_dn = si->si_base;
1183         op->o_req_ndn = si->si_base;
1184
1185         op->o_time = slap_get_time();
1186         op->ors_tlimit = SLAP_NO_LIMIT;
1187         op->ors_slimit = 1;
1188
1189         op->ors_attrs = slap_anlist_no_attrs;
1190         op->ors_attrsonly = 1;
1191
1192         /* set callback function */
1193         op->o_callback = &cb;
1194         cb.sc_response = dn_callback;
1195         cb.sc_private = si;
1196
1197         si->si_syncUUID_ndn.bv_val = NULL;
1198
1199         if ( limits_check( op, &rs_search ) == 0 ) {
1200                 rc = be->be_search( op, &rs_search );
1201         }
1202
1203         if ( op->ors_filterstr.bv_val ) {
1204                 slap_sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1205         }
1206
1207         cb.sc_response = null_callback;
1208         cb.sc_private = si;
1209
1210         if ( rs_search.sr_err == LDAP_SUCCESS && si->si_syncUUID_ndn.bv_val ) {
1211                 char *subseq_ptr;
1212
1213                 if ( syncstate != LDAP_SYNC_DELETE ) {
1214                         op->o_no_psearch = 1;
1215                 }
1216
1217                 ber_dupbv( &op->o_sync_csn, syncCookie_req->ctxcsn );
1218                 if ( op->o_sync_csn.bv_val ) {
1219                         subseq_ptr = strstr( op->o_sync_csn.bv_val, "#0000" );
1220                         subseq_ptr += 4;
1221                         *subseq_ptr = '1';
1222                 }
1223                 
1224                 op->o_req_dn = si->si_syncUUID_ndn;
1225                 op->o_req_ndn = si->si_syncUUID_ndn;
1226                 op->o_tag = LDAP_REQ_DELETE;
1227                 rc = be->be_delete( op, &rs_delete );
1228
1229                 org_req_dn = op->o_req_dn;
1230                 org_req_ndn = op->o_req_ndn;
1231                 org_dn = op->o_dn;
1232                 org_ndn = op->o_ndn;
1233                 org_managedsait = get_manageDSAit( op );
1234                 op->o_dn = op->o_bd->be_rootdn;
1235                 op->o_ndn = op->o_bd->be_rootndn;
1236                 op->o_managedsait = 1;
1237
1238                 while ( rs_delete.sr_err == LDAP_SUCCESS && op->o_delete_glue_parent ) {
1239                         op->o_delete_glue_parent = 0;
1240                         if ( !be_issuffix( op->o_bd, &op->o_req_ndn )) {
1241                                 slap_callback cb = { NULL };
1242                                 cb.sc_response = slap_null_cb;
1243                                 dnParent( &op->o_req_ndn, &pdn );
1244                                 op->o_req_dn = pdn;
1245                                 op->o_req_ndn = pdn;
1246                                 op->o_callback = &cb;
1247                                 op->o_bd->be_delete( op, &rs_delete );
1248                         } else {
1249                                 break;
1250                     }
1251                 }
1252
1253                 op->o_managedsait = org_managedsait;
1254                 op->o_dn = org_dn;
1255                 op->o_ndn = org_ndn;
1256                 op->o_req_dn = org_req_dn;
1257                 op->o_req_ndn = org_req_ndn;
1258                 op->o_delete_glue_parent = 0;
1259
1260                 op->o_no_psearch = 0;
1261         }
1262
1263         switch ( syncstate ) {
1264         case LDAP_SYNC_ADD:
1265         case LDAP_SYNC_MODIFY:
1266                 if ( rs_search.sr_err == LDAP_SUCCESS ||
1267                          rs_search.sr_err == LDAP_REFERRAL ||
1268                          rs_search.sr_err == LDAP_NO_SUCH_OBJECT ||
1269                          rs_search.sr_err == LDAP_NOT_ALLOWED_ON_NONLEAF )
1270                 {
1271                         attr_delete( &entry->e_attrs, slap_schema.si_ad_entryUUID );
1272                         attr_merge_one( entry, slap_schema.si_ad_entryUUID,
1273                                 &syncUUID_strrep, syncUUID );
1274
1275                         op->o_tag = LDAP_REQ_ADD;
1276                         op->ora_e = entry;
1277                         op->o_req_dn = entry->e_name;
1278                         op->o_req_ndn = entry->e_nname;
1279
1280                         rc = be->be_add( op, &rs_add );
1281
1282                         if ( rs_add.sr_err != LDAP_SUCCESS ) {
1283                                 if ( rs_add.sr_err == LDAP_ALREADY_EXISTS &&
1284                                          rs_search.sr_err != LDAP_NO_SUCH_OBJECT ) {
1285                                         Modifications *mod;
1286                                         Modifications *modtail = modlist;
1287
1288                                         assert( modlist );
1289
1290                                         for ( mod = modlist; mod != NULL; mod = mod->sml_next ) {
1291                                                 modtail = mod;
1292                                         }
1293
1294                                         mod = (Modifications *)ch_calloc(1, sizeof(Modifications));
1295                                         ber_dupbv( &uuid_bv, syncUUID );
1296                                         mod->sml_op = LDAP_MOD_REPLACE;
1297                                         mod->sml_desc = slap_schema.si_ad_entryUUID;
1298                                         mod->sml_type = mod->sml_desc->ad_cname;
1299                                         ber_bvarray_add( &mod->sml_values, &uuid_bv );
1300                                         modtail->sml_next = mod;
1301                                         
1302                                         op->o_tag = LDAP_REQ_MODIFY;
1303                                         op->orm_modlist = modlist;
1304                                         op->o_req_dn = entry->e_name;
1305                                         op->o_req_ndn = entry->e_nname;
1306
1307                                         rc = be->be_modify( op, &rs_modify );
1308                                         if ( rs_modify.sr_err != LDAP_SUCCESS ) {
1309                                                 Debug( LDAP_DEBUG_ANY,
1310                                                         "syncrepl_entry : be_modify failed (%d)\n",
1311                                                         rs_modify.sr_err, 0, 0 );
1312                                         }
1313                                         ret = 1;
1314                                         goto done;
1315                                 } else if ( rs_modify.sr_err == LDAP_REFERRAL ||
1316                                                         rs_modify.sr_err == LDAP_NO_SUCH_OBJECT ) {
1317                                         syncrepl_add_glue( op, entry );
1318                                         ret = 0;
1319                                         goto done;
1320                                 } else {
1321                                         Debug( LDAP_DEBUG_ANY,
1322                                                 "syncrepl_entry : be_add failed (%d)\n",
1323                                                 rs_add.sr_err, 0, 0 );
1324                                         ret = 1;
1325                                         goto done;
1326                                 }
1327                         } else {
1328                                 be_entry_release_w( op, entry );
1329                                 ret = 0;
1330                                 goto done;
1331                         }
1332                 } else {
1333                         Debug( LDAP_DEBUG_ANY,
1334                                 "syncrepl_entry : be_search failed (%d)\n",
1335                                 rs_search.sr_err, 0, 0 );
1336                         ret = 1;
1337                         goto done;
1338                 }
1339
1340         case LDAP_SYNC_DELETE :
1341                 /* Already deleted */
1342                 ret = 0;
1343                 goto done;
1344
1345         default :
1346                 Debug( LDAP_DEBUG_ANY,
1347                         "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1348                 ret = 1;
1349                 goto done;
1350         }
1351
1352 done :
1353
1354         if ( syncUUID_strrep.bv_val ) {
1355                 slap_sl_free( syncUUID_strrep.bv_val, op->o_tmpmemctx );
1356         }
1357         if ( si->si_syncUUID_ndn.bv_val ) {
1358                 ch_free( si->si_syncUUID_ndn.bv_val );
1359                 si->si_syncUUID_ndn.bv_val = NULL;
1360         }
1361         return ret;
1362 }
1363
1364 static struct berval gcbva[] = {
1365         BER_BVC("top"),
1366         BER_BVC("glue"),
1367         BER_BVNULL
1368 };
1369
1370 static void
1371 syncrepl_del_nonpresent(
1372         Operation *op,
1373         syncinfo_t *si )
1374 {
1375         Backend* be = op->o_bd;
1376         slap_callback   cb = { NULL };
1377         SlapReply       rs_search = {REP_RESULT};
1378         SlapReply       rs_delete = {REP_RESULT};
1379         SlapReply       rs_modify = {REP_RESULT};
1380         struct nonpresent_entry *np_list, *np_prev;
1381         int rc;
1382         Modifications *ml;
1383         Modifications *mlnext;
1384         Modifications *mod;
1385         Modifications *modlist = NULL;
1386         Modifications **modtail = &modlist;
1387         Attribute       *attr;
1388         AttributeName   an[2];
1389
1390         struct berval pdn = BER_BVNULL;
1391         struct berval org_req_dn = BER_BVNULL;
1392         struct berval org_req_ndn = BER_BVNULL;
1393         struct berval org_dn = BER_BVNULL;
1394         struct berval org_ndn = BER_BVNULL;
1395         int     org_managedsait;
1396
1397         op->o_req_dn = si->si_base;
1398         op->o_req_ndn = si->si_base;
1399
1400         cb.sc_response = nonpresent_callback;
1401         cb.sc_private = si;
1402
1403         op->o_callback = &cb;
1404         op->o_tag = LDAP_REQ_SEARCH;
1405         op->ors_scope = si->si_scope;
1406         op->ors_deref = LDAP_DEREF_NEVER;
1407         op->o_time = slap_get_time();
1408         op->ors_tlimit = SLAP_NO_LIMIT;
1409         op->ors_slimit = SLAP_NO_LIMIT;
1410
1411         memset( &an[0], 0, 2 * sizeof( AttributeName ) );
1412         an[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
1413         an[0].an_desc = slap_schema.si_ad_entryUUID;
1414         op->ors_attrs = an;
1415
1416         op->ors_attrsonly = 0;
1417         op->ors_filter = str2filter_x( op, si->si_filterstr.bv_val );
1418         op->ors_filterstr = si->si_filterstr;
1419
1420         op->o_nocaching = 1;
1421         op->o_managedsait = 0;
1422
1423         if ( limits_check( op, &rs_search ) == 0 ) {
1424                 rc = be->be_search( op, &rs_search );
1425         }
1426
1427         op->o_managedsait = 1;
1428         op->o_nocaching = 0;
1429
1430         if ( op->ors_filter ) filter_free_x( op, op->ors_filter );
1431
1432         if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
1433                 np_list = LDAP_LIST_FIRST( &si->si_nonpresentlist );
1434                 while ( np_list != NULL ) {
1435                         LDAP_LIST_REMOVE( np_list, npe_link );
1436                         np_prev = np_list;
1437                         np_list = LDAP_LIST_NEXT( np_list, npe_link );
1438                         op->o_tag = LDAP_REQ_DELETE;
1439                         op->o_callback = &cb;
1440                         cb.sc_response = null_callback;
1441                         cb.sc_private = si;
1442                         op->o_req_dn = *np_prev->npe_name;
1443                         op->o_req_ndn = *np_prev->npe_nname;
1444                         rc = op->o_bd->be_delete( op, &rs_delete );
1445
1446                         if ( rs_delete.sr_err == LDAP_NOT_ALLOWED_ON_NONLEAF ) {
1447                                 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1448                                 mod->sml_op = LDAP_MOD_REPLACE;
1449                                 mod->sml_desc = slap_schema.si_ad_objectClass;
1450                                 mod->sml_type = mod->sml_desc->ad_cname;
1451                                 mod->sml_values = &gcbva[0];
1452                                 *modtail = mod;
1453                                 modtail = &mod->sml_next;
1454
1455                                 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1456                                 mod->sml_op = LDAP_MOD_REPLACE;
1457                                 mod->sml_desc = slap_schema.si_ad_structuralObjectClass;
1458                                 mod->sml_type = mod->sml_desc->ad_cname;
1459                                 mod->sml_values = &gcbva[1];
1460                                 *modtail = mod;
1461                                 modtail = &mod->sml_next;
1462
1463                                 op->o_tag = LDAP_REQ_MODIFY;
1464                                 op->orm_modlist = modlist;
1465
1466                                 rc = be->be_modify( op, &rs_modify );
1467
1468                                 for ( ml = modlist; ml != NULL; ml = mlnext ) {
1469                                         mlnext = ml->sml_next;
1470                                         free( ml );
1471                                 }
1472                         }
1473
1474                         org_req_dn = op->o_req_dn;
1475                         org_req_ndn = op->o_req_ndn;
1476                         org_dn = op->o_dn;
1477                         org_ndn = op->o_ndn;
1478                         org_managedsait = get_manageDSAit( op );
1479                         op->o_dn = op->o_bd->be_rootdn;
1480                         op->o_ndn = op->o_bd->be_rootndn;
1481                         op->o_managedsait = 1;
1482
1483                         while ( rs_delete.sr_err == LDAP_SUCCESS &&
1484                                         op->o_delete_glue_parent ) {
1485                                 op->o_delete_glue_parent = 0;
1486                                 if ( !be_issuffix( op->o_bd, &op->o_req_ndn )) {
1487                                         slap_callback cb = { NULL };
1488                                         cb.sc_response = slap_null_cb;
1489                                         dnParent( &op->o_req_ndn, &pdn );
1490                                         op->o_req_dn = pdn;
1491                                         op->o_req_ndn = pdn;
1492                                         op->o_callback = &cb;
1493                                         /* give it a root privil ? */
1494                                         op->o_bd->be_delete( op, &rs_delete );
1495                                 } else {
1496                                         break;
1497                             }
1498                         }
1499
1500                         op->o_managedsait = org_managedsait;
1501                         op->o_dn = org_dn;
1502                         op->o_ndn = org_ndn;
1503                         op->o_req_dn = org_req_dn;
1504                         op->o_req_ndn = org_req_ndn;
1505                         op->o_delete_glue_parent = 0;
1506
1507                         ber_bvfree( np_prev->npe_name );
1508                         ber_bvfree( np_prev->npe_nname );
1509                         op->o_req_dn.bv_val = NULL;
1510                         op->o_req_ndn.bv_val = NULL;
1511                         ch_free( np_prev );
1512                 }
1513         }
1514
1515         return;
1516 }
1517
1518 void
1519 syncrepl_add_glue(
1520         Operation* op,
1521         Entry *e )
1522 {
1523         Backend *be = op->o_bd;
1524         slap_callback cb = { NULL };
1525         Attribute       *a;
1526         int     rc;
1527         int suffrdns;
1528         int i;
1529         struct berval dn = {0, NULL};
1530         struct berval ndn = {0, NULL};
1531         Entry   *glue;
1532         SlapReply       rs_add = {REP_RESULT};
1533         char    *ptr, *comma;
1534
1535         op->o_tag = LDAP_REQ_ADD;
1536         op->o_callback = &cb;
1537         cb.sc_response = null_callback;
1538         cb.sc_private = NULL;
1539
1540         dn = e->e_name;
1541         ndn = e->e_nname;
1542
1543         /* count RDNs in suffix */
1544         if ( be->be_nsuffix[0].bv_len ) {
1545                 for (i=0, ptr=be->be_nsuffix[0].bv_val; ptr; ptr=strchr( ptr, ',' )) {
1546                         ptr++;
1547                         i++;
1548                 }
1549                 suffrdns = i;
1550         } else {
1551                 /* suffix is "" */
1552                 suffrdns = 0;
1553         }
1554
1555         /* Start with BE suffix */
1556         for ( i = 0, ptr = NULL; i < suffrdns; i++ ) {
1557                 comma = strrchr(dn.bv_val, ',');
1558                 if ( ptr ) *ptr = ',';
1559                 if ( comma ) *comma = '\0';
1560                 ptr = comma;
1561         }
1562         if ( ptr ) {
1563                 *ptr++ = ',';
1564                 dn.bv_len -= ptr - dn.bv_val;
1565                 dn.bv_val = ptr;
1566         }
1567         /* the normalizedDNs are always the same length, no counting
1568          * required.
1569          */
1570         if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) {
1571                 ndn.bv_val += ndn.bv_len - be->be_nsuffix[0].bv_len;
1572                 ndn.bv_len = be->be_nsuffix[0].bv_len;
1573         }
1574
1575         while ( ndn.bv_val > e->e_nname.bv_val ) {
1576                 glue = (Entry *) ch_calloc( 1, sizeof(Entry) );
1577                 ber_dupbv( &glue->e_name, &dn );
1578                 ber_dupbv( &glue->e_nname, &ndn );
1579
1580                 a = ch_calloc( 1, sizeof( Attribute ));
1581                 a->a_desc = slap_schema.si_ad_objectClass;
1582
1583                 a->a_vals = ch_calloc( 3, sizeof( struct berval ));
1584                 ber_dupbv( &a->a_vals[0], &gcbva[0] );
1585                 ber_dupbv( &a->a_vals[1], &gcbva[1] );
1586                 ber_dupbv( &a->a_vals[2], &gcbva[2] );
1587
1588                 a->a_nvals = a->a_vals;
1589
1590                 a->a_next = glue->e_attrs;
1591                 glue->e_attrs = a;
1592
1593                 a = ch_calloc( 1, sizeof( Attribute ));
1594                 a->a_desc = slap_schema.si_ad_structuralObjectClass;
1595
1596                 a->a_vals = ch_calloc( 2, sizeof( struct berval ));
1597                 ber_dupbv( &a->a_vals[0], &gcbva[1] );
1598                 ber_dupbv( &a->a_vals[1], &gcbva[2] );
1599
1600                 a->a_nvals = a->a_vals;
1601
1602                 a->a_next = glue->e_attrs;
1603                 glue->e_attrs = a;
1604
1605                 op->o_req_dn = glue->e_name;
1606                 op->o_req_ndn = glue->e_nname;
1607                 op->ora_e = glue;
1608                 rc = be->be_add ( op, &rs_add );
1609                 if ( rs_add.sr_err == LDAP_SUCCESS ) {
1610                         be_entry_release_w( op, glue );
1611                 } else {
1612                 /* incl. ALREADY EXIST */
1613                         entry_free( glue );
1614                 }
1615
1616                 /* Move to next child */
1617                 for (ptr = dn.bv_val-2; ptr > e->e_name.bv_val && *ptr != ','; ptr--) {
1618                         /* empty */
1619                 }
1620                 if ( ptr == e->e_name.bv_val ) break;
1621                 dn.bv_val = ++ptr;
1622                 dn.bv_len = e->e_name.bv_len - (ptr-e->e_name.bv_val);
1623                 for( ptr = ndn.bv_val-2;
1624                         ptr > e->e_nname.bv_val && *ptr != ',';
1625                         ptr--)
1626                 {
1627                         /* empty */
1628                 }
1629                 ndn.bv_val = ++ptr;
1630                 ndn.bv_len = e->e_nname.bv_len - (ptr-e->e_nname.bv_val);
1631         }
1632
1633         op->o_req_dn = e->e_name;
1634         op->o_req_ndn = e->e_nname;
1635         op->ora_e = e;
1636         rc = be->be_add ( op, &rs_add );
1637         if ( rs_add.sr_err == LDAP_SUCCESS ) {
1638                 be_entry_release_w( op, e );
1639         } else {
1640                 entry_free( e );
1641         }
1642
1643         return;
1644 }
1645
1646 static struct berval ocbva[] = {
1647         BER_BVC("top"),
1648         BER_BVC("subentry"),
1649         BER_BVC("syncConsumerSubentry"),
1650         BER_BVNULL
1651 };
1652
1653 static struct berval cnbva[] = {
1654         BER_BVNULL,
1655         BER_BVNULL
1656 };
1657
1658 static struct berval ssbva[] = {
1659         BER_BVC("{}"),
1660         BER_BVNULL
1661 };
1662
1663 static struct berval scbva[] = {
1664         BER_BVNULL,
1665         BER_BVNULL
1666 };
1667
1668 void
1669 syncrepl_updateCookie(
1670         syncinfo_t *si,
1671         Operation *op,
1672         struct berval *pdn,
1673         struct sync_cookie *syncCookie )
1674 {
1675         Backend *be = op->o_bd;
1676         Modifications *ml;
1677         Modifications *mlnext;
1678         Modifications *mod;
1679         Modifications *modlist = NULL;
1680         Modifications **modtail = &modlist;
1681
1682         const char      *text;
1683         char txtbuf[SLAP_TEXT_BUFLEN];
1684         size_t textlen = sizeof txtbuf;
1685
1686         Entry* e = NULL;
1687         int rc;
1688
1689         char syncrepl_cbuf[sizeof(CN_STR SYNCREPL_STR)];
1690         struct berval slap_syncrepl_dn_bv = BER_BVNULL;
1691         struct berval slap_syncrepl_cn_bv = BER_BVNULL;
1692         
1693         slap_callback cb = { NULL };
1694         SlapReply       rs_add = {REP_RESULT};
1695         SlapReply       rs_modify = {REP_RESULT};
1696
1697         slap_sync_cookie_free( &si->si_syncCookie, 0 );
1698         slap_dup_sync_cookie( &si->si_syncCookie, syncCookie );
1699
1700         mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1701         mod->sml_op = LDAP_MOD_REPLACE;
1702         mod->sml_desc = slap_schema.si_ad_objectClass;
1703         mod->sml_type = mod->sml_desc->ad_cname;
1704         mod->sml_values = ocbva;
1705         *modtail = mod;
1706         modtail = &mod->sml_next;
1707
1708         ber_dupbv( &cnbva[0], (struct berval *) &slap_syncrepl_bvc );
1709         assert( si->si_rid < 1000 );
1710         cnbva[0].bv_len = snprintf( cnbva[0].bv_val,
1711                 slap_syncrepl_bvc.bv_len + 1,
1712                 "syncrepl%ld", si->si_rid );
1713         mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1714         mod->sml_op = LDAP_MOD_REPLACE;
1715         mod->sml_desc = slap_schema.si_ad_cn;
1716         mod->sml_type = mod->sml_desc->ad_cname;
1717         mod->sml_values = cnbva;
1718         *modtail = mod;
1719         modtail = &mod->sml_next;
1720
1721         mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1722         mod->sml_op = LDAP_MOD_REPLACE;
1723         mod->sml_desc = slap_schema.si_ad_subtreeSpecification;
1724         mod->sml_type = mod->sml_desc->ad_cname;
1725         mod->sml_values = ssbva;
1726         *modtail = mod;
1727         modtail = &mod->sml_next;
1728
1729         /* Keep this last, so we can avoid touching the previous
1730          * attributes unnecessarily.
1731          */
1732         if ( scbva[0].bv_val ) ch_free( scbva[0].bv_val );
1733         ber_dupbv( &scbva[0], &si->si_syncCookie.octet_str[0] );
1734         mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1735         mod->sml_op = LDAP_MOD_REPLACE;
1736         mod->sml_desc = slap_schema.si_ad_syncreplCookie;
1737         mod->sml_type = mod->sml_desc->ad_cname;
1738         mod->sml_values = scbva;
1739         *modtail = mod;
1740         modtail = &mod->sml_next;
1741
1742         mlnext = mod;
1743
1744         op->o_tag = LDAP_REQ_ADD;
1745         rc = slap_mods_opattrs( op, modlist, modtail,
1746                  &text, txtbuf, textlen, 0 );
1747
1748         for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
1749                 ml->sml_op = LDAP_MOD_REPLACE;
1750         }
1751
1752         if( rc != LDAP_SUCCESS ) {
1753                 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods opattrs (%s)\n",
1754                          text, 0, 0 );
1755         }
1756
1757         e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1758
1759         slap_syncrepl_cn_bv.bv_val = syncrepl_cbuf;
1760         assert( si->si_rid < 1000 );
1761         slap_syncrepl_cn_bv.bv_len = snprintf( slap_syncrepl_cn_bv.bv_val,
1762                 slap_syncrepl_cn_bvc.bv_len + 1,
1763                 "cn=syncrepl%ld", si->si_rid );
1764
1765         build_new_dn( &slap_syncrepl_dn_bv, pdn, &slap_syncrepl_cn_bv,
1766                 op->o_tmpmemctx );
1767         ber_dupbv( &e->e_name, &slap_syncrepl_dn_bv );
1768         ber_dupbv( &e->e_nname, &slap_syncrepl_dn_bv );
1769
1770         if ( slap_syncrepl_dn_bv.bv_val ) {
1771                 slap_sl_free( slap_syncrepl_dn_bv.bv_val, op->o_tmpmemctx );
1772         }
1773
1774         e->e_attrs = NULL;
1775
1776         rc = slap_mods2entry( modlist, &e, 1, 1, &text, txtbuf, textlen );
1777
1778         if( rc != LDAP_SUCCESS ) {
1779                 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods2entry (%s)\n",
1780                          text, 0, 0 );
1781         }
1782
1783         cb.sc_response = null_callback;
1784         cb.sc_private = si;
1785
1786         op->o_callback = &cb;
1787         op->o_req_dn = e->e_name;
1788         op->o_req_ndn = e->e_nname;
1789
1790         /* update persistent cookie */
1791 update_cookie_retry:
1792         op->o_tag = LDAP_REQ_MODIFY;
1793         /* Just modify the cookie value, not the entire entry */
1794         op->orm_modlist = mod;
1795         rc = be->be_modify( op, &rs_modify );
1796
1797         if ( rs_modify.sr_err != LDAP_SUCCESS ) {
1798                 if ( rs_modify.sr_err == LDAP_REFERRAL ||
1799                          rs_modify.sr_err == LDAP_NO_SUCH_OBJECT ) {
1800                         op->o_tag = LDAP_REQ_ADD;
1801                         op->ora_e = e;
1802                         rc = be->be_add( op, &rs_add );
1803                         if ( rs_add.sr_err != LDAP_SUCCESS ) {
1804                                 if ( rs_add.sr_err == LDAP_ALREADY_EXISTS ) {
1805                                         goto update_cookie_retry;
1806                                 } else if ( rs_add.sr_err == LDAP_REFERRAL ||
1807                                                         rs_add.sr_err == LDAP_NO_SUCH_OBJECT ) {
1808                                         Debug( LDAP_DEBUG_ANY,
1809                                                 "cookie will be non-persistent\n",
1810                                                 0, 0, 0 );
1811                                 } else {
1812                                         Debug( LDAP_DEBUG_ANY,
1813                                                 "be_add failed (%d)\n", rs_add.sr_err, 0, 0 );
1814                                 }
1815                         } else {
1816                                 be_entry_release_w( op, e );
1817                                 goto done;
1818                         }
1819                 } else {
1820                         Debug( LDAP_DEBUG_ANY,
1821                                 "be_modify failed (%d)\n", rs_modify.sr_err, 0, 0 );
1822                 }
1823         }
1824
1825         if ( e != NULL ) {
1826                 entry_free( e );
1827         }
1828
1829 done :
1830
1831         if ( cnbva[0].bv_val ) {
1832                 ch_free( cnbva[0].bv_val );
1833                 cnbva[0].bv_val = NULL;
1834         }
1835         if ( scbva[0].bv_val ) {
1836                 ch_free( scbva[0].bv_val );
1837                 scbva[0].bv_val = NULL;
1838         }
1839
1840         if ( mlnext->sml_next ) {
1841                 slap_mods_free( mlnext->sml_next );
1842                 mlnext->sml_next = NULL;
1843         }
1844
1845         for (ml = modlist ; ml != NULL; ml = mlnext ) {
1846                 mlnext = ml->sml_next;
1847                 free( ml );
1848         }
1849
1850         return;
1851 }
1852
1853 int
1854 syncrepl_isupdate( Operation *op )
1855 {
1856         return ( syncrepl_isupdate_dn( op->o_bd, &op->o_ndn ));
1857 }
1858
1859 int
1860 syncrepl_isupdate_dn(
1861         Backend*                be,
1862         struct berval*  ndn )
1863 {
1864         syncinfo_t*     si;
1865         int                     ret = 0;
1866
1867         if ( !LDAP_STAILQ_EMPTY( &be->be_syncinfo )) {
1868                 LDAP_STAILQ_FOREACH( si, &be->be_syncinfo, si_next ) {
1869                         if ( ( ret = dn_match( &si->si_updatedn, ndn ) ) ) {
1870                                 return ret;
1871                         }
1872                 }
1873         }
1874         return 0;
1875 }
1876
1877 static int
1878 dn_callback(
1879         Operation*      op,
1880         SlapReply*      rs )
1881 {
1882         syncinfo_t *si = op->o_callback->sc_private;
1883
1884         if ( rs->sr_type == REP_SEARCH ) {
1885                 if ( si->si_syncUUID_ndn.bv_val != NULL ) {
1886                         Debug( LDAP_DEBUG_ANY,
1887                                 "dn_callback : consistency error - entryUUID is not unique\n", 0, 0, 0 );
1888                 } else {
1889                         ber_dupbv_x( &si->si_syncUUID_ndn, &rs->sr_entry->e_nname, NULL );
1890                 }
1891         } else if ( rs->sr_type == REP_RESULT ) {
1892                 if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) {
1893                         Debug( LDAP_DEBUG_ANY,
1894                                 "dn_callback : consistency error - entryUUID is not unique\n", 0, 0, 0 );
1895                 }
1896         }
1897
1898         return LDAP_SUCCESS;
1899 }
1900
1901 static int
1902 nonpresent_callback(
1903         Operation*      op,
1904         SlapReply*      rs )
1905 {
1906         syncinfo_t *si = op->o_callback->sc_private;
1907         Attribute *a;
1908         int count = 0;
1909         struct berval* present_uuid = NULL;
1910         struct nonpresent_entry *np_entry;
1911
1912         if ( rs->sr_type == REP_RESULT ) {
1913                 count = avl_free( si->si_presentlist, avl_ber_bvfree );
1914                 si->si_presentlist = NULL;
1915
1916         } else if ( rs->sr_type == REP_SEARCH ) {
1917                 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
1918
1919                 if ( a == NULL ) return 0;
1920
1921                 present_uuid = avl_find( si->si_presentlist, &a->a_nvals[0],
1922                         syncuuid_cmp );
1923
1924                 if ( present_uuid == NULL ) {
1925                         np_entry = (struct nonpresent_entry *)
1926                                 ch_calloc( 1, sizeof( struct nonpresent_entry ));
1927                         np_entry->npe_name = ber_dupbv( NULL, &rs->sr_entry->e_name );
1928                         np_entry->npe_nname = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1929                         LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link );
1930
1931                 } else {
1932                         avl_delete( &si->si_presentlist,
1933                                         &a->a_nvals[0], syncuuid_cmp );
1934                         ch_free( present_uuid->bv_val );
1935                         ch_free( present_uuid );
1936                 }
1937         }
1938         return LDAP_SUCCESS;
1939 }
1940
1941 static int
1942 null_callback(
1943         Operation*      op,
1944         SlapReply*      rs )
1945 {
1946         if ( rs->sr_err != LDAP_SUCCESS &&
1947                 rs->sr_err != LDAP_REFERRAL &&
1948                 rs->sr_err != LDAP_ALREADY_EXISTS &&
1949                 rs->sr_err != LDAP_NO_SUCH_OBJECT &&
1950                 rs->sr_err != LDAP_NOT_ALLOWED_ON_NONLEAF )
1951         {
1952                 Debug( LDAP_DEBUG_ANY,
1953                         "null_callback : error code 0x%x\n",
1954                         rs->sr_err, 0, 0 );
1955         }
1956         return LDAP_SUCCESS;
1957 }
1958
1959 Entry *
1960 slap_create_syncrepl_entry(
1961         Backend *be,
1962         struct berval *context_csn,
1963         struct berval *rdn,
1964         struct berval *cn )
1965 {
1966         Entry* e;
1967
1968         struct berval bv;
1969
1970         e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1971
1972         attr_merge( e, slap_schema.si_ad_objectClass, ocbva, NULL );
1973
1974         attr_merge_one( e, slap_schema.si_ad_structuralObjectClass,
1975                 &ocbva[1], NULL );
1976
1977         attr_merge_one( e, slap_schema.si_ad_cn, cn, NULL );
1978
1979         if ( context_csn ) {
1980                 attr_merge_one( e, slap_schema.si_ad_syncreplCookie,
1981                         context_csn, NULL );
1982         }
1983
1984         bv.bv_val = "{}";
1985         bv.bv_len = sizeof("{}")-1;
1986         attr_merge_one( e, slap_schema.si_ad_subtreeSpecification, &bv, NULL );
1987
1988         build_new_dn( &e->e_name, &be->be_nsuffix[0], rdn, NULL );
1989         ber_dupbv( &e->e_nname, &e->e_name );
1990
1991         return e;
1992 }
1993
1994 struct berval *
1995 slap_uuidstr_from_normalized(
1996         struct berval* uuidstr,
1997         struct berval* normalized,
1998         void *ctx )
1999 {
2000         struct berval *new;
2001         unsigned char nibble;
2002         int i, d = 0;
2003
2004         if ( normalized == NULL ) return NULL;
2005         if ( normalized->bv_len != 16 ) return NULL;
2006
2007         if ( uuidstr ) {
2008                 new = uuidstr;
2009         } else {
2010                 new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx );
2011         }
2012
2013         new->bv_len = 36;
2014
2015         if (( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx )) == NULL) {
2016                 if ( !uuidstr ) slap_sl_free( new, ctx );
2017                 return NULL;
2018         }
2019
2020         for ( i = 0; i < 16; i++ ) {
2021                 if ( i == 4 || i == 6 || i == 8 || i == 10 ) {
2022                         new->bv_val[(i<<1)+d] = '-';
2023                         d += 1;
2024                 }
2025
2026                 nibble = (normalized->bv_val[i] >> 4) & 0xF;
2027                 if ( nibble < 10 ) {
2028                         new->bv_val[(i<<1)+d] = nibble + '0';
2029                 } else {
2030                         new->bv_val[(i<<1)+d] = nibble - 10 + 'a';
2031                 }
2032
2033                 nibble = (normalized->bv_val[i]) & 0xF;
2034                 if ( nibble < 10 ) {
2035                         new->bv_val[(i<<1)+d+1] = nibble + '0';
2036                 } else {
2037                         new->bv_val[(i<<1)+d+1] = nibble - 10 + 'a';
2038                 }
2039         }
2040
2041         new->bv_val[new->bv_len] = '\0';
2042         return new;
2043 }
2044
2045 static int
2046 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
2047 {
2048         const struct berval *uuid1 = v_uuid1;
2049         const struct berval *uuid2 = v_uuid2;
2050         int rc = uuid1->bv_len - uuid2->bv_len;
2051         if ( rc ) return rc;
2052         return ( memcmp( uuid1->bv_val, uuid2->bv_val, uuid1->bv_len ) );
2053 }
2054
2055 static void
2056 avl_ber_bvfree( void *bv )
2057 {
2058         if( bv == NULL ) return;
2059         if ( ((struct berval *)bv)->bv_val != NULL ) {
2060                 ch_free( ((struct berval *)bv)->bv_val );
2061         }
2062         ch_free( (char *) bv );
2063 }
2064
2065 void
2066 syncinfo_free( syncinfo_t *sie )
2067 {
2068         if ( sie->si_provideruri ) {
2069                 ch_free( sie->si_provideruri );
2070         }
2071         if ( sie->si_provideruri_bv ) {
2072                 ber_bvarray_free( sie->si_provideruri_bv );
2073         }
2074         if ( sie->si_updatedn.bv_val ) {
2075                 ch_free( sie->si_updatedn.bv_val );
2076         }
2077         if ( sie->si_binddn ) {
2078                 ch_free( sie->si_binddn );
2079         }
2080         if ( sie->si_passwd ) {
2081                 ch_free( sie->si_passwd );
2082         }
2083         if ( sie->si_saslmech ) {
2084                 ch_free( sie->si_saslmech );
2085         }
2086         if ( sie->si_secprops ) {
2087                 ch_free( sie->si_secprops );
2088         }
2089         if ( sie->si_realm ) {
2090                 ch_free( sie->si_realm );
2091         }
2092         if ( sie->si_authcId ) {
2093                 ch_free( sie->si_authcId );
2094         }
2095         if ( sie->si_authzId ) {
2096                 ch_free( sie->si_authzId );
2097         }
2098         if ( sie->si_filterstr.bv_val ) {
2099                 ch_free( sie->si_filterstr.bv_val );
2100         }
2101         if ( sie->si_base.bv_val ) {
2102                 ch_free( sie->si_base.bv_val );
2103         }
2104         if ( sie->si_attrs ) {
2105                 int i = 0;
2106                 while ( sie->si_attrs[i] != NULL ) {
2107                         ch_free( sie->si_attrs[i] );
2108                         i++;
2109                 }
2110                 ch_free( sie->si_attrs );
2111         }
2112         if ( sie->si_exattrs ) {
2113                 int i = 0;
2114                 while ( sie->si_exattrs[i] != NULL ) {
2115                         ch_free( sie->si_exattrs[i] );
2116                         i++;
2117                 }
2118                 ch_free( sie->si_exattrs );
2119         }
2120         if ( sie->si_anlist ) {
2121                 int i = 0;
2122                 while ( sie->si_anlist[i].an_name.bv_val != NULL ) {
2123                         ch_free( sie->si_anlist[i].an_name.bv_val );
2124                         i++;
2125                 }
2126                 ch_free( sie->si_anlist );
2127         }
2128         if ( sie->si_exanlist ) {
2129                 int i = 0;
2130                 while ( sie->si_exanlist[i].an_name.bv_val != NULL ) {
2131                         ch_free( sie->si_exanlist[i].an_name.bv_val );
2132                         i++;
2133                 }
2134                 ch_free( sie->si_exanlist );
2135         }
2136         if ( sie->si_retryinterval ) {
2137                 ch_free( sie->si_retryinterval );
2138         }
2139         if ( sie->si_retrynum ) {
2140                 ch_free( sie->si_retrynum );
2141         }
2142         if ( sie->si_retrynum_init ) {
2143                 ch_free( sie->si_retrynum_init );
2144         }
2145         slap_sync_cookie_free( &sie->si_syncCookie, 0 );
2146         if ( sie->si_syncUUID_ndn.bv_val ) {
2147                 ch_free( sie->si_syncUUID_ndn.bv_val );
2148         }
2149         if ( sie->si_presentlist ) {
2150             avl_free( sie->si_presentlist, avl_ber_bvfree );
2151         }
2152         if ( sie->si_ld ) {
2153                 ldap_ld_free( sie->si_ld, 1, NULL, NULL );
2154         }
2155         while ( !LDAP_LIST_EMPTY( &sie->si_nonpresentlist )) {
2156                 struct nonpresent_entry* npe;
2157                 npe = LDAP_LIST_FIRST( &sie->si_nonpresentlist );
2158                 LDAP_LIST_REMOVE( npe, npe_link );
2159                 if ( npe->npe_name ) {
2160                         if ( npe->npe_name->bv_val ) {
2161                                 ch_free( npe->npe_name->bv_val );
2162                         }
2163                         ch_free( npe->npe_name );
2164                 }
2165                 if ( npe->npe_nname ) {
2166                         if ( npe->npe_nname->bv_val ) {
2167                                 ch_free( npe->npe_nname->bv_val );
2168                         }
2169                         ch_free( npe->npe_nname );
2170                 }
2171                 ch_free( npe );
2172         }
2173         ch_free( sie );
2174 }