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