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