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