]> git.sur5r.net Git - openldap/blob - servers/slapd/syncrepl.c
b4acf565ce55494525938bf7a95e6eff061a6b85
[openldap] / servers / slapd / syncrepl.c
1 /* $OpenLDAP$ */
2 /*
3  * Replication Engine which uses the LDAP Sync protocol
4  */
5 /*
6  * Copyright 2003 The OpenLDAP Foundation, All Rights Reserved.
7  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
8  */
9 /* Copyright (c) 2003 by International Business Machines, Inc.
10  *
11  * International Business Machines, Inc. (hereinafter called IBM) grants
12  * permission under its copyrights to use, copy, modify, and distribute this
13  * Software with or without fee, provided that the above copyright notice and
14  * all paragraphs of this notice appear in all copies, and that the name of IBM
15  * not be used in connection with the marketing of any product incorporating
16  * the Software or modifications thereof, without specific, written prior
17  * permission.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
20  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
22  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
23  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
24  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
25  */
26 /* Modified by Howard Chu
27  *
28  * Copyright (c) 2003 by Howard Chu, Symas Corporation
29  *
30  * Modifications provided under the terms of the OpenLDAP public license.
31  */
32
33 #include "portable.h"
34
35 #include <stdio.h>
36
37 #include <ac/string.h>
38 #include <ac/socket.h>
39
40 #include "ldap_pvt.h"
41 #include "lutil.h"
42 #include "slap.h"
43 #include "lutil_ldap.h"
44
45 #include "ldap_rq.h"
46
47 #define SYNCREPL_STR    "syncreplxxx"
48 #define CN_STR  "cn="
49
50 static const struct berval slap_syncrepl_bvc = BER_BVC(SYNCREPL_STR);
51 static const struct berval slap_syncrepl_cn_bvc = BER_BVC(CN_STR SYNCREPL_STR);
52
53 static void
54 syncrepl_del_nonpresent( Operation *, syncinfo_t * );
55
56 /* callback functions */
57 static int dn_callback( struct slap_op *, struct slap_rep * );
58 static int nonpresent_callback( struct slap_op *, struct slap_rep * );
59 static int null_callback( struct slap_op *, struct slap_rep * );
60
61 static AttributeDescription *sync_descs[4];
62
63 struct runqueue_s syncrepl_rq;
64
65 void
66 init_syncrepl(syncinfo_t *si)
67 {
68         int i, j, k, n;
69         char **tmp;
70
71         if ( !sync_descs[0] ) {
72                 sync_descs[0] = slap_schema.si_ad_objectClass;
73                 sync_descs[1] = slap_schema.si_ad_structuralObjectClass;
74                 sync_descs[2] = slap_schema.si_ad_entryCSN;
75                 sync_descs[3] = NULL;
76         }
77
78         for ( n = 0; si->si_attrs[ n ] != NULL; n++ ) /* empty */;
79
80         if ( n ) {
81                 /* Delete Attributes */
82                 for ( i = 0; sync_descs[i] != NULL; i++ ) {
83                         for ( j = 0; si->si_attrs[j] != NULL; j++ ) {
84                                 if ( strcmp( si->si_attrs[j], sync_descs[i]->ad_cname.bv_val )
85                                         == 0 )
86                                 {
87                                         ch_free( si->si_attrs[j] );
88                                         for ( k = j; si->si_attrs[k] != NULL; k++ ) {
89                                                 si->si_attrs[k] = si->si_attrs[k+1];
90                                         }
91                                 }
92                         }
93                 }
94                 for ( n = 0; si->si_attrs[ n ] != NULL; n++ ) /* empty */;
95                 tmp = ( char ** ) ch_realloc( si->si_attrs, (n + 4)*sizeof( char * ));
96                 if ( tmp == NULL ) {
97 #ifdef NEW_LOGGING
98                         LDAP_LOG( OPERATION, ERR, "out of memory\n", 0,0,0 );
99 #else
100                         Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
101 #endif
102                 }
103         } else {
104                 tmp = ( char ** ) ch_realloc( si->si_attrs, 5 * sizeof( char * ));
105                 if ( tmp == NULL ) {
106 #ifdef NEW_LOGGING
107                         LDAP_LOG( OPERATION, ERR, "out of memory\n", 0,0,0 );
108 #else
109                         Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
110 #endif
111                 }
112                 tmp[ n++ ] = ch_strdup( "*" );
113         }
114         
115         si->si_attrs = tmp;
116
117         /* Add Attributes */
118
119         for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
120                 si->si_attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
121                 si->si_attrs[ n ] = NULL;
122         }
123 }
124
125 static int
126 ldap_sync_search(
127         syncinfo_t *si,
128         void *ctx
129 )
130 {
131         BerElementBuffer berbuf;
132         BerElement *ber = (BerElement *)&berbuf;
133         LDAPControl c[2], *ctrls[3];
134         struct timeval timeout;
135         ber_int_t       msgid;
136         int rc;
137
138         /* setup LDAP SYNC control */
139         ber_init2( ber, NULL, LBER_USE_DER );
140         ber_set_option( ber, LBER_OPT_BER_MEMCTX, &ctx );
141
142         if ( si->si_syncCookie.octet_str &&
143                  si->si_syncCookie.octet_str[0].bv_val ) {
144                 ber_printf( ber, "{eO}", abs(si->si_type),
145                                         &si->si_syncCookie.octet_str[0] );
146         } else {
147                 ber_printf( ber, "{e}", abs(si->si_type) );
148         }
149
150         if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 )) == LBER_ERROR ) {
151                 ber_free_buf( ber );
152                 return rc;
153         }
154
155         c[0].ldctl_oid = LDAP_CONTROL_SYNC;
156         c[0].ldctl_iscritical = si->si_type < 0;
157         ctrls[0] = &c[0];
158
159         if ( si->si_authzId ) {
160                 c[1].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
161                 ber_str2bv( si->si_authzId, 0, 0, &c[1].ldctl_value );
162                 c[1].ldctl_iscritical = 1;
163                 ctrls[1] = &c[1];
164                 ctrls[2] = NULL;
165         } else {
166                 ctrls[1] = NULL;
167         }
168
169         timeout.tv_sec = si->si_tlimit > 0 ? si->si_tlimit : 1;
170         timeout.tv_usec = 0;
171
172         rc = ldap_search_ext( si->si_ld, si->si_base.bv_val, si->si_scope,
173                 si->si_filterstr.bv_val, si->si_attrs, si->si_attrsonly,
174                 ctrls, NULL, si->si_tlimit < 0 ? NULL : &timeout,
175                 si->si_slimit, &msgid );
176         ber_free_buf( ber );
177
178         return rc;
179 }
180
181 static const Listener dummy_list = { {0, ""}, {0, ""} };
182
183 static int
184 do_syncrep1(
185         Operation *op,
186         syncinfo_t *si )
187 {
188         int     rc;
189
190         char syncrepl_cbuf[sizeof(CN_STR SYNCREPL_STR)];
191         struct berval syncrepl_cn_bv;
192         struct sync_cookie      syncCookie = { NULL, -1, NULL };
193
194         si->si_sync_mode = LDAP_SYNC_STATE_MODE;
195
196         /* Init connection to master */
197
198         rc = ldap_initialize( &si->si_ld, si->si_provideruri );
199         if ( rc != LDAP_SUCCESS ) {
200 #ifdef NEW_LOGGING
201                 LDAP_LOG( OPERATION, ERR,
202                         "do_syncrep1: ldap_initialize failed (%s)\n",
203                         si->si_provideruri, 0, 0 );
204 #else
205                 Debug( LDAP_DEBUG_ANY,
206                         "do_syncrep1: ldap_initialize failed (%s)\n",
207                         si->si_provideruri, 0, 0 );
208 #endif
209                 return rc;
210         }
211
212         op->o_protocol = LDAP_VERSION3;
213         ldap_set_option( si->si_ld, LDAP_OPT_PROTOCOL_VERSION, &op->o_protocol );
214
215         /* Bind to master */
216
217         if ( si->si_tls ) {
218                 rc = ldap_start_tls_s( si->si_ld, NULL, NULL );
219                 if( rc != LDAP_SUCCESS ) {
220 #ifdef NEW_LOGGING
221                         LDAP_LOG ( OPERATION, ERR, "do_syncrep1: "
222                                 "%s: ldap_start_tls failed (%d)\n",
223                                 si->si_tls == SYNCINFO_TLS_CRITICAL ? "Error" : "Warning",
224                                 rc, 0 );
225 #else
226                         Debug( LDAP_DEBUG_ANY,
227                                 "%s: ldap_start_tls failed (%d)\n",
228                                 si->si_tls == SYNCINFO_TLS_CRITICAL ? "Error" : "Warning",
229                                 rc, 0 );
230 #endif
231                         if( si->si_tls == SYNCINFO_TLS_CRITICAL ) goto done;
232                 }
233         }
234
235         if ( si->si_bindmethod == LDAP_AUTH_SASL ) {
236 #ifdef HAVE_CYRUS_SASL
237                 void *defaults;
238
239                 if ( si->si_secprops != NULL ) {
240                         rc = ldap_set_option( si->si_ld,
241                                 LDAP_OPT_X_SASL_SECPROPS, si->si_secprops);
242
243                         if( rc != LDAP_OPT_SUCCESS ) {
244 #ifdef NEW_LOGGING
245                                 LDAP_LOG ( OPERATION, ERR, "do_bind: Error: "
246                                         "ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
247                                         si->si_provideruri, si->si_secprops, 0 );
248 #else
249                                 Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
250                                         "(%s,SECPROPS,\"%s\") failed!\n",
251                                         si->si_provideruri, si->si_secprops, 0 );
252 #endif
253                                 goto done;
254                         }
255                 }
256
257                 defaults = lutil_sasl_defaults( si->si_ld,
258                         si->si_saslmech, si->si_realm,
259                         si->si_authcId, si->si_passwd, si->si_authzId );
260
261                 rc = ldap_sasl_interactive_bind_s( si->si_ld,
262                                 si->si_binddn,
263                                 si->si_saslmech,
264                                 NULL, NULL,
265                                 LDAP_SASL_QUIET,
266                                 lutil_sasl_interact,
267                                 defaults );
268
269                 lutil_sasl_freedefs( defaults );
270
271                 /* FIXME : different error behaviors according to
272                  *      1) return code
273                  *      2) on err policy : exit, retry, backoff ...
274                  */
275                 if ( rc != LDAP_SUCCESS ) {
276 #ifdef NEW_LOGGING
277                         LDAP_LOG ( OPERATION, ERR, "do_syncrep1: "
278                                 "ldap_sasl_interactive_bind_s failed (%d)\n",
279                                 rc, 0, 0 );
280 #else
281                         Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
282                                 "ldap_sasl_interactive_bind_s failed (%d)\n",
283                                 rc, 0, 0 );
284 #endif
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, si->si_binddn, si->si_passwd, si->si_bindmethod );
295                 if ( rc != LDAP_SUCCESS ) {
296 #ifdef NEW_LOGGING
297                         LDAP_LOG ( OPERATION, ERR, "do_syncrep1: "
298                                 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
299 #else
300                         Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
301                                 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
302 #endif
303                         goto done;
304                 }
305         }
306
307         /* get syncrepl cookie of shadow replica from subentry */
308
309         assert( si->si_id < 1000 );
310         syncrepl_cn_bv.bv_val = syncrepl_cbuf;
311         syncrepl_cn_bv.bv_len = snprintf(syncrepl_cbuf, sizeof(syncrepl_cbuf),
312                 CN_STR "syncrepl%d", si->si_id );
313         build_new_dn( &op->o_req_ndn, &si->si_base, &syncrepl_cn_bv,
314                 op->o_tmpmemctx );
315         op->o_req_dn = op->o_req_ndn;
316
317         if ( slap_sync_cookie != NULL ) {
318                 slap_sync_cookie_free( &si->si_syncCookie, 0 );
319                 slap_parse_sync_cookie( slap_sync_cookie );
320                 if ( slap_sync_cookie->ctxcsn == NULL ||
321                          slap_sync_cookie->ctxcsn->bv_val == NULL ) {
322                         slap_init_sync_cookie_ctxcsn( slap_sync_cookie );
323                 }
324                 slap_dup_sync_cookie( &si->si_syncCookie, slap_sync_cookie );
325                 slap_sync_cookie_free( slap_sync_cookie, 1 );
326                 slap_sync_cookie = NULL;
327         }
328
329         /* use in-memory version if it exists */
330         if ( si->si_syncCookie.octet_str == NULL ) {
331                 BerVarray cookie = NULL;
332                 struct berval cookie_bv;
333                 backend_attribute( op, NULL, &op->o_req_ndn,
334                         slap_schema.si_ad_syncreplCookie, &cookie );
335                 if ( cookie ) {
336                         ber_dupbv( &cookie_bv, &cookie[0] );
337                         ber_bvarray_add( &si->si_syncCookie.octet_str, &cookie_bv );
338                         slap_parse_sync_cookie( &si->si_syncCookie );
339                         ber_bvarray_free_x( cookie, op->o_tmpmemctx );
340                 }
341         }
342
343         rc = ldap_sync_search( si, op->o_tmpmemctx );
344
345         if( rc != LDAP_SUCCESS ) {
346 #ifdef NEW_LOGGING
347                 LDAP_LOG ( OPERATION, ERR, "do_syncrep1: "
348                         "ldap_search_ext: %s (%d)\n", ldap_err2string( rc ), rc, 0 );
349 #else
350                 Debug( LDAP_DEBUG_ANY, "do_syncrep1: "
351                         "ldap_search_ext: %s (%d)\n", ldap_err2string( rc ), rc, 0 );
352 #endif
353         }
354
355 done:
356         if ( rc ) {
357                 if ( si->si_ld ) {
358                         ldap_unbind( si->si_ld );
359                         si->si_ld = NULL;
360                 }
361         }
362
363         return rc;
364 }
365
366 static int
367 do_syncrep2(
368         Operation *op,
369         syncinfo_t *si )
370 {
371         LDAPControl     **rctrls = NULL;
372         LDAPControl     *rctrlp;
373
374         BerElementBuffer berbuf;
375         BerElement      *ber = (BerElement *)&berbuf;
376
377         LDAPMessage     *res = NULL;
378         LDAPMessage     *msg = NULL;
379
380         char            *retoid = NULL;
381         struct berval   *retdata = NULL;
382
383         int             sync_info_arrived = 0;
384         Entry           *entry = NULL;
385
386         int             syncstate;
387         struct berval   syncUUID = { 0, NULL };
388         struct sync_cookie      syncCookie = { NULL, -1, NULL };
389         struct sync_cookie      syncCookie_req = { NULL, -1, NULL };
390         struct berval           cookie = { 0, NULL };
391
392         int     rc;
393         int     err;
394         ber_len_t       len;
395         int     syncinfo_arrived = 0;
396
397         slap_callback   cb;
398
399         int rc_efree;
400
401         struct berval   *psub;
402         Modifications   *modlist = NULL;
403
404         const char              *text;
405         int                             match;
406
407         struct timeval *tout_p = NULL;
408         struct timeval tout = { 0, 0 };
409
410         if ( slapd_abrupt_shutdown ) {
411                 rc = -2;
412                 goto done;
413         }
414
415 #ifdef NEW_LOGGING
416         LDAP_LOG ( OPERATION, DETAIL1, "do_syncrep2\n", 0, 0, 0 );
417 #else
418         Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2\n", 0, 0, 0 );
419 #endif
420
421         op->o_callback = &cb;
422
423         psub = &si->si_be->be_nsuffix[0];
424
425         slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
426
427         if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ){
428                 tout_p = &tout;
429         } else {
430                 tout_p = NULL;
431         }
432
433         while (( rc = ldap_result( si->si_ld, LDAP_RES_ANY, LDAP_MSG_ONE, tout_p, &res ))
434                 > 0 )
435         {
436                 if ( slapd_abrupt_shutdown ) {
437                         rc = -2;
438                         goto done;
439                 }
440                 for( msg = ldap_first_message( si->si_ld, res );
441                   msg != NULL;
442                   msg = ldap_next_message( si->si_ld, msg ) )
443                 {
444                         switch( ldap_msgtype( msg ) ) {
445                         case LDAP_RES_SEARCH_ENTRY:
446                                 ldap_get_entry_controls( si->si_ld, msg, &rctrls );
447                                 /* we can't work without the control */
448                                 if ( !rctrls ) {
449                                         rc = -1;
450                                         goto done;
451                                 }
452                                 rctrlp = *rctrls;
453                                 ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
454                                 ber_scanf( ber, "{em", &syncstate, &syncUUID );
455                                 if ( ber_peek_tag( ber, &len ) == LDAP_SYNC_TAG_COOKIE ) {
456                                         ber_scanf( ber, "m}", &cookie );
457                                         if ( cookie.bv_val ) {
458                                                 struct berval tmp_bv;
459                                                 ber_dupbv( &tmp_bv, &cookie );
460                                                 ber_bvarray_add( &syncCookie.octet_str, &tmp_bv );
461                                         }
462                                         if ( syncCookie.octet_str &&
463                                                         syncCookie.octet_str[0].bv_val )
464                                                 slap_parse_sync_cookie( &syncCookie );
465                                 }
466                                 entry = syncrepl_message_to_entry( si, op, msg,
467                                         &modlist, syncstate );
468                                 rc_efree = syncrepl_entry( si, op, entry, modlist, syncstate,
469                                                         &syncUUID, &syncCookie_req, !syncinfo_arrived );
470                                 if ( syncCookie.octet_str && syncCookie.octet_str[0].bv_val ) {
471                                         syncrepl_updateCookie( si, op, psub, &syncCookie );
472                                 }
473                                 ldap_controls_free( rctrls );
474                                 if ( modlist ) {
475                                         slap_mods_free( modlist );
476                                 }
477                                 if ( rc_efree && entry ) {
478                                         entry_free( entry );
479                                 }
480                                 break;
481
482                         case LDAP_RES_SEARCH_REFERENCE:
483 #ifdef NEW_LOGGING
484                                 LDAP_LOG( OPERATION, ERR,
485                                         "do_syncrep2 : reference received\n", 0, 0, 0 );
486 #else
487                                 Debug( LDAP_DEBUG_ANY,
488                                         "do_syncrep2 : reference received\n", 0, 0, 0 );
489 #endif
490                                 break;
491
492                         case LDAP_RES_SEARCH_RESULT:
493                                 ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
494                                         &rctrls, 0 );
495                                 if ( rctrls ) {
496                                         rctrlp = *rctrls;
497                                         ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
498
499                                         ber_scanf( ber, "{" /*"}"*/);
500                                         if ( ber_peek_tag( ber, &len ) == LDAP_SYNC_TAG_COOKIE )
501                                         {
502                                                 ber_scanf( ber, "m", &cookie );
503                                                 if ( cookie.bv_val ) {
504                                                         struct berval tmp_bv;
505                                                         ber_dupbv( &tmp_bv, &cookie );
506                                                         ber_bvarray_add( &syncCookie.octet_str, &tmp_bv);
507                                                 }
508                                                 if ( syncCookie.octet_str &&
509                                                                  syncCookie.octet_str[0].bv_val )
510                                                         slap_parse_sync_cookie( &syncCookie );
511                                         }
512                                 }
513                                 if ( syncCookie_req.ctxcsn == NULL ) {
514                                         match = -1;
515                                 } else if ( syncCookie.ctxcsn == NULL ) {
516                                         match = 1;
517                                 } else {
518                                         value_match( &match, slap_schema.si_ad_entryCSN,
519                                                 slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
520                                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
521                                                 &syncCookie_req.ctxcsn[0], &syncCookie.ctxcsn[0], &text );
522                                 }
523                                 if ( syncCookie.octet_str && syncCookie.octet_str->bv_val
524                                          && match < 0 ) {
525                                         syncrepl_updateCookie( si, op, psub, &syncCookie );
526                                 }
527                                 if ( rctrls ) {
528                                         ldap_controls_free( rctrls );
529                                 }
530                                 if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) {
531                                         /* FIXME : different error behaviors according to
532                                          *      1) err code : LDAP_BUSY ...
533                                          *      2) on err policy : stop service, stop sync, retry
534                                          */
535                                         if ( si->si_sync_mode == LDAP_SYNC_STATE_MODE && match
536                                                 < 0 )
537                                         {
538                                                 syncrepl_del_nonpresent( op, si );
539                                         }
540                                 }
541                                 rc = -2;
542                                 goto done;
543                                 break;
544
545                         case LDAP_RES_INTERMEDIATE:
546                                 rc = ldap_parse_intermediate( si->si_ld, msg,
547                                         &retoid, &retdata, NULL, 0 );
548                                 if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
549                                         sync_info_arrived = 1;
550                                         ber_init2( ber, retdata, LBER_USE_DER );
551                                         ber_scanf( ber, "{e" /*"}"*/, &syncstate );
552
553                                         if ( ber_peek_tag( ber, &len )
554                                                                 == LDAP_SYNC_TAG_COOKIE ) {
555                                                 ber_scanf( ber, /*"{"*/ "m}", &cookie );
556                                                 if ( cookie.bv_val ) {
557                                                         struct berval tmp_bv;
558                                                         ber_dupbv( &tmp_bv, &cookie );
559                                                         ber_bvarray_add( &syncCookie.octet_str, &tmp_bv);
560                                                 }
561                                                 if ( syncCookie.octet_str &&
562                                                                  syncCookie.octet_str[0].bv_val )
563                                                         slap_parse_sync_cookie( &syncCookie );
564                                         }
565
566                                         if ( syncCookie_req.ctxcsn == NULL ) {
567                                                 match = -1;
568                                         } else if ( syncCookie.ctxcsn == NULL ) {
569                                                 match = 1;
570                                         } else {
571                                                 value_match( &match, slap_schema.si_ad_entryCSN,
572                                                         slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
573                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
574                                                         &syncCookie_req.ctxcsn[0],
575                                                         &syncCookie.ctxcsn[0], &text );
576                                         }
577
578                                         if ( syncCookie.ctxcsn && syncCookie.ctxcsn[0].bv_val
579                                                  && match < 0 ) {
580                                                 syncrepl_updateCookie( si, op, psub, &syncCookie);
581                                         }
582
583                                         if ( syncstate == LDAP_SYNC_STATE_MODE_DONE ) {
584                                                 if ( match < 0 ) {
585                                                         syncrepl_del_nonpresent( op, si );
586                                                 }
587                                                 si->si_sync_mode = LDAP_SYNC_LOG_MODE;
588                                         } else if ( syncstate == LDAP_SYNC_LOG_MODE_DONE ) {
589                                                 si->si_sync_mode = LDAP_SYNC_PERSIST_MODE;
590                                         } else if ( syncstate == LDAP_SYNC_REFRESH_DONE ) {
591                                                 si->si_sync_mode = LDAP_SYNC_PERSIST_MODE;
592                                         } else if ( syncstate != LDAP_SYNC_NEW_COOKIE ||
593                                                 syncstate != LDAP_SYNC_LOG_MODE_DONE )
594                                         {
595 #ifdef NEW_LOGGING
596                                                 LDAP_LOG( OPERATION, ERR,
597                                                         "do_syncrep2 : unknown sync info\n", 0, 0, 0 );
598 #else
599                                                 Debug( LDAP_DEBUG_ANY,
600                                                         "do_syncrep2 : unknown sync info\n", 0, 0, 0 );
601 #endif
602                                         }
603
604                                         ldap_memfree( retoid );
605                                         ber_bvfree( retdata );
606                                         break;
607                                 } else {
608 #ifdef NEW_LOGGING
609                                         LDAP_LOG( OPERATION, ERR,"do_syncrep2 :"
610                                                 " unknown intermediate "
611                                                 "response\n", 0, 0, 0 );
612 #else
613                                         Debug( LDAP_DEBUG_ANY, "do_syncrep2 : "
614                                                 "unknown intermediate response (%d)\n",
615                                                 rc, 0, 0 );
616 #endif
617                                         ldap_memfree( retoid );
618                                         ber_bvfree( retdata );
619                                         break;
620                                 }
621                                 break;
622                         default:
623 #ifdef NEW_LOGGING
624                                 LDAP_LOG( OPERATION, ERR, "do_syncrep2 : "
625                                         "unknown message\n", 0, 0, 0 );
626 #else
627                                 Debug( LDAP_DEBUG_ANY, "do_syncrep2 : "
628                                         "unknown message\n", 0, 0, 0 );
629 #endif
630                                 break;
631
632                         }
633                         if ( syncCookie.octet_str ) {
634                                 slap_sync_cookie_free( &syncCookie_req, 0 );
635                                 slap_dup_sync_cookie( &syncCookie_req, &syncCookie );
636                                 slap_sync_cookie_free( &syncCookie, 0 );
637                         }
638                 }
639                 ldap_msgfree( res );
640                 res = NULL;
641         }
642
643         if ( rc == -1 ) {
644                 const char *errstr;
645
646                 ldap_get_option( si->si_ld, LDAP_OPT_ERROR_NUMBER, &rc );
647                 errstr = ldap_err2string( rc );
648                 
649 #ifdef NEW_LOGGING
650                 LDAP_LOG( OPERATION, ERR,
651                         "do_syncrep2 : %s\n", errstr, 0, 0 );
652 #else
653                 Debug( LDAP_DEBUG_ANY,
654                         "do_syncrep2 : %s\n", errstr, 0, 0 );
655 #endif
656         }
657
658 done:
659         slap_sync_cookie_free( &syncCookie, 0 );
660         slap_sync_cookie_free( &syncCookie_req, 0 );
661
662         if ( res ) ldap_msgfree( res );
663
664         if ( rc && si->si_ld ) {
665                 ldap_unbind( si->si_ld );
666                 si->si_ld = NULL;
667         }
668
669         return rc;
670 }
671
672 void *
673 do_syncrepl(
674         void    *ctx,
675         void    *arg )
676 {
677         struct re_s* rtask = arg;
678         syncinfo_t *si = ( syncinfo_t * ) rtask->arg;
679         Connection conn = {0};
680         Operation op = {0};
681         int rc = LDAP_SUCCESS;
682         int first = 0;
683         int dostop = 0;
684         ber_socket_t s;
685
686 #ifdef NEW_LOGGING
687         LDAP_LOG ( OPERATION, DETAIL1, "do_syncrepl\n", 0, 0, 0 );
688 #else
689         Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl\n", 0, 0, 0 );
690 #endif
691
692         if ( si == NULL )
693                 return NULL;
694
695         switch( abs( si->si_type )) {
696         case LDAP_SYNC_REFRESH_ONLY:
697         case LDAP_SYNC_REFRESH_AND_PERSIST:
698                 break;
699         default:
700                 return NULL;
701         }
702
703         if ( slapd_abrupt_shutdown && si->si_ld ) {
704                 ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
705                 connection_client_stop( s );
706                 ldap_unbind( si->si_ld );
707                 si->si_ld = NULL;
708                 return NULL;
709         }
710
711         conn.c_connid = -1;
712         conn.c_send_ldap_result = slap_send_ldap_result;
713         conn.c_send_search_entry = slap_send_search_entry;
714         conn.c_send_search_reference = slap_send_search_reference;
715         conn.c_listener = (Listener *)&dummy_list;
716         conn.c_peer_name = slap_empty_bv;
717
718         /* set memory context */
719 #define SLAB_SIZE 1048576
720         op.o_tmpmemctx = sl_mem_create( SLAB_SIZE, ctx );
721         op.o_tmpmfuncs = &sl_mfuncs;
722
723         op.o_dn = si->si_updatedn;
724         op.o_ndn = si->si_updatedn;
725         op.o_time = slap_get_time();
726         op.o_threadctx = ctx;
727         op.o_managedsait = 1;
728         op.o_bd = si->si_be;
729         op.o_conn = &conn;
730         op.o_connid = op.o_conn->c_connid;
731
732         op.o_sync_state.ctxcsn = NULL;
733         op.o_sync_state.sid = -1;
734         op.o_sync_state.octet_str = NULL;
735         op.o_sync_slog_size = -1;
736         LDAP_STAILQ_FIRST( &op.o_sync_slog_list ) = NULL;
737         op.o_sync_slog_list.stqh_last = &LDAP_STAILQ_FIRST(&op.o_sync_slog_list);
738
739         /* Establish session, do search */
740         if ( !si->si_ld ) {
741                 first = 1;
742                 rc = do_syncrep1( &op, si );
743         }
744
745         /* Process results */
746         if ( rc == LDAP_SUCCESS ) {
747                 ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
748
749                 rc = do_syncrep2( &op, si );
750
751                 if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
752                         /* If we succeeded, enable the connection for further listening.
753                          * If we failed, tear down the connection and reschedule.
754                          */
755                         if ( rc == LDAP_SUCCESS ) {
756                                 if ( first ) {
757                                         rc = connection_client_setup( s, (Listener *)&dummy_list, do_syncrepl,
758                                                 arg );
759                                 } else {
760                                         connection_client_enable( s );
761                                 }
762                         } else if ( !first ) {
763                                 dostop = 1;
764                         }
765                 } else {
766                         if ( rc == -2 ) rc = 0;
767                 }
768         }
769
770         /* At this point, we have 4 cases:
771          * 1) for any hard failure, give up and remove this task
772          * 2) for ServerDown, reschedule this task to run
773          * 3) for Refresh and Success, reschedule to run
774          * 4) for Persist and Success, reschedule to defer
775          */
776         ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
777         if ( ldap_pvt_runqueue_isrunning( &syncrepl_rq, rtask )) {
778                 ldap_pvt_runqueue_stoptask( &syncrepl_rq, rtask );
779         }
780
781         if ( dostop ) {
782                 connection_client_stop( s );
783         }
784
785         if ( rc && rc != LDAP_SERVER_DOWN ) {
786                 ldap_pvt_runqueue_remove( &syncrepl_rq, rtask );
787         } else {
788                 if ( rc == LDAP_SERVER_DOWN ||
789                         si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
790                         rc = 0;
791                 } else {
792                         rc = 1;
793                 }
794                 ldap_pvt_runqueue_resched( &syncrepl_rq, rtask, rc );
795         }
796         ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
797
798         return NULL;
799 }
800
801 Entry*
802 syncrepl_message_to_entry(
803         syncinfo_t      *si,
804         Operation       *op,
805         LDAPMessage     *msg,
806         Modifications   **modlist,
807         int             syncstate
808 )
809 {
810         Entry           *e = NULL;
811         BerElement      *ber = NULL;
812         Modifications   tmp;
813         Modifications   *mod;
814         Modifications   **modtail = modlist;
815
816         const char      *text;
817         char txtbuf[SLAP_TEXT_BUFLEN];
818         size_t textlen = sizeof txtbuf;
819
820         struct berval   bdn = {0, NULL}, dn, ndn;
821         int             rc;
822
823         *modlist = NULL;
824
825         if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
826 #ifdef NEW_LOGGING
827                 LDAP_LOG( OPERATION, ERR,
828                         "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
829 #else
830                 Debug( LDAP_DEBUG_ANY,
831                         "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
832 #endif
833                 return NULL;
834         }
835
836         op->o_tag = LDAP_REQ_ADD;
837
838         rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
839
840         if ( rc != LDAP_SUCCESS ) {
841 #ifdef NEW_LOGGING
842                 LDAP_LOG( OPERATION, ERR,
843                         "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
844 #else
845                 Debug( LDAP_DEBUG_ANY,
846                         "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
847 #endif
848                 return NULL;
849         }
850
851         dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
852         ber_dupbv( &op->o_req_dn, &dn );
853         ber_dupbv( &op->o_req_ndn, &ndn );
854         sl_free( ndn.bv_val, op->o_tmpmemctx );
855         sl_free( dn.bv_val, op->o_tmpmemctx );
856
857         if ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_DELETE ) {
858                 return NULL;
859         }
860
861         e = ( Entry * ) ch_calloc( 1, sizeof( Entry ) );
862         e->e_name = op->o_req_dn;
863         e->e_nname = op->o_req_ndn;
864
865         while ( ber_remaining( ber ) ) {
866                 if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) ==
867                         LBER_ERROR ) || ( tmp.sml_type.bv_val == NULL ))
868                 {
869                         break;
870                 }
871
872                 mod  = (Modifications *) ch_malloc( sizeof( Modifications ));
873
874                 mod->sml_op = LDAP_MOD_REPLACE;
875                 mod->sml_next = NULL;
876                 mod->sml_desc = NULL;
877                 mod->sml_type = tmp.sml_type;
878                 mod->sml_bvalues = tmp.sml_bvalues;
879                 mod->sml_nvalues = NULL;
880
881                 *modtail = mod;
882                 modtail = &mod->sml_next;
883         }
884
885         if ( *modlist == NULL ) {
886 #ifdef NEW_LOGGING
887                 LDAP_LOG( OPERATION, ERR,
888                                 "syncrepl_message_to_entry: no attributes\n", 0, 0, 0 );
889 #else
890                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: no attributes\n",
891                                 0, 0, 0 );
892 #endif
893         }
894
895         rc = slap_mods_check( *modlist, 1, &text, txtbuf, textlen, NULL );
896
897         if ( rc != LDAP_SUCCESS ) {
898 #ifdef NEW_LOGGING
899                 LDAP_LOG( OPERATION, ERR,
900                                 "syncrepl_message_to_entry: mods check (%s)\n", text, 0, 0 );
901 #else
902                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods check (%s)\n",
903                                 text, 0, 0 );
904 #endif
905                 goto done;
906         }
907         
908         rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
909         if( rc != LDAP_SUCCESS ) {
910 #ifdef NEW_LOGGING
911                 LDAP_LOG( OPERATION, ERR,
912                                 "syncrepl_message_to_entry: mods2entry (%s)\n", text, 0, 0 );
913 #else
914                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods2entry (%s)\n",
915                                 text, 0, 0 );
916 #endif
917         }
918
919 done:
920         ber_free ( ber, 0 );
921         if ( rc != LDAP_SUCCESS ) {
922                 entry_free( e );
923                 e = NULL;
924         }
925
926         return e;
927 }
928
929 int
930 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
931 {
932         const struct berval *uuid1 = v_uuid1;
933         const struct berval *uuid2 = v_uuid2;
934         int rc = uuid1->bv_len - uuid2->bv_len;
935         if ( rc ) return rc;
936         return ( strcmp( uuid1->bv_val, uuid2->bv_val ) );
937 }
938
939 int
940 syncrepl_entry(
941         syncinfo_t* si,
942         Operation *op,
943         Entry* e,
944         Modifications* modlist,
945         int syncstate,
946         struct berval* syncUUID,
947         struct sync_cookie* syncCookie_req,
948         int refresh
949 )
950 {
951         Backend *be = op->o_bd;
952         slap_callback   cb;
953         struct berval   *syncuuid_bv = NULL;
954
955         SlapReply       rs = {REP_RESULT};
956         Filter f = {0};
957         AttributeAssertion ava = {0};
958         int rc = LDAP_SUCCESS;
959         int ret = LDAP_SUCCESS;
960         const char *text;
961
962         if ( refresh && si->si_sync_mode == LDAP_SYNC_STATE_MODE &&
963                 ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ))
964         {
965                 syncuuid_bv = ber_dupbv( NULL, syncUUID );
966                 avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
967                         syncuuid_cmp, avl_dup_error );
968         }
969
970         if ( syncstate == LDAP_SYNC_PRESENT ) {
971                 return e ? 1 : 0;
972         }
973
974         f.f_choice = LDAP_FILTER_EQUALITY;
975         f.f_ava = &ava;
976         ava.aa_desc = slap_schema.si_ad_entryUUID;
977         rc = asserted_value_validate_normalize(
978                 ava.aa_desc, ad_mr(ava.aa_desc, SLAP_MR_EQUALITY),
979                 SLAP_MR_EQUALITY, syncUUID, &ava.aa_value, &text, op->o_tmpmemctx );
980         if ( rc != LDAP_SUCCESS ) {
981                 return rc;
982         }
983         op->ors_filter = &f;
984
985         op->ors_filterstr.bv_len = (sizeof("entryUUID=")-1) + syncUUID->bv_len;
986         op->ors_filterstr.bv_val = (char *) sl_malloc(
987                 op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); 
988         AC_MEMCPY( op->ors_filterstr.bv_val, "entryUUID=", sizeof("entryUUID=")-1 );
989         AC_MEMCPY( &op->ors_filterstr.bv_val[sizeof("entryUUID=")-1],
990                 syncUUID->bv_val, syncUUID->bv_len );
991         op->ors_filterstr.bv_val[op->ors_filterstr.bv_len] = '\0';
992
993         op->ors_scope = LDAP_SCOPE_SUBTREE;
994
995         /* get syncrepl cookie of shadow replica from subentry */
996         op->o_req_dn = si->si_base;
997         op->o_req_ndn = si->si_base;
998
999         /* set callback function */
1000         op->o_callback = &cb;
1001         cb.sc_response = dn_callback;
1002         cb.sc_private = si;
1003
1004         si->si_syncUUID_ndn.bv_val = NULL;
1005
1006         rc = be->be_search( op, &rs );
1007
1008         if ( op->ors_filterstr.bv_val ) {
1009                 sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1010         }
1011
1012         cb.sc_response = null_callback;
1013         cb.sc_private = si;
1014
1015         if ( rc == LDAP_SUCCESS && si->si_syncUUID_ndn.bv_val )
1016         {
1017                 char *subseq_ptr;
1018
1019                 if ( syncstate != LDAP_SYNC_DELETE ) {
1020                         op->o_no_psearch = 1;
1021                 }
1022
1023                 ber_dupbv( &op->o_sync_csn, syncCookie_req->ctxcsn );
1024                 subseq_ptr = strstr( op->o_sync_csn.bv_val, "#0000" );
1025                 subseq_ptr += 4;
1026                 *subseq_ptr = '1';
1027                 
1028                 op->o_req_dn = si->si_syncUUID_ndn;
1029                 op->o_req_ndn = si->si_syncUUID_ndn;
1030                 op->o_tag = LDAP_REQ_DELETE;
1031                 rc = be->be_delete( op, &rs );
1032                 op->o_no_psearch = 0;
1033         }
1034
1035         switch ( syncstate ) {
1036         case LDAP_SYNC_ADD:
1037         case LDAP_SYNC_MODIFY:
1038                 if ( rc == LDAP_SUCCESS ||
1039                          rc == LDAP_REFERRAL ||
1040                          rc == LDAP_NO_SUCH_OBJECT )
1041                 {
1042                         attr_delete( &e->e_attrs, slap_schema.si_ad_entryUUID );
1043                         attr_merge_one( e, slap_schema.si_ad_entryUUID,
1044                                 syncUUID, &ava.aa_value );
1045
1046                         op->o_tag = LDAP_REQ_ADD;
1047                         op->ora_e = e;
1048                         op->o_req_dn = e->e_name;
1049                         op->o_req_ndn = e->e_nname;
1050                         rc = be->be_add( op, &rs );
1051
1052                         if ( rc != LDAP_SUCCESS ) {
1053                                 if ( rc == LDAP_ALREADY_EXISTS ) {      
1054                                         op->o_tag = LDAP_REQ_MODIFY;
1055                                         op->orm_modlist = modlist;
1056                                         op->o_req_dn = e->e_name;
1057                                         op->o_req_ndn = e->e_nname;
1058                                         rc = be->be_modify( op, &rs );
1059                                         if ( rc != LDAP_SUCCESS ) {
1060 #ifdef NEW_LOGGING
1061                                                 LDAP_LOG( OPERATION, ERR,
1062                                                         "syncrepl_entry : be_modify failed (%d)\n",
1063                                                         rc, 0, 0 );
1064 #else
1065                                                 Debug( LDAP_DEBUG_ANY,
1066                                                         "syncrepl_entry : be_modify failed (%d)\n",
1067                                                         rc, 0, 0 );
1068 #endif
1069                                         }
1070                                         ret = 1;
1071                                         goto done;
1072                                 } else if ( rc == LDAP_REFERRAL || rc == LDAP_NO_SUCH_OBJECT ) {
1073                                         syncrepl_add_glue( op, e );
1074                                         ret = 0;
1075                                         goto done;
1076                                 } else {
1077 #ifdef NEW_LOGGING
1078                                         LDAP_LOG( OPERATION, ERR,
1079                                                 "syncrepl_entry : be_add failed (%d)\n",
1080                                                 rc, 0, 0 );
1081 #else
1082                                         Debug( LDAP_DEBUG_ANY,
1083                                                 "syncrepl_entry : be_add failed (%d)\n",
1084                                                 rc, 0, 0 );
1085 #endif
1086                                         ret = 1;
1087                                         goto done;
1088                                 }
1089                         } else {
1090                                 be_entry_release_w( op, e );
1091                                 ret = 0;
1092                                 goto done;
1093                         }
1094                 } else {
1095 #ifdef NEW_LOGGING
1096                         LDAP_LOG( OPERATION, ERR,
1097                                 "syncrepl_entry : be_search failed (%d)\n", rc, 0, 0 );
1098 #else
1099                         Debug( LDAP_DEBUG_ANY,
1100                                 "syncrepl_entry : be_search failed (%d)\n", rc, 0, 0 );
1101 #endif
1102                         ret = 1;
1103                         goto done;
1104                 }
1105
1106         case LDAP_SYNC_DELETE :
1107                 /* Already deleted */
1108                 ret = 1;
1109                 goto done;
1110
1111         default :
1112 #ifdef NEW_LOGGING
1113                 LDAP_LOG( OPERATION, ERR,
1114                         "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1115 #else
1116                 Debug( LDAP_DEBUG_ANY,
1117                         "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1118 #endif
1119                 ret = 1;
1120                 goto done;
1121         }
1122
1123 done :
1124
1125         if ( ava.aa_value.bv_val ) {
1126                 ber_memfree_x( ava.aa_value.bv_val, op->o_tmpmemctx );
1127         }
1128         if ( si->si_syncUUID_ndn.bv_val ) {
1129                 ber_memfree_x( si->si_syncUUID_ndn.bv_val, op->o_tmpmemctx );
1130         }
1131         return ret;
1132 }
1133
1134 static void
1135 syncrepl_del_nonpresent(
1136         Operation *op,
1137         syncinfo_t *si
1138 )
1139 {
1140         Backend* be = op->o_bd;
1141         slap_callback   cb;
1142         SlapReply       rs = {REP_RESULT};
1143         struct nonpresent_entry *np_list, *np_prev;
1144
1145         op->o_req_dn = si->si_base;
1146         op->o_req_ndn = si->si_base;
1147
1148         cb.sc_response = nonpresent_callback;
1149         cb.sc_private = si;
1150
1151         op->o_callback = &cb;
1152         op->o_tag = LDAP_REQ_SEARCH;
1153         op->ors_scope = si->si_scope;
1154         op->ors_deref = LDAP_DEREF_NEVER;
1155         op->ors_slimit = 0;
1156         op->ors_tlimit = 0;
1157         op->ors_attrsonly = 0;
1158         op->ors_attrs = NULL;
1159         op->ors_filter = str2filter_x( op, si->si_filterstr.bv_val );
1160         op->ors_filterstr = si->si_filterstr;
1161
1162         op->o_nocaching = 1;
1163         be->be_search( op, &rs );
1164         op->o_nocaching = 0;
1165
1166         if ( op->ors_filter ) filter_free_x( op, op->ors_filter );
1167
1168         if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
1169                 np_list = LDAP_LIST_FIRST( &si->si_nonpresentlist );
1170                 while ( np_list != NULL ) {
1171                         LDAP_LIST_REMOVE( np_list, npe_link );
1172                         np_prev = np_list;
1173                         np_list = LDAP_LIST_NEXT( np_list, npe_link );
1174                         op->o_tag = LDAP_REQ_DELETE;
1175                         op->o_callback = &cb;
1176                         cb.sc_response = null_callback;
1177                         cb.sc_private = si;
1178                         op->o_req_dn = *np_prev->npe_name;
1179                         op->o_req_ndn = *np_prev->npe_nname;
1180                         op->o_bd->be_delete( op, &rs );
1181                         ber_bvfree( np_prev->npe_name );
1182                         ber_bvfree( np_prev->npe_nname );
1183                         op->o_req_dn.bv_val = NULL;
1184                         op->o_req_ndn.bv_val = NULL;
1185                         ch_free( np_prev );
1186                 }
1187         }
1188
1189         return;
1190 }
1191
1192
1193 static struct berval gcbva[] = {
1194         BER_BVC("top"),
1195         BER_BVC("glue")
1196 };
1197
1198 void
1199 syncrepl_add_glue(
1200         Operation* op,
1201         Entry *e
1202 )
1203 {
1204         Backend *be = op->o_bd;
1205         slap_callback cb;
1206         Attribute       *a;
1207         int     rc;
1208         int suffrdns;
1209         int i;
1210         struct berval dn = {0, NULL};
1211         struct berval ndn = {0, NULL};
1212         Entry   *glue;
1213         SlapReply       rs = {REP_RESULT};
1214         char    *ptr, *comma;
1215
1216         op->o_tag = LDAP_REQ_ADD;
1217         op->o_callback = &cb;
1218         cb.sc_response = null_callback;
1219         cb.sc_private = NULL;
1220
1221         dn = e->e_name;
1222         ndn = e->e_nname;
1223
1224         /* count RDNs in suffix */
1225         if ( be->be_nsuffix[0].bv_len ) {
1226                 for (i=0, ptr=be->be_nsuffix[0].bv_val; ptr; ptr=strchr( ptr, ',' )) {
1227                         ptr++;
1228                         i++;
1229                 }
1230                 suffrdns = i;
1231         } else {
1232                 /* suffix is "" */
1233                 suffrdns = 0;
1234         }
1235
1236         /* Start with BE suffix */
1237         for ( i = 0, ptr = NULL; i < suffrdns; i++ ) {
1238                 comma = strrchr(dn.bv_val, ',');
1239                 if ( ptr ) *ptr = ',';
1240                 if ( comma ) *comma = '\0';
1241                 ptr = comma;
1242         }
1243         if ( ptr ) {
1244                 *ptr++ = ',';
1245                 dn.bv_len -= ptr - dn.bv_val;
1246                 dn.bv_val = ptr;
1247         }
1248         /* the normalizedDNs are always the same length, no counting
1249          * required.
1250          */
1251         if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) {
1252                 ndn.bv_val += ndn.bv_len - be->be_nsuffix[0].bv_len;
1253                 ndn.bv_len = be->be_nsuffix[0].bv_len;
1254         }
1255
1256         while ( ndn.bv_val > e->e_nname.bv_val ) {
1257                 glue = (Entry *) ch_calloc( 1, sizeof(Entry) );
1258                 ber_dupbv( &glue->e_name, &dn );
1259                 ber_dupbv( &glue->e_nname, &ndn );
1260
1261                 a = ch_calloc( 1, sizeof( Attribute ));
1262                 a->a_desc = slap_schema.si_ad_objectClass;
1263
1264                 a->a_vals = ch_calloc( 3, sizeof( struct berval ));
1265                 ber_dupbv( &a->a_vals[0], &gcbva[0] );
1266                 ber_dupbv( &a->a_vals[1], &gcbva[1] );
1267                 a->a_vals[2].bv_len = 0;
1268                 a->a_vals[2].bv_val = NULL;
1269
1270                 a->a_nvals = a->a_vals;
1271
1272                 a->a_next = glue->e_attrs;
1273                 glue->e_attrs = a;
1274
1275                 a = ch_calloc( 1, sizeof( Attribute ));
1276                 a->a_desc = slap_schema.si_ad_structuralObjectClass;
1277
1278                 a->a_vals = ch_calloc( 2, sizeof( struct berval ));
1279                 ber_dupbv( &a->a_vals[0], &gcbva[1] );
1280                 a->a_vals[1].bv_len = 0;
1281                 a->a_vals[1].bv_val = NULL;
1282
1283                 a->a_nvals = a->a_vals;
1284
1285                 a->a_next = glue->e_attrs;
1286                 glue->e_attrs = a;
1287
1288                 op->o_req_dn = glue->e_name;
1289                 op->o_req_ndn = glue->e_nname;
1290                 op->ora_e = glue;
1291                 rc = be->be_add ( op, &rs );
1292                 if ( rc == LDAP_SUCCESS ) {
1293                         be_entry_release_w( op, glue );
1294                 } else {
1295                 /* incl. ALREADY EXIST */
1296                         entry_free( glue );
1297                 }
1298
1299                 /* Move to next child */
1300                 for (ptr = dn.bv_val-2; ptr > e->e_name.bv_val && *ptr != ','; ptr--) {
1301                         /* empty */
1302                 }
1303                 if ( ptr == e->e_name.bv_val ) break;
1304                 dn.bv_val = ++ptr;
1305                 dn.bv_len = e->e_name.bv_len - (ptr-e->e_name.bv_val);
1306                 for( ptr = ndn.bv_val-2;
1307                         ptr > e->e_nname.bv_val && *ptr != ',';
1308                         ptr--)
1309                 {
1310                         /* empty */
1311                 }
1312                 ndn.bv_val = ++ptr;
1313                 ndn.bv_len = e->e_nname.bv_len - (ptr-e->e_nname.bv_val);
1314         }
1315
1316         op->o_req_dn = e->e_name;
1317         op->o_req_ndn = e->e_nname;
1318         op->ora_e = e;
1319         rc = be->be_add ( op, &rs );
1320         if ( rc == LDAP_SUCCESS ) {
1321                 be_entry_release_w( op, e );
1322         } else {
1323                 entry_free( e );
1324         }
1325
1326         return;
1327 }
1328
1329 static struct berval ocbva[] = {
1330         BER_BVC("top"),
1331         BER_BVC("subentry"),
1332         BER_BVC("syncConsumerSubentry"),
1333         BER_BVNULL
1334 };
1335
1336 static struct berval cnbva[] = {
1337         BER_BVNULL,
1338         BER_BVNULL
1339 };
1340
1341 static struct berval ssbva[] = {
1342         BER_BVC("{}"),
1343         BER_BVNULL
1344 };
1345
1346 static struct berval scbva[] = {
1347         BER_BVNULL,
1348         BER_BVNULL
1349 };
1350
1351 void
1352 syncrepl_updateCookie(
1353         syncinfo_t *si,
1354         Operation *op,
1355         struct berval *pdn,
1356         struct sync_cookie *syncCookie
1357 )
1358 {
1359         Backend *be = op->o_bd;
1360         Modifications *ml;
1361         Modifications *mlnext;
1362         Modifications *mod;
1363         Modifications *modlist = NULL;
1364         Modifications **modtail = &modlist;
1365
1366         const char      *text;
1367         char txtbuf[SLAP_TEXT_BUFLEN];
1368         size_t textlen = sizeof txtbuf;
1369
1370         Entry* e = NULL;
1371         int rc;
1372
1373         char syncrepl_cbuf[sizeof(CN_STR SYNCREPL_STR)];
1374         struct berval slap_syncrepl_dn_bv = BER_BVNULL;
1375         struct berval slap_syncrepl_cn_bv = BER_BVNULL;
1376         
1377         slap_callback cb;
1378         SlapReply       rs = {REP_RESULT};
1379
1380         slap_sync_cookie_free( &si->si_syncCookie, 0 );
1381         slap_dup_sync_cookie( &si->si_syncCookie, syncCookie );
1382
1383         mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1384         mod->sml_op = LDAP_MOD_REPLACE;
1385         mod->sml_desc = slap_schema.si_ad_objectClass;
1386         mod->sml_type = mod->sml_desc->ad_cname;
1387         mod->sml_bvalues = ocbva;
1388         *modtail = mod;
1389         modtail = &mod->sml_next;
1390
1391         ber_dupbv( &cnbva[0], (struct berval *) &slap_syncrepl_bvc );
1392         assert( si->si_id < 1000 );
1393         cnbva[0].bv_len = snprintf( cnbva[0].bv_val,
1394                 slap_syncrepl_bvc.bv_len,
1395                 "syncrepl%d", si->si_id );
1396         mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1397         mod->sml_op = LDAP_MOD_REPLACE;
1398         mod->sml_desc = slap_schema.si_ad_cn;
1399         mod->sml_type = mod->sml_desc->ad_cname;
1400         mod->sml_bvalues = cnbva;
1401         *modtail = mod;
1402         modtail = &mod->sml_next;
1403
1404         if ( scbva[0].bv_val ) ch_free( scbva[0].bv_val );
1405         ber_dupbv( &scbva[0], &si->si_syncCookie.octet_str[0] );
1406         mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1407         mod->sml_op = LDAP_MOD_REPLACE;
1408         mod->sml_desc = slap_schema.si_ad_syncreplCookie;
1409         mod->sml_type = mod->sml_desc->ad_cname;
1410         mod->sml_bvalues = scbva;
1411         *modtail = mod;
1412         modtail = &mod->sml_next;
1413
1414         mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1415         mod->sml_op = LDAP_MOD_REPLACE;
1416         mod->sml_desc = slap_schema.si_ad_subtreeSpecification;
1417         mod->sml_type = mod->sml_desc->ad_cname;
1418         mod->sml_bvalues = ssbva;
1419         *modtail = mod;
1420         modtail = &mod->sml_next;
1421
1422         mlnext = mod;
1423
1424         op->o_tag = LDAP_REQ_ADD;
1425         rc = slap_mods_opattrs( op, modlist, modtail,
1426                                                          &text,txtbuf, textlen );
1427
1428         for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
1429                 ml->sml_op = LDAP_MOD_REPLACE;
1430         }
1431
1432         if( rc != LDAP_SUCCESS ) {
1433 #ifdef NEW_LOGGING
1434                 LDAP_LOG( OPERATION, ERR,
1435                         "syncrepl_updateCookie: mods opattrs (%s)\n", text, 0, 0 );
1436 #else
1437                 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods opattrs (%s)\n",
1438                          text, 0, 0 );
1439 #endif
1440         }
1441
1442         e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1443
1444         slap_syncrepl_cn_bv.bv_val = syncrepl_cbuf;
1445         assert( si->si_id < 1000 );
1446         slap_syncrepl_cn_bv.bv_len = snprintf( slap_syncrepl_cn_bv.bv_val,
1447                 slap_syncrepl_cn_bvc.bv_len,
1448                 "cn=syncrepl%d", si->si_id );
1449
1450         build_new_dn( &slap_syncrepl_dn_bv, pdn, &slap_syncrepl_cn_bv,
1451                 op->o_tmpmemctx );
1452         ber_dupbv( &e->e_name, &slap_syncrepl_dn_bv );
1453         ber_dupbv( &e->e_nname, &slap_syncrepl_dn_bv );
1454
1455         if ( slap_syncrepl_dn_bv.bv_val ) {
1456                 sl_free( slap_syncrepl_dn_bv.bv_val, op->o_tmpmemctx );
1457         }
1458
1459         e->e_attrs = NULL;
1460
1461         rc = slap_mods2entry( modlist, &e, 1, 1, &text, txtbuf, textlen );
1462
1463         if( rc != LDAP_SUCCESS ) {
1464 #ifdef NEW_LOGGING
1465                 LDAP_LOG( OPERATION, ERR,
1466                         "syncrepl_updateCookie: mods2entry (%s)\n", text, 0, 0 );
1467 #else
1468                 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods2entry (%s)\n",
1469                          text, 0, 0 );
1470 #endif
1471         }
1472
1473         cb.sc_response = null_callback;
1474         cb.sc_private = si;
1475
1476         op->o_callback = &cb;
1477         op->o_req_dn = e->e_name;
1478         op->o_req_ndn = e->e_nname;
1479
1480         /* update persistent cookie */
1481 update_cookie_retry:
1482         op->o_tag = LDAP_REQ_MODIFY;
1483         op->orm_modlist = modlist;
1484         rc = be->be_modify( op, &rs );
1485
1486         if ( rc != LDAP_SUCCESS ) {
1487                 if ( rc == LDAP_REFERRAL ||
1488                          rc == LDAP_NO_SUCH_OBJECT ) {
1489                         op->o_tag = LDAP_REQ_ADD;
1490                         op->ora_e = e;
1491                         rc = be->be_add( op, &rs );
1492                         if ( rc != LDAP_SUCCESS ) {
1493                                 if ( rc == LDAP_ALREADY_EXISTS ) {
1494                                         goto update_cookie_retry;
1495                                 } else if ( rc == LDAP_REFERRAL ||
1496                                                         rc == LDAP_NO_SUCH_OBJECT ) {
1497 #ifdef NEW_LOGGING
1498                                         LDAP_LOG( OPERATION, ERR,
1499                                                 "cookie will be non-persistent\n",
1500                                                 0, 0, 0 );
1501 #else
1502                                         Debug( LDAP_DEBUG_ANY,
1503                                                 "cookie will be non-persistent\n",
1504                                                 0, 0, 0 );
1505 #endif
1506                                 } else {
1507 #ifdef NEW_LOGGING
1508                                         LDAP_LOG( OPERATION, ERR,
1509                                                 "be_add failed (%d)\n",
1510                                                 rc, 0, 0 );
1511 #else
1512                                         Debug( LDAP_DEBUG_ANY,
1513                                                 "be_add failed (%d)\n",
1514                                                 rc, 0, 0 );
1515 #endif
1516                                 }
1517                         } else {
1518                                 be_entry_release_w( op, e );
1519                                 goto done;
1520                         }
1521                 } else {
1522 #ifdef NEW_LOGGING
1523                         LDAP_LOG( OPERATION, ERR,
1524                                 "be_modify failed (%d)\n", rc, 0, 0 );
1525 #else
1526                         Debug( LDAP_DEBUG_ANY,
1527                                 "be_modify failed (%d)\n", rc, 0, 0 );
1528 #endif
1529                 }
1530         }
1531
1532         if ( e != NULL ) {
1533                 entry_free( e );
1534         }
1535
1536 done :
1537
1538         if ( cnbva[0].bv_val ) {
1539                 ch_free( cnbva[0].bv_val );
1540                 cnbva[0].bv_val = NULL;
1541         }
1542         if ( scbva[0].bv_val ) {
1543                 ch_free( scbva[0].bv_val );
1544                 scbva[0].bv_val = NULL;
1545         }
1546
1547         if ( mlnext->sml_next ) {
1548                 slap_mods_free( mlnext->sml_next );
1549                 mlnext->sml_next = NULL;
1550         }
1551
1552         for (ml = modlist ; ml != NULL; ml = mlnext ) {
1553                 mlnext = ml->sml_next;
1554                 free( ml );
1555         }
1556
1557         return;
1558 }
1559
1560 void
1561 avl_ber_bvfree( void *bv )
1562 {
1563         if( bv == NULL ) {
1564                 return;
1565         }
1566         if ( ((struct berval *)bv)->bv_val != NULL ) {
1567                 ch_free ( ((struct berval *)bv)->bv_val );
1568         }
1569         ch_free ( (char *) bv );
1570 }
1571
1572 static int
1573 dn_callback(
1574         Operation*      op,
1575         SlapReply*      rs
1576 )
1577 {
1578         syncinfo_t *si = op->o_callback->sc_private;
1579
1580         if ( rs->sr_type == REP_SEARCH ) {
1581                 if ( si->si_syncUUID_ndn.bv_val != NULL ) {
1582 #ifdef NEW_LOGGING
1583                         LDAP_LOG( OPERATION, ERR,
1584                                 "dn_callback : multiple entries match dn\n", 0, 0, 0 );
1585 #else
1586                         Debug( LDAP_DEBUG_ANY,
1587                                 "dn_callback : multiple entries match dn\n", 0, 0, 0 );
1588 #endif
1589                 } else {
1590                         ber_dupbv_x( &si->si_syncUUID_ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx );
1591                 }
1592         }
1593
1594         return LDAP_SUCCESS;
1595 }
1596
1597 static int
1598 nonpresent_callback(
1599         Operation*      op,
1600         SlapReply*      rs
1601 )
1602 {
1603         syncinfo_t *si = op->o_callback->sc_private;
1604         Attribute *a;
1605         int count = 0;
1606         struct berval* present_uuid = NULL;
1607         struct nonpresent_entry *np_entry;
1608
1609         if ( rs->sr_type == REP_RESULT ) {
1610                 count = avl_free( si->si_presentlist, avl_ber_bvfree );
1611                 si->si_presentlist = NULL;
1612
1613         } else if ( rs->sr_type == REP_SEARCH ) {
1614                 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
1615
1616                 if ( a == NULL ) return 0;
1617
1618                 present_uuid = avl_find( si->si_presentlist, &a->a_vals[0],
1619                         syncuuid_cmp );
1620
1621                 if ( present_uuid == NULL ) {
1622                         np_entry = (struct nonpresent_entry *)
1623                                 ch_calloc( 1, sizeof( struct nonpresent_entry ));
1624                         np_entry->npe_name = ber_dupbv( NULL, &rs->sr_entry->e_name );
1625                         np_entry->npe_nname = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1626                         LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link );
1627
1628                 } else {
1629                         avl_delete( &si->si_presentlist,
1630                                         &a->a_vals[0], syncuuid_cmp );
1631                         ch_free( present_uuid->bv_val );
1632                         ch_free( present_uuid );
1633                 }
1634         }
1635         return LDAP_SUCCESS;
1636 }
1637
1638 static int
1639 null_callback(
1640         Operation*      op,
1641         SlapReply*      rs
1642 )
1643 {
1644         if ( rs->sr_err != LDAP_SUCCESS &&
1645                 rs->sr_err != LDAP_REFERRAL &&
1646                 rs->sr_err != LDAP_ALREADY_EXISTS &&
1647                 rs->sr_err != LDAP_NO_SUCH_OBJECT )
1648         {
1649 #ifdef NEW_LOGGING
1650                 LDAP_LOG( OPERATION, ERR,
1651                         "null_callback : error code 0x%x\n",
1652                         rs->sr_err, 0, 0 );
1653 #else
1654                 Debug( LDAP_DEBUG_ANY,
1655                         "null_callback : error code 0x%x\n",
1656                         rs->sr_err, 0, 0 );
1657 #endif
1658         }
1659         return LDAP_SUCCESS;
1660 }
1661
1662 Entry *
1663 slap_create_syncrepl_entry(
1664         Backend *be,
1665         struct berval *context_csn,
1666         struct berval *rdn,
1667         struct berval *cn
1668 )
1669 {
1670         Entry* e;
1671
1672         struct berval bv;
1673
1674         e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1675
1676         attr_merge( e, slap_schema.si_ad_objectClass, ocbva, NULL );
1677
1678         attr_merge_one( e, slap_schema.si_ad_structuralObjectClass,
1679                 &ocbva[1], NULL );
1680
1681         attr_merge_one( e, slap_schema.si_ad_cn, cn, NULL );
1682
1683         if ( context_csn ) {
1684                 attr_merge_one( e, slap_schema.si_ad_syncreplCookie,
1685                         context_csn, NULL );
1686         }
1687
1688         bv.bv_val = "{}";
1689         bv.bv_len = sizeof("{}")-1;
1690         attr_merge_one( e, slap_schema.si_ad_subtreeSpecification, &bv, NULL );
1691
1692         build_new_dn( &e->e_name, &be->be_nsuffix[0], rdn, NULL );
1693         ber_dupbv( &e->e_nname, &e->e_name );
1694
1695         return e;
1696 }