3 * Replication Engine which uses the LDAP Sync protocol
5 /* Copyright (c) 2003 by International Business Machines, Inc.
7 * International Business Machines, Inc. (hereinafter called IBM) grants
8 * permission under its copyrights to use, copy, modify, and distribute this
9 * Software with or without fee, provided that the above copyright notice and
10 * all paragraphs of this notice appear in all copies, and that the name of IBM
11 * not be used in connection with the marketing of any product incorporating
12 * the Software or modifications thereof, without specific, written prior
15 * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
17 * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
18 * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
19 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
20 * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
22 /* Modified by Howard Chu
24 * Copyright (c) 2003 by Howard Chu, Symas Corporation
26 * Modifications provided under the terms of the OpenLDAP public license.
33 #include <ac/string.h>
34 #include <ac/socket.h>
39 #include "lutil_ldap.h"
47 #define SYNCREPL_STR "syncreplxxx"
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);
54 syncrepl_del_nonpresent( LDAP *, Operation *, syncinfo_t * );
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 * );
61 static AttributeDescription *sync_descs[4];
63 struct runqueue_s syncrepl_rq;
66 init_syncrepl(syncinfo_t *si)
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;
78 for ( n = 0; si->attrs[ n ] != NULL; n++ ) ;
81 /* Delete Attributes */
82 for ( i = 0; sync_descs[i] != NULL; i++ ) {
83 for ( j = 0; si->attrs[j] != NULL; j++ ) {
84 if ( !strcmp( si->attrs[j], sync_descs[i]->ad_cname.bv_val )) {
85 ch_free( si->attrs[j] );
86 for ( k = j; si->attrs[k] != NULL; k++ ) {
87 si->attrs[k] = si->attrs[k+1];
92 for ( n = 0; si->attrs[ n ] != NULL; n++ );
93 tmp = ( char ** ) ch_realloc( si->attrs, ( n + 4 ) * sizeof( char * ));
96 LDAP_LOG( OPERATION, ERR, "out of memory\n", 0,0,0 );
98 Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
102 tmp = ( char ** ) ch_realloc( si->attrs, 5 * sizeof( char * ));
105 LDAP_LOG( OPERATION, ERR, "out of memory\n", 0,0,0 );
107 Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
110 tmp[ n++ ] = ch_strdup( "*" );
117 for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
118 si->attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
119 si->attrs[ n ] = NULL;
130 BerElementBuffer berbuf;
131 BerElement *ber = (BerElement *)&berbuf;
132 LDAPControl c[2], *ctrls[3];
133 struct timeval timeout;
136 /* setup LDAP SYNC control */
137 ber_init2( ber, NULL, LBER_USE_DER );
138 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &ctx );
140 if ( si->syncCookie ) {
141 ber_printf( ber, "{eO}", abs(si->type), si->syncCookie );
143 ber_printf( ber, "{e}", abs(si->type) );
146 if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 )) == LBER_ERROR ) {
151 c[0].ldctl_oid = LDAP_CONTROL_SYNC;
152 c[0].ldctl_iscritical = si->type < 0;
156 c[1].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
157 ber_str2bv( si->authzId, 0, 0, &c[1].ldctl_value );
158 c[1].ldctl_iscritical = 1;
165 timeout.tv_sec = si->tlimit > 0 ? si->tlimit : 1;
168 rc = ldap_search_ext( ld, si->base.bv_val, si->scope, si->filterstr.bv_val,
169 si->attrs, si->attrsonly, ctrls, NULL,
170 si->tlimit < 0 ? NULL : &timeout,
171 si->slimit, msgidp );
177 static const Listener dummy_list = { {0, ""}, {0, ""} };
184 struct re_s* rtask = arg;
185 syncinfo_t *si = ( syncinfo_t * ) rtask->arg;
188 LDAPControl **rctrls = NULL;
189 LDAPControl *rctrlp = NULL;
191 BerElement *res_ber = NULL;
194 LDAPMessage *res = NULL;
195 LDAPMessage *msg = NULL;
200 struct berval *retdata = NULL;
202 int sync_info_arrived = 0;
206 struct berval syncUUID = { 0, NULL };
207 struct berval syncCookie = { 0, NULL };
208 struct berval syncCookie_req = { 0, NULL };
213 int syncinfo_arrived = 0;
215 Connection conn = {0};
224 struct berval psub = { 0, NULL };
225 Modifications *modlist = NULL;
227 char syncrepl_cbuf[sizeof(CN_STR SYNCREPL_STR)];
228 struct berval syncrepl_cn_bv = {sizeof(syncrepl_cbuf)-1, syncrepl_cbuf};
233 struct timeval *tout_p = NULL;
234 struct timeval tout = { 10, 0 };
237 LDAP_LOG ( OPERATION, DETAIL1, "do_syncrepl\n", 0, 0, 0 );
239 Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl\n", 0, 0, 0 );
245 if ( abs(si->type) != LDAP_SYNC_REFRESH_ONLY &&
246 abs(si->type) != LDAP_SYNC_REFRESH_AND_PERSIST ) {
250 si->sync_mode = LDAP_SYNC_STATE_MODE;
252 /* Init connection to master */
254 rc = ldap_initialize( &ld, si->provideruri );
255 if ( rc != LDAP_SUCCESS ) {
257 LDAP_LOG( OPERATION, ERR,
258 "do_syncrepl: ldap_initialize failed (%s)\n",
259 si->provideruri, 0, 0 );
261 Debug( LDAP_DEBUG_ANY,
262 "do_syncrepl: ldap_initialize failed (%s)\n",
263 si->provideruri, 0, 0 );
268 op.o_protocol = LDAP_VERSION3;
269 ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &op.o_protocol );
274 rc = ldap_start_tls_s( ld, NULL, NULL );
275 if( rc != LDAP_SUCCESS ) {
277 LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
278 "%s: ldap_start_tls failed (%d)\n",
279 si->tls == TLS_CRITICAL ? "Error" : "Warning",
282 Debug( LDAP_DEBUG_ANY,
283 "%s: ldap_start_tls failed (%d)\n",
284 si->tls == TLS_CRITICAL ? "Error" : "Warning",
287 if( si->tls == TLS_CRITICAL )
292 if ( si->bindmethod == LDAP_AUTH_SASL ) {
293 #ifdef HAVE_CYRUS_SASL
296 if ( si->secprops != NULL ) {
297 int err = ldap_set_option( ld,
298 LDAP_OPT_X_SASL_SECPROPS, si->secprops);
300 if( err != LDAP_OPT_SUCCESS ) {
302 LDAP_LOG ( OPERATION, ERR, "do_bind: Error: "
303 "ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
304 si->provideruri, si->secprops, 0 );
306 Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
307 "(%s,SECPROPS,\"%s\") failed!\n",
308 si->provideruri, si->secprops, NULL );
314 defaults = lutil_sasl_defaults( ld,
321 rc = ldap_sasl_interactive_bind_s( ld,
329 lutil_sasl_freedefs( defaults );
331 /* FIXME : different error behaviors according to
333 2) on err policy : exit, retry, backoff ...
335 if ( rc != LDAP_SUCCESS ) {
337 LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
338 "ldap_sasl_interactive_bind_s failed (%d)\n",
341 Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
342 "ldap_sasl_interactive_bind_s failed (%d)\n",
347 #else /* HAVE_CYRUS_SASL */
348 fprintf( stderr, "not compiled with SASL support\n" );
352 rc = ldap_bind_s( ld, si->binddn, si->passwd, si->bindmethod );
353 if ( rc != LDAP_SUCCESS ) {
355 LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
356 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
358 Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
359 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
365 /* set thread context in syncinfo */
372 conn.c_send_ldap_result = slap_send_ldap_result;
373 conn.c_send_search_entry = slap_send_search_entry;
374 conn.c_send_search_reference = slap_send_search_reference;
375 conn.c_listener = (Listener *)&dummy_list;
376 conn.c_peer_name = slap_empty_bv;
378 /* set memory context */
379 #define SLAB_SIZE 1048576
381 memctx = sl_mem_create( memsiz, ctx );
382 op.o_tmpmemctx = memctx;
383 op.o_tmpmfuncs = &sl_mfuncs;
385 op.o_dn = si->updatedn;
386 op.o_ndn = si->updatedn;
388 op.o_time = slap_get_time();
389 op.o_threadctx = si->ctx;
390 op.o_managedsait = 1;
393 op.o_connid = op.o_conn->c_connid;
394 #if defined( LDAP_SLAPI )
395 op.o_pb = slapi_pblock_new();
396 slapi_x_create_object_extensions( SLAPI_X_EXT_OPERATION, &op );
397 #endif /* defined( LDAP_SLAPI ) */
399 /* get syncrepl cookie of shadow replica from subentry */
401 snprintf(syncrepl_cbuf, sizeof(syncrepl_cbuf), CN_STR "syncrepl%d",
403 build_new_dn( &op.o_req_ndn, &si->base, &syncrepl_cn_bv, op.o_tmpmemctx );
404 op.o_req_dn = op.o_req_ndn;
406 si->syncCookie = NULL;
407 backend_attribute( &op, NULL, &op.o_req_ndn,
408 slap_schema.si_ad_syncreplCookie, &si->syncCookie );
410 ber_dupbv( &syncCookie_req, si->syncCookie );
412 psub = be->be_nsuffix[0];
414 rc = ldap_sync_search( si, ld, memctx, &msgid );
415 if( rc != LDAP_SUCCESS ) {
417 LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
418 "ldap_search_ext: %s (%d)\n", ldap_err2string( rc ), rc, 0 );
420 Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
421 "ldap_search_ext: %s (%d)\n", ldap_err2string( rc ), rc, 0 );
426 if ( abs(si->type) == LDAP_SYNC_REFRESH_AND_PERSIST ){
432 while (( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, tout_p, &res )) >= 0 ) {
434 if ( slapd_abrupt_shutdown ) {
441 for ( msg = ldap_first_message( ld, res );
443 msg = ldap_next_message( ld, msg ) )
445 syncCookie.bv_len = 0; syncCookie.bv_val = NULL;
446 switch( ldap_msgtype( msg ) ) {
447 case LDAP_RES_SEARCH_ENTRY:
448 entry = syncrepl_message_to_entry( si, ld, &op, msg,
449 &modlist, &syncstate, &syncUUID, &syncCookie );
450 rc_efree = syncrepl_entry( si, ld, &op, entry, modlist,
451 syncstate, &syncUUID, &syncCookie, !syncinfo_arrived );
452 if ( syncCookie.bv_len ) {
453 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie );
456 slap_mods_free( modlist );
463 case LDAP_RES_SEARCH_REFERENCE:
465 LDAP_LOG( OPERATION, ERR,
466 "do_syncrepl : reference received\n", 0, 0, 0 );
468 Debug( LDAP_DEBUG_ANY,
469 "do_syncrepl : reference received\n", 0, 0, 0 );
473 case LDAP_RES_SEARCH_RESULT:
474 ldap_parse_result( ld, msg, &err, NULL, NULL, NULL, &rctrls, 0 );
476 BerElementBuffer berbuf;
477 BerElement *ctrl_ber;
479 ctrl_ber = (BerElement *)&berbuf;
480 ber_init2( ctrl_ber, &rctrlp->ldctl_value, LBER_USE_DER );
482 ber_scanf( ctrl_ber, "{" /*"}"*/);
483 if ( ber_peek_tag( ctrl_ber, &len )
484 == LDAP_SYNC_TAG_COOKIE ) {
485 ber_scanf( ctrl_ber, "o", &syncCookie );
487 ldap_controls_free( rctrls );
489 value_match( &match, slap_schema.si_ad_entryCSN,
490 slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
491 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
492 &syncCookie_req, &syncCookie, &text );
493 if (si->type == LDAP_SYNC_REFRESH_AND_PERSIST) {
494 /* FIXME : different error behaviors according to
495 1) err code : LDAP_BUSY ...
496 2) on err policy : stop service, stop sync, retry
498 if ( syncCookie.bv_len && match < 0) {
499 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie );
503 /* FIXME : different error behaviors according to
504 1) err code : LDAP_BUSY ...
505 2) on err policy : stop service, stop sync, retry
507 if ( syncCookie.bv_len && match < 0 ) {
508 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie);
510 if ( si->sync_mode == LDAP_SYNC_STATE_MODE && match < 0 ) {
511 syncrepl_del_nonpresent( ld, &op, si );
517 case LDAP_RES_INTERMEDIATE:
518 rc = ldap_parse_intermediate( ld, msg,
519 &retoid, &retdata, NULL, 0 );
520 if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
521 sync_info_arrived = 1;
522 res_ber = ber_init( retdata );
523 ber_scanf( res_ber, "{e" /*"}"*/, &syncstate );
525 if ( ber_peek_tag( res_ber, &len )
526 == LDAP_SYNC_TAG_COOKIE ) {
527 ber_scanf( res_ber, /*"{"*/ "o}", &syncCookie );
529 if ( syncstate == LDAP_SYNC_NEW_COOKIE ) {
531 LDAP_LOG( OPERATION, ERR,
532 "do_syncrepl : cookie required\n", 0, 0, 0 );
534 Debug( LDAP_DEBUG_ANY,
535 "do_syncrepl : cookie required\n", 0, 0, 0 );
540 value_match( &match, slap_schema.si_ad_entryCSN,
541 slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
542 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
543 &syncCookie_req, &syncCookie, &text );
545 if ( syncCookie.bv_len && match < 0 ) {
546 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie);
549 if ( syncstate == LDAP_SYNC_STATE_MODE_DONE ) {
551 syncrepl_del_nonpresent( ld, &op, si );
553 si->sync_mode = LDAP_SYNC_LOG_MODE;
554 } else if ( syncstate == LDAP_SYNC_LOG_MODE_DONE ) {
555 si->sync_mode = LDAP_SYNC_PERSIST_MODE;
556 } else if ( syncstate == LDAP_SYNC_REFRESH_DONE ) {
557 si->sync_mode = LDAP_SYNC_PERSIST_MODE;
558 } else if ( syncstate != LDAP_SYNC_NEW_COOKIE ||
559 syncstate != LDAP_SYNC_LOG_MODE_DONE ) {
561 LDAP_LOG( OPERATION, ERR,
562 "do_syncrepl : unknown sync info\n", 0, 0, 0 );
564 Debug( LDAP_DEBUG_ANY,
565 "do_syncrepl : unknown sync info\n", 0, 0, 0 );
569 ldap_memfree( retoid );
570 ber_bvfree( retdata );
571 ber_free( res_ber, 1 );
575 LDAP_LOG( OPERATION, ERR,"do_syncrepl :"
576 " unknown intermediate "
577 "response\n", 0, 0, 0 );
579 Debug( LDAP_DEBUG_ANY, "do_syncrepl : "
580 "unknown intermediate response (%d)\n",
583 ldap_memfree( retoid );
584 ber_bvfree( retdata );
590 LDAP_LOG( OPERATION, ERR, "do_syncrepl : "
591 "unknown message\n", 0, 0, 0 );
593 Debug( LDAP_DEBUG_ANY, "do_syncrepl : "
594 "unknown message\n", 0, 0, 0 );
599 if ( syncCookie.bv_val ) {
600 ch_free( syncCookie.bv_val );
601 syncCookie.bv_val = NULL;
603 if ( syncUUID.bv_val ) {
604 ch_free( syncUUID.bv_val );
605 syncUUID.bv_val = NULL;
615 ldap_get_option( ld, LDAP_OPT_ERROR_NUMBER, &errno );
616 errstr = ldap_err2string( errno );
619 LDAP_LOG( OPERATION, ERR,
620 "do_syncrepl : %s\n", errstr, 0, 0 );
622 Debug( LDAP_DEBUG_ANY,
623 "do_syncrepl : %s\n", errstr, 0, 0 );
628 #if defined( LDAP_SLAPI )
629 if ( op.o_pb ) slapi_pblock_destroy( op.o_pb );
630 slapi_x_free_object_extensions( SLAPI_X_EXT_OPERATION, &op );
631 #endif /* defined( LDAP_SLAPI ) */
633 if ( syncCookie.bv_val )
634 ch_free( syncCookie.bv_val );
635 if ( syncCookie_req.bv_val )
636 ch_free( syncCookie_req.bv_val );
637 if ( syncUUID.bv_val )
638 ch_free( syncUUID.bv_val );
645 ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
646 ldap_pvt_runqueue_stoptask( &syncrepl_rq, rtask );
647 if ( si->type == LDAP_SYNC_REFRESH_ONLY ) {
648 ldap_pvt_runqueue_resched( &syncrepl_rq, rtask );
650 ldap_pvt_runqueue_remove( &syncrepl_rq, rtask );
652 ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
658 syncrepl_message_to_entry(
663 Modifications **modlist,
665 struct berval *syncUUID,
666 struct berval *syncCookie
670 BerElement *ber = NULL;
673 Modifications **modtail = modlist;
676 char txtbuf[SLAP_TEXT_BUFLEN];
677 size_t textlen = sizeof txtbuf;
679 struct berval bdn = {0, NULL};
684 LDAPControl** rctrls = NULL;
688 if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
690 LDAP_LOG( OPERATION, ERR,
691 "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
693 Debug( LDAP_DEBUG_ANY,
694 "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
699 op->o_tag = LDAP_REQ_ADD;
701 rc = ldap_get_entry_controls( ld, msg, &rctrls );
702 if ( rc != LDAP_SUCCESS ) {
704 LDAP_LOG( OPERATION, ERR,
705 "syncrepl_message_to_entry : control get failed (%d)", rc, 0, 0 );
707 Debug( LDAP_DEBUG_ANY,
708 "syncrepl_message_to_entry : control get failed (%d)", rc, 0, 0 );
713 rc = ldap_get_dn_ber( ld, msg, &ber, &bdn );
715 if ( rc != LDAP_SUCCESS ) {
717 LDAP_LOG( OPERATION, ERR,
718 "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
720 Debug( LDAP_DEBUG_ANY,
721 "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
726 e = ( Entry * ) sl_calloc( 1, sizeof( Entry ), op->o_tmpmemctx);
727 dnPrettyNormal( NULL, &bdn, &e->e_name, &e->e_nname, op->o_tmpmemctx );
729 while ( ber_remaining( ber ) ) {
730 if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) ==
731 LBER_ERROR ) || ( tmp.sml_type.bv_val == NULL )) break;
733 mod = (Modifications *) ch_malloc( sizeof( Modifications ));
735 mod->sml_op = LDAP_MOD_REPLACE;
736 mod->sml_next = NULL;
737 mod->sml_desc = NULL;
738 mod->sml_type = tmp.sml_type;
739 mod->sml_bvalues = tmp.sml_bvalues;
740 mod->sml_nvalues = NULL;
743 modtail = &mod->sml_next;
747 BerElementBuffer berbuf;
748 BerElement *ctrl_ber;
751 ctrl_ber = (BerElement *)&berbuf;
752 ber_init2( ctrl_ber, &rctrlp->ldctl_value, LBER_USE_DER );
753 ber_scanf( ctrl_ber, "{eo", syncstate, syncUUID );
754 if ( ber_peek_tag( ctrl_ber, &len ) == LDAP_SYNC_TAG_COOKIE ) {
755 ber_scanf( ctrl_ber, "o}", syncCookie );
757 ldap_controls_free( rctrls );
760 LDAP_LOG( OPERATION, ERR,"syncrepl_message_to_entry : "
761 " rctrls absent\n", 0, 0, 0 );
763 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry :"
764 " rctrls absent\n", 0, 0, 0 );
768 if ( *syncstate == LDAP_SYNC_PRESENT || *syncstate == LDAP_SYNC_DELETE ) {
773 if ( *modlist == NULL ) {
775 LDAP_LOG( OPERATION, ERR,
776 "syncrepl_message_to_entry: no attributes\n", 0, 0, 0 );
778 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: no attributes\n",
783 rc = slap_mods_check( *modlist, 1, &text, txtbuf, textlen, NULL );
785 if ( rc != LDAP_SUCCESS ) {
787 LDAP_LOG( OPERATION, ERR,
788 "syncrepl_message_to_entry: mods check (%s)\n", text, 0, 0 );
790 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods check (%s)\n",
796 rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
797 if( rc != LDAP_SUCCESS ) {
799 LDAP_LOG( OPERATION, ERR,
800 "syncrepl_message_to_entry: mods2entry (%s)\n", text, 0, 0 );
802 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods2entry (%s)\n",
809 if ( rc != LDAP_SUCCESS ) {
818 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
820 const struct berval *uuid1 = v_uuid1;
821 const struct berval *uuid2 = v_uuid2;
822 int rc = uuid1->bv_len - uuid2->bv_len;
824 return ( strcmp( uuid1->bv_val, uuid2->bv_val ) );
833 Modifications* modlist,
835 struct berval* syncUUID,
836 struct berval* syncCookie,
840 Backend *be = op->o_bd;
842 struct berval *syncuuid_bv = NULL;
844 SlapReply rs = {REP_RESULT};
845 int rc = LDAP_SUCCESS;
848 ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD )) {
849 syncuuid_bv = ber_dupbv( NULL, syncUUID );
850 avl_insert( &si->presentlist, (caddr_t) syncuuid_bv,
851 syncuuid_cmp, avl_dup_error );
854 if ( syncstate == LDAP_SYNC_PRESENT ) {
862 op->ors_filterstr.bv_len = strlen("entryUUID=") + syncUUID->bv_len;
863 op->ors_filterstr.bv_val = (char *) sl_malloc( op->ors_filterstr.bv_len + 1,
865 strcpy( op->ors_filterstr.bv_val, "entryUUID=" );
866 strcat( op->ors_filterstr.bv_val, syncUUID->bv_val );
869 si->syncUUID_ndn = NULL;
871 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
872 op->ors_scope = LDAP_SCOPE_SUBTREE;
874 /* get syncrepl cookie of shadow replica from subentry */
875 op->o_req_dn = si->base;
876 op->o_req_ndn = si->base;
878 /* set callback function */
879 op->o_callback = &cb;
880 cb.sc_response = dn_callback;
883 si->syncUUID_ndn = NULL;
885 rc = be->be_search( op, &rs );
887 if ( op->ors_filter )
888 filter_free_x( op, op->ors_filter );
889 if ( op->ors_filterstr.bv_val )
890 sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
892 cb.sc_response = null_callback;
895 if ( rc == LDAP_SUCCESS && si->syncUUID_ndn && si->sync_mode != LDAP_SYNC_LOG_MODE ) {
896 op->o_req_dn = *si->syncUUID_ndn;
897 op->o_req_ndn = *si->syncUUID_ndn;
898 op->o_tag = LDAP_REQ_DELETE;
899 rc = be->be_delete( op, &rs );
902 if ( si->syncUUID_ndn ) {
903 ber_bvfree( si->syncUUID_ndn );
906 switch ( syncstate ) {
908 case LDAP_SYNC_MODIFY :
910 if ( rc == LDAP_SUCCESS ||
911 rc == LDAP_REFERRAL ||
912 rc == LDAP_NO_SUCH_OBJECT ) {
914 attr_delete( &e->e_attrs, slap_schema.si_ad_entryUUID );
915 attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID, syncUUID, op->o_tmpmemctx );
917 op->o_tag = LDAP_REQ_ADD;
919 op->o_req_dn = e->e_name;
920 op->o_req_ndn = e->e_nname;
921 rc = be->be_add( op, &rs );
923 if ( rc != LDAP_SUCCESS ) {
924 if ( rc == LDAP_ALREADY_EXISTS ) {
925 op->o_tag = LDAP_REQ_MODIFY;
926 op->orm_modlist = modlist;
927 op->o_req_dn = e->e_name;
928 op->o_req_ndn = e->e_nname;
929 rc = be->be_modify( op, &rs );
931 if ( rc != LDAP_SUCCESS ) {
933 LDAP_LOG( OPERATION, ERR,
934 "syncrepl_entry : be_modify failed (%d)\n",
937 Debug( LDAP_DEBUG_ANY,
938 "syncrepl_entry : be_modify failed (%d)\n",
943 } else if ( rc == LDAP_REFERRAL ||
944 rc == LDAP_NO_SUCH_OBJECT ) {
945 syncrepl_add_glue( si, ld, op, e,
947 syncUUID, syncCookie);
952 LDAP_LOG( OPERATION, ERR,
953 "syncrepl_entry : be_add failed (%d)\n",
956 Debug( LDAP_DEBUG_ANY,
957 "syncrepl_entry : be_add failed (%d)\n",
965 be_entry_release_w( op, e );
970 LDAP_LOG( OPERATION, ERR,
971 "syncrepl_entry : be_search failed (%d)\n", rc, 0, 0 );
973 Debug( LDAP_DEBUG_ANY,
974 "syncrepl_entry : be_search failed (%d)\n", rc, 0, 0 );
980 case LDAP_SYNC_DELETE :
981 if ( si->sync_mode == LDAP_SYNC_LOG_MODE ) {
982 op->o_req_dn = *si->syncUUID_ndn;
983 op->o_req_ndn = *si->syncUUID_ndn;
984 op->o_tag = LDAP_REQ_DELETE;
985 rc = be->be_delete( op, &rs );
987 /* Already deleted otherwise */
992 LDAP_LOG( OPERATION, ERR,
993 "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
995 Debug( LDAP_DEBUG_ANY,
996 "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1003 syncrepl_del_nonpresent(
1009 Backend* be = op->o_bd;
1011 SlapReply rs = {REP_RESULT};
1012 struct nonpresent_entry *np_list, *np_prev;
1014 op->o_req_dn = si->base;
1015 op->o_req_ndn = si->base;
1017 cb.sc_response = nonpresent_callback;
1020 op->o_callback = &cb;
1021 op->o_tag = LDAP_REQ_SEARCH;
1022 op->ors_scope = si->scope;
1023 op->ors_deref = LDAP_DEREF_NEVER;
1026 op->ors_attrsonly = 0;
1027 op->ors_attrs = NULL;
1028 op->ors_filter = str2filter_x( op, si->filterstr.bv_val );
1029 op->ors_filterstr = si->filterstr;
1031 op->o_nocaching = 1;
1032 be->be_search( op, &rs );
1033 op->o_nocaching = 0;
1035 if ( op->ors_filter )
1036 filter_free_x( op, op->ors_filter );
1038 if ( !LDAP_LIST_EMPTY( &si->nonpresentlist ) ) {
1039 np_list = LDAP_LIST_FIRST( &si->nonpresentlist );
1040 while ( np_list != NULL ) {
1041 LDAP_LIST_REMOVE( np_list, np_link );
1043 np_list = LDAP_LIST_NEXT( np_list, np_link );
1044 op->o_tag = LDAP_REQ_DELETE;
1045 op->o_callback = &cb;
1046 cb.sc_response = null_callback;
1048 op->o_req_dn = *np_prev->dn;
1049 op->o_req_ndn = *np_prev->ndn;
1050 op->o_bd->be_delete( op, &rs );
1051 ber_bvfree( np_prev->dn );
1052 ber_bvfree( np_prev->ndn );
1053 op->o_req_dn.bv_val = NULL;
1054 op->o_req_ndn.bv_val = NULL;
1063 static struct berval gcbva[] = {
1074 Modifications* modlist,
1076 struct berval* syncUUID,
1077 struct berval* syncCookie
1080 Backend *be = op->o_bd;
1086 struct berval dn = {0, NULL};
1087 struct berval ndn = {0, NULL};
1089 SlapReply rs = {REP_RESULT};
1092 op->o_tag = LDAP_REQ_ADD;
1093 op->o_callback = &cb;
1094 cb.sc_response = null_callback;
1100 /* count RDNs in suffix */
1101 if ( be->be_nsuffix[0].bv_len ) {
1102 for (i=0, ptr=be->be_nsuffix[0].bv_val; ptr; ptr=strchr( ptr, ',' )) {
1112 /* advance to first child: count RDN separators since the prettyDNs
1113 * may not be exactly the same length
1115 for ( i = 0, ptr = NULL; i < suffrdns; i++ ) {
1116 comma = strrchr(dn.bv_val, ',');
1117 if ( ptr ) *ptr = ',';
1118 if ( comma ) *comma = '\0';
1123 dn.bv_len -= ptr - dn.bv_val;
1126 /* the normalizedDNs are always the same length, no counting
1129 if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) {
1130 comma = ndn.bv_val + ndn.bv_len - be->be_nsuffix[0].bv_len - 1;
1132 ptr = strrchr( ndn.bv_val, ',' ) + 1;
1134 ndn.bv_len -= ptr - ndn.bv_val;
1138 while ( ndn.bv_val > e->e_nname.bv_val ) {
1139 glue = (Entry *) ch_calloc( 1, sizeof(Entry) );
1140 ber_dupbv( &glue->e_name, &dn );
1141 ber_dupbv( &glue->e_nname, &ndn );
1143 a = ch_calloc( 1, sizeof( Attribute ));
1144 a->a_desc = slap_schema.si_ad_objectClass;
1146 a->a_vals = ch_calloc( 3, sizeof( struct berval ));
1147 ber_dupbv( &a->a_vals[0], &gcbva[0] );
1148 ber_dupbv( &a->a_vals[1], &gcbva[1] );
1149 a->a_vals[2].bv_len = 0;
1150 a->a_vals[2].bv_val = NULL;
1152 a->a_nvals = a->a_vals;
1154 a->a_next = glue->e_attrs;
1157 a = ch_calloc( 1, sizeof( Attribute ));
1158 a->a_desc = slap_schema.si_ad_structuralObjectClass;
1160 a->a_vals = ch_calloc( 2, sizeof( struct berval ));
1161 ber_dupbv( &a->a_vals[0], &gcbva[1] );
1162 a->a_vals[1].bv_len = 0;
1163 a->a_vals[1].bv_val = NULL;
1165 a->a_nvals = a->a_vals;
1167 a->a_next = glue->e_attrs;
1170 op->o_req_dn = glue->e_name;
1171 op->o_req_ndn = glue->e_nname;
1173 rc = be->be_add ( op, &rs );
1174 if ( rc == LDAP_SUCCESS ) {
1175 be_entry_release_w( op, glue );
1177 /* incl. ALREADY EXIST */
1181 /* Move to next child */
1182 for (ptr = dn.bv_val-2; ptr > e->e_name.bv_val && *ptr != ','; ptr--);
1183 if ( ptr == e->e_name.bv_val ) break;
1185 dn.bv_len = e->e_name.bv_len - (ptr-e->e_name.bv_val);
1186 for (ptr = ndn.bv_val-2; ptr > e->e_nname.bv_val && *ptr != ','; ptr--);
1188 ndn.bv_len = e->e_nname.bv_len - (ptr-e->e_nname.bv_val);
1191 op->o_req_dn = e->e_name;
1192 op->o_req_ndn = e->e_nname;
1194 rc = be->be_add ( op, &rs );
1195 if ( rc == LDAP_SUCCESS )
1196 be_entry_release_w( op, e );
1203 static struct berval ocbva[] = {
1205 BER_BVC("subentry"),
1206 BER_BVC("syncConsumerSubentry"),
1210 static struct berval cnbva[] = {
1215 static struct berval ssbva[] = {
1220 static struct berval scbva[] = {
1226 syncrepl_updateCookie(
1231 struct berval *syncCookie
1234 Backend *be = op->o_bd;
1236 Modifications *mlnext;
1238 Modifications *modlist = NULL;
1239 Modifications **modtail = &modlist;
1242 char txtbuf[SLAP_TEXT_BUFLEN];
1243 size_t textlen = sizeof txtbuf;
1248 char syncrepl_cbuf[sizeof(CN_STR SYNCREPL_STR)];
1249 struct berval slap_syncrepl_dn_bv = BER_BVNULL;
1250 struct berval slap_syncrepl_cn_bv = BER_BVNULL;
1253 SlapReply rs = {REP_RESULT};
1255 /* update in memory cookie */
1256 if ( si->syncCookie != NULL ) {
1257 ber_bvfree( si->syncCookie );
1259 si->syncCookie = ber_dupbv( NULL, syncCookie );
1260 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1261 mod->sml_op = LDAP_MOD_REPLACE;
1262 mod->sml_desc = slap_schema.si_ad_objectClass;
1263 mod->sml_type = mod->sml_desc->ad_cname;
1264 mod->sml_bvalues = ocbva;
1266 modtail = &mod->sml_next;
1268 ber_dupbv( &cnbva[0], (struct berval *) &slap_syncrepl_bvc );
1269 cnbva[0].bv_len = snprintf( cnbva[0].bv_val,
1270 slap_syncrepl_bvc.bv_len,
1271 "syncrepl%d", si->id );
1272 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1273 mod->sml_op = LDAP_MOD_REPLACE;
1274 mod->sml_desc = slap_schema.si_ad_cn;
1275 mod->sml_type = mod->sml_desc->ad_cname;
1276 mod->sml_bvalues = cnbva;
1278 modtail = &mod->sml_next;
1280 if ( scbva[0].bv_val ) ch_free( scbva[0].bv_val );
1281 ber_dupbv( &scbva[0], si->syncCookie );
1282 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1283 mod->sml_op = LDAP_MOD_REPLACE;
1284 mod->sml_desc = slap_schema.si_ad_syncreplCookie;
1285 mod->sml_type = mod->sml_desc->ad_cname;
1286 mod->sml_bvalues = scbva;
1288 modtail = &mod->sml_next;
1290 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1291 mod->sml_op = LDAP_MOD_REPLACE;
1292 mod->sml_desc = slap_schema.si_ad_subtreeSpecification;
1293 mod->sml_type = mod->sml_desc->ad_cname;
1294 mod->sml_bvalues = ssbva;
1296 modtail = &mod->sml_next;
1300 op->o_tag = LDAP_REQ_ADD;
1301 rc = slap_mods_opattrs( op, modlist, modtail,
1302 &text,txtbuf, textlen );
1304 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
1305 ml->sml_op = LDAP_MOD_REPLACE;
1308 if( rc != LDAP_SUCCESS ) {
1310 LDAP_LOG( OPERATION, ERR,
1311 "syncrepl_updateCookie: mods opattrs (%s)\n", text, 0, 0 );
1313 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods opattrs (%s)\n",
1318 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1320 slap_syncrepl_cn_bv.bv_val = syncrepl_cbuf;
1321 slap_syncrepl_cn_bv.bv_len = snprintf( slap_syncrepl_cn_bv.bv_val,
1322 slap_syncrepl_cn_bvc.bv_len,
1323 "cn=syncrepl%d", si->id );
1325 build_new_dn( &slap_syncrepl_dn_bv, pdn, &slap_syncrepl_cn_bv, op->o_tmpmemctx );
1326 ber_dupbv( &e->e_name, &slap_syncrepl_dn_bv );
1327 ber_dupbv( &e->e_nname, &slap_syncrepl_dn_bv );
1329 if ( slap_syncrepl_dn_bv.bv_val )
1330 sl_free( slap_syncrepl_dn_bv.bv_val, op->o_tmpmemctx );
1334 rc = slap_mods2entry( modlist, &e, 1, 1, &text, txtbuf, textlen );
1336 if( rc != LDAP_SUCCESS ) {
1338 LDAP_LOG( OPERATION, ERR,
1339 "syncrepl_updateCookie: mods2entry (%s)\n", text, 0, 0 );
1341 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods2entry (%s)\n",
1346 cb.sc_response = null_callback;
1349 op->o_callback = &cb;
1350 op->o_req_dn = e->e_name;
1351 op->o_req_ndn = e->e_nname;
1353 /* update persistent cookie */
1354 update_cookie_retry:
1355 op->o_tag = LDAP_REQ_MODIFY;
1356 op->orm_modlist = modlist;
1357 rc = be->be_modify( op, &rs );
1359 if ( rc != LDAP_SUCCESS ) {
1360 if ( rc == LDAP_REFERRAL ||
1361 rc == LDAP_NO_SUCH_OBJECT ) {
1362 op->o_tag = LDAP_REQ_ADD;
1364 rc = be->be_add( op, &rs );
1365 if ( rc != LDAP_SUCCESS ) {
1366 if ( rc == LDAP_ALREADY_EXISTS ) {
1367 goto update_cookie_retry;
1368 } else if ( rc == LDAP_REFERRAL ||
1369 rc == LDAP_NO_SUCH_OBJECT ) {
1371 LDAP_LOG( OPERATION, ERR,
1372 "cookie will be non-persistent\n",
1375 Debug( LDAP_DEBUG_ANY,
1376 "cookie will be non-persistent\n",
1381 LDAP_LOG( OPERATION, ERR,
1382 "be_add failed (%d)\n",
1385 Debug( LDAP_DEBUG_ANY,
1386 "be_add failed (%d)\n",
1391 be_entry_release_w( op, e );
1396 LDAP_LOG( OPERATION, ERR,
1397 "be_modify failed (%d)\n", rc, 0, 0 );
1399 Debug( LDAP_DEBUG_ANY,
1400 "be_modify failed (%d)\n", rc, 0, 0 );
1411 if ( cnbva[0].bv_val ) {
1412 ch_free( cnbva[0].bv_val );
1413 cnbva[0].bv_val = NULL;
1415 if ( scbva[0].bv_val ) {
1416 ch_free( scbva[0].bv_val );
1417 scbva[0].bv_val = NULL;
1420 if ( mlnext->sml_next ) {
1421 slap_mods_free( mlnext->sml_next );
1422 mlnext->sml_next = NULL;
1425 for (ml = modlist ; ml != NULL; ml = mlnext ) {
1426 mlnext = ml->sml_next;
1434 avl_ber_bvfree( void *bv )
1439 if ( ((struct berval *)bv)->bv_val != NULL ) {
1440 ch_free ( ((struct berval *)bv)->bv_val );
1442 ch_free ( (char *) bv );
1451 syncinfo_t *si = op->o_callback->sc_private;
1453 if ( rs->sr_type == REP_SEARCH ) {
1454 if ( si->syncUUID_ndn != NULL ) {
1456 LDAP_LOG( OPERATION, ERR,
1457 "dn_callback : multiple entries match dn\n", 0, 0, 0 );
1459 Debug( LDAP_DEBUG_ANY,
1460 "dn_callback : multiple entries match dn\n", 0, 0, 0 );
1463 if ( rs->sr_entry == NULL ) {
1464 si->syncUUID_ndn = NULL;
1466 si->syncUUID_ndn = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1471 return LDAP_SUCCESS;
1475 nonpresent_callback(
1480 syncinfo_t *si = op->o_callback->sc_private;
1483 struct berval* present_uuid = NULL;
1484 struct nonpresent_entry *np_entry;
1486 if ( rs->sr_type == REP_RESULT ) {
1487 count = avl_free( si->presentlist, avl_ber_bvfree );
1488 si->presentlist = NULL;
1489 return LDAP_SUCCESS;
1490 } else if ( rs->sr_type == REP_SEARCH ) {
1491 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
1496 present_uuid = avl_find( si->presentlist, &a->a_vals[0], syncuuid_cmp );
1498 if ( present_uuid == NULL ) {
1499 np_entry = (struct nonpresent_entry *)
1500 ch_calloc( 1, sizeof( struct nonpresent_entry ));
1501 np_entry->dn = ber_dupbv( NULL, &rs->sr_entry->e_name );
1502 np_entry->ndn = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1503 LDAP_LIST_INSERT_HEAD( &si->nonpresentlist, np_entry, np_link );
1505 avl_delete( &si->presentlist,
1506 &a->a_vals[0], syncuuid_cmp );
1507 ch_free( present_uuid->bv_val );
1508 ch_free( present_uuid );
1510 return LDAP_SUCCESS;
1512 return LDAP_SUCCESS;
1523 if ( rs->sr_err != LDAP_SUCCESS &&
1524 rs->sr_err != LDAP_REFERRAL &&
1525 rs->sr_err != LDAP_ALREADY_EXISTS &&
1526 rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
1528 LDAP_LOG( OPERATION, ERR,
1529 "null_callback : error code 0x%x\n",
1532 Debug( LDAP_DEBUG_ANY,
1533 "null_callback : error code 0x%x\n",
1537 return LDAP_SUCCESS;
1541 slap_create_syncrepl_entry(
1543 struct berval *context_csn,
1552 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1554 attr_merge( e, slap_schema.si_ad_objectClass, ocbva, NULL );
1556 attr_merge_one( e, slap_schema.si_ad_structuralObjectClass, &ocbva[1], NULL );
1558 attr_merge_one( e, slap_schema.si_ad_cn, cn, NULL );
1560 if ( context_csn ) {
1561 attr_merge_one( e, slap_schema.si_ad_syncreplCookie,
1562 context_csn, NULL );
1566 bv.bv_len = sizeof("{}")-1;
1567 attr_merge_one( e, slap_schema.si_ad_subtreeSpecification, &bv, NULL );
1569 build_new_dn( &e->e_name, &be->be_nsuffix[0], rdn, NULL );
1570 ber_dupbv( &e->e_nname, &e->e_name );