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}, dn, ndn;
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 );
714 BerElementBuffer berbuf;
715 BerElement *ctrl_ber;
718 ctrl_ber = (BerElement *)&berbuf;
719 ber_init2( ctrl_ber, &rctrlp->ldctl_value, LBER_USE_DER );
720 ber_scanf( ctrl_ber, "{eo", syncstate, syncUUID );
721 if ( ber_peek_tag( ctrl_ber, &len ) == LDAP_SYNC_TAG_COOKIE ) {
722 ber_scanf( ctrl_ber, "o}", syncCookie );
724 ldap_controls_free( rctrls );
727 LDAP_LOG( OPERATION, ERR,"syncrepl_message_to_entry : "
728 " rctrls absent\n", 0, 0, 0 );
730 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry :"
731 " rctrls absent\n", 0, 0, 0 );
735 rc = ldap_get_dn_ber( ld, msg, &ber, &bdn );
737 if ( rc != LDAP_SUCCESS ) {
739 LDAP_LOG( OPERATION, ERR,
740 "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
742 Debug( LDAP_DEBUG_ANY,
743 "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
748 dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
749 ber_dupbv( &op->o_req_dn, &dn );
750 ber_dupbv( &op->o_req_ndn, &ndn );
751 sl_free( ndn.bv_val, op->o_tmpmemctx );
752 sl_free( dn.bv_val, op->o_tmpmemctx );
754 if ( *syncstate == LDAP_SYNC_PRESENT || *syncstate == LDAP_SYNC_DELETE ) {
758 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ) );
759 e->e_name = op->o_req_dn;
760 e->e_nname = op->o_req_ndn;
762 while ( ber_remaining( ber ) ) {
763 if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) ==
764 LBER_ERROR ) || ( tmp.sml_type.bv_val == NULL )) break;
766 mod = (Modifications *) ch_malloc( sizeof( Modifications ));
768 mod->sml_op = LDAP_MOD_REPLACE;
769 mod->sml_next = NULL;
770 mod->sml_desc = NULL;
771 mod->sml_type = tmp.sml_type;
772 mod->sml_bvalues = tmp.sml_bvalues;
773 mod->sml_nvalues = NULL;
776 modtail = &mod->sml_next;
779 if ( *modlist == NULL ) {
781 LDAP_LOG( OPERATION, ERR,
782 "syncrepl_message_to_entry: no attributes\n", 0, 0, 0 );
784 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: no attributes\n",
789 rc = slap_mods_check( *modlist, 1, &text, txtbuf, textlen, NULL );
791 if ( rc != LDAP_SUCCESS ) {
793 LDAP_LOG( OPERATION, ERR,
794 "syncrepl_message_to_entry: mods check (%s)\n", text, 0, 0 );
796 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods check (%s)\n",
802 rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
803 if( rc != LDAP_SUCCESS ) {
805 LDAP_LOG( OPERATION, ERR,
806 "syncrepl_message_to_entry: mods2entry (%s)\n", text, 0, 0 );
808 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods2entry (%s)\n",
815 if ( rc != LDAP_SUCCESS ) {
824 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
826 const struct berval *uuid1 = v_uuid1;
827 const struct berval *uuid2 = v_uuid2;
828 int rc = uuid1->bv_len - uuid2->bv_len;
830 return ( strcmp( uuid1->bv_val, uuid2->bv_val ) );
839 Modifications* modlist,
841 struct berval* syncUUID,
842 struct berval* syncCookie,
846 Backend *be = op->o_bd;
848 struct berval *syncuuid_bv = NULL;
850 SlapReply rs = {REP_RESULT};
851 int rc = LDAP_SUCCESS;
854 ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD )) {
855 syncuuid_bv = ber_dupbv( NULL, syncUUID );
856 avl_insert( &si->presentlist, (caddr_t) syncuuid_bv,
857 syncuuid_cmp, avl_dup_error );
860 if ( syncstate == LDAP_SYNC_PRESENT ) {
868 op->ors_filterstr.bv_len = strlen("entryUUID=") + syncUUID->bv_len;
869 op->ors_filterstr.bv_val = (char *) sl_malloc( op->ors_filterstr.bv_len + 1,
871 strcpy( op->ors_filterstr.bv_val, "entryUUID=" );
872 strcat( op->ors_filterstr.bv_val, syncUUID->bv_val );
875 si->syncUUID_ndn = NULL;
877 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
878 op->ors_scope = LDAP_SCOPE_SUBTREE;
880 /* get syncrepl cookie of shadow replica from subentry */
881 op->o_req_dn = si->base;
882 op->o_req_ndn = si->base;
884 /* set callback function */
885 op->o_callback = &cb;
886 cb.sc_response = dn_callback;
889 si->syncUUID_ndn = NULL;
891 rc = be->be_search( op, &rs );
893 if ( op->ors_filter )
894 filter_free_x( op, op->ors_filter );
895 if ( op->ors_filterstr.bv_val )
896 sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
898 cb.sc_response = null_callback;
901 if ( rc == LDAP_SUCCESS && si->syncUUID_ndn && si->sync_mode != LDAP_SYNC_LOG_MODE ) {
902 op->o_req_dn = *si->syncUUID_ndn;
903 op->o_req_ndn = *si->syncUUID_ndn;
904 op->o_tag = LDAP_REQ_DELETE;
905 rc = be->be_delete( op, &rs );
908 if ( si->syncUUID_ndn ) {
909 ber_bvfree( si->syncUUID_ndn );
912 switch ( syncstate ) {
914 case LDAP_SYNC_MODIFY :
916 if ( rc == LDAP_SUCCESS ||
917 rc == LDAP_REFERRAL ||
918 rc == LDAP_NO_SUCH_OBJECT ) {
920 attr_delete( &e->e_attrs, slap_schema.si_ad_entryUUID );
921 attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID, syncUUID, op->o_tmpmemctx );
923 op->o_tag = LDAP_REQ_ADD;
925 op->o_req_dn = e->e_name;
926 op->o_req_ndn = e->e_nname;
927 rc = be->be_add( op, &rs );
929 if ( rc != LDAP_SUCCESS ) {
930 if ( rc == LDAP_ALREADY_EXISTS ) {
931 op->o_tag = LDAP_REQ_MODIFY;
932 op->orm_modlist = modlist;
933 op->o_req_dn = e->e_name;
934 op->o_req_ndn = e->e_nname;
935 rc = be->be_modify( op, &rs );
937 if ( rc != LDAP_SUCCESS ) {
939 LDAP_LOG( OPERATION, ERR,
940 "syncrepl_entry : be_modify failed (%d)\n",
943 Debug( LDAP_DEBUG_ANY,
944 "syncrepl_entry : be_modify failed (%d)\n",
949 } else if ( rc == LDAP_REFERRAL ||
950 rc == LDAP_NO_SUCH_OBJECT ) {
951 syncrepl_add_glue( si, ld, op, e,
953 syncUUID, syncCookie);
958 LDAP_LOG( OPERATION, ERR,
959 "syncrepl_entry : be_add failed (%d)\n",
962 Debug( LDAP_DEBUG_ANY,
963 "syncrepl_entry : be_add failed (%d)\n",
971 be_entry_release_w( op, e );
976 LDAP_LOG( OPERATION, ERR,
977 "syncrepl_entry : be_search failed (%d)\n", rc, 0, 0 );
979 Debug( LDAP_DEBUG_ANY,
980 "syncrepl_entry : be_search failed (%d)\n", rc, 0, 0 );
986 case LDAP_SYNC_DELETE :
987 if ( si->sync_mode == LDAP_SYNC_LOG_MODE ) {
988 op->o_req_dn = *si->syncUUID_ndn;
989 op->o_req_ndn = *si->syncUUID_ndn;
990 op->o_tag = LDAP_REQ_DELETE;
991 rc = be->be_delete( op, &rs );
993 /* Already deleted otherwise */
998 LDAP_LOG( OPERATION, ERR,
999 "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1001 Debug( LDAP_DEBUG_ANY,
1002 "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1009 syncrepl_del_nonpresent(
1015 Backend* be = op->o_bd;
1017 SlapReply rs = {REP_RESULT};
1018 struct nonpresent_entry *np_list, *np_prev;
1020 op->o_req_dn = si->base;
1021 op->o_req_ndn = si->base;
1023 cb.sc_response = nonpresent_callback;
1026 op->o_callback = &cb;
1027 op->o_tag = LDAP_REQ_SEARCH;
1028 op->ors_scope = si->scope;
1029 op->ors_deref = LDAP_DEREF_NEVER;
1032 op->ors_attrsonly = 0;
1033 op->ors_attrs = NULL;
1034 op->ors_filter = str2filter_x( op, si->filterstr.bv_val );
1035 op->ors_filterstr = si->filterstr;
1037 op->o_nocaching = 1;
1038 be->be_search( op, &rs );
1039 op->o_nocaching = 0;
1041 if ( op->ors_filter )
1042 filter_free_x( op, op->ors_filter );
1044 if ( !LDAP_LIST_EMPTY( &si->nonpresentlist ) ) {
1045 np_list = LDAP_LIST_FIRST( &si->nonpresentlist );
1046 while ( np_list != NULL ) {
1047 LDAP_LIST_REMOVE( np_list, np_link );
1049 np_list = LDAP_LIST_NEXT( np_list, np_link );
1050 op->o_tag = LDAP_REQ_DELETE;
1051 op->o_callback = &cb;
1052 cb.sc_response = null_callback;
1054 op->o_req_dn = *np_prev->dn;
1055 op->o_req_ndn = *np_prev->ndn;
1056 op->o_bd->be_delete( op, &rs );
1057 ber_bvfree( np_prev->dn );
1058 ber_bvfree( np_prev->ndn );
1059 op->o_req_dn.bv_val = NULL;
1060 op->o_req_ndn.bv_val = NULL;
1069 static struct berval gcbva[] = {
1080 Modifications* modlist,
1082 struct berval* syncUUID,
1083 struct berval* syncCookie
1086 Backend *be = op->o_bd;
1092 struct berval dn = {0, NULL};
1093 struct berval ndn = {0, NULL};
1095 SlapReply rs = {REP_RESULT};
1098 op->o_tag = LDAP_REQ_ADD;
1099 op->o_callback = &cb;
1100 cb.sc_response = null_callback;
1106 /* count RDNs in suffix */
1107 if ( be->be_nsuffix[0].bv_len ) {
1108 for (i=0, ptr=be->be_nsuffix[0].bv_val; ptr; ptr=strchr( ptr, ',' )) {
1118 /* advance to first child: count RDN separators since the prettyDNs
1119 * may not be exactly the same length
1121 for ( i = 0, ptr = NULL; i < suffrdns; i++ ) {
1122 comma = strrchr(dn.bv_val, ',');
1123 if ( ptr ) *ptr = ',';
1124 if ( comma ) *comma = '\0';
1129 dn.bv_len -= ptr - dn.bv_val;
1132 /* the normalizedDNs are always the same length, no counting
1135 if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) {
1136 comma = ndn.bv_val + ndn.bv_len - be->be_nsuffix[0].bv_len - 1;
1138 ptr = strrchr( ndn.bv_val, ',' ) + 1;
1140 ndn.bv_len -= ptr - ndn.bv_val;
1144 while ( ndn.bv_val > e->e_nname.bv_val ) {
1145 glue = (Entry *) ch_calloc( 1, sizeof(Entry) );
1146 ber_dupbv( &glue->e_name, &dn );
1147 ber_dupbv( &glue->e_nname, &ndn );
1149 a = ch_calloc( 1, sizeof( Attribute ));
1150 a->a_desc = slap_schema.si_ad_objectClass;
1152 a->a_vals = ch_calloc( 3, sizeof( struct berval ));
1153 ber_dupbv( &a->a_vals[0], &gcbva[0] );
1154 ber_dupbv( &a->a_vals[1], &gcbva[1] );
1155 a->a_vals[2].bv_len = 0;
1156 a->a_vals[2].bv_val = NULL;
1158 a->a_nvals = a->a_vals;
1160 a->a_next = glue->e_attrs;
1163 a = ch_calloc( 1, sizeof( Attribute ));
1164 a->a_desc = slap_schema.si_ad_structuralObjectClass;
1166 a->a_vals = ch_calloc( 2, sizeof( struct berval ));
1167 ber_dupbv( &a->a_vals[0], &gcbva[1] );
1168 a->a_vals[1].bv_len = 0;
1169 a->a_vals[1].bv_val = NULL;
1171 a->a_nvals = a->a_vals;
1173 a->a_next = glue->e_attrs;
1176 op->o_req_dn = glue->e_name;
1177 op->o_req_ndn = glue->e_nname;
1179 rc = be->be_add ( op, &rs );
1180 if ( rc == LDAP_SUCCESS ) {
1181 be_entry_release_w( op, glue );
1183 /* incl. ALREADY EXIST */
1187 /* Move to next child */
1188 for (ptr = dn.bv_val-2; ptr > e->e_name.bv_val && *ptr != ','; ptr--);
1189 if ( ptr == e->e_name.bv_val ) break;
1191 dn.bv_len = e->e_name.bv_len - (ptr-e->e_name.bv_val);
1192 for (ptr = ndn.bv_val-2; ptr > e->e_nname.bv_val && *ptr != ','; ptr--);
1194 ndn.bv_len = e->e_nname.bv_len - (ptr-e->e_nname.bv_val);
1197 op->o_req_dn = e->e_name;
1198 op->o_req_ndn = e->e_nname;
1200 rc = be->be_add ( op, &rs );
1201 if ( rc == LDAP_SUCCESS )
1202 be_entry_release_w( op, e );
1209 static struct berval ocbva[] = {
1211 BER_BVC("subentry"),
1212 BER_BVC("syncConsumerSubentry"),
1216 static struct berval cnbva[] = {
1221 static struct berval ssbva[] = {
1226 static struct berval scbva[] = {
1232 syncrepl_updateCookie(
1237 struct berval *syncCookie
1240 Backend *be = op->o_bd;
1242 Modifications *mlnext;
1244 Modifications *modlist = NULL;
1245 Modifications **modtail = &modlist;
1248 char txtbuf[SLAP_TEXT_BUFLEN];
1249 size_t textlen = sizeof txtbuf;
1254 char syncrepl_cbuf[sizeof(CN_STR SYNCREPL_STR)];
1255 struct berval slap_syncrepl_dn_bv = BER_BVNULL;
1256 struct berval slap_syncrepl_cn_bv = BER_BVNULL;
1259 SlapReply rs = {REP_RESULT};
1261 /* update in memory cookie */
1262 if ( si->syncCookie != NULL ) {
1263 ber_bvfree( si->syncCookie );
1265 si->syncCookie = ber_dupbv( NULL, syncCookie );
1266 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1267 mod->sml_op = LDAP_MOD_REPLACE;
1268 mod->sml_desc = slap_schema.si_ad_objectClass;
1269 mod->sml_type = mod->sml_desc->ad_cname;
1270 mod->sml_bvalues = ocbva;
1272 modtail = &mod->sml_next;
1274 ber_dupbv( &cnbva[0], (struct berval *) &slap_syncrepl_bvc );
1275 cnbva[0].bv_len = snprintf( cnbva[0].bv_val,
1276 slap_syncrepl_bvc.bv_len,
1277 "syncrepl%d", si->id );
1278 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1279 mod->sml_op = LDAP_MOD_REPLACE;
1280 mod->sml_desc = slap_schema.si_ad_cn;
1281 mod->sml_type = mod->sml_desc->ad_cname;
1282 mod->sml_bvalues = cnbva;
1284 modtail = &mod->sml_next;
1286 if ( scbva[0].bv_val ) ch_free( scbva[0].bv_val );
1287 ber_dupbv( &scbva[0], si->syncCookie );
1288 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1289 mod->sml_op = LDAP_MOD_REPLACE;
1290 mod->sml_desc = slap_schema.si_ad_syncreplCookie;
1291 mod->sml_type = mod->sml_desc->ad_cname;
1292 mod->sml_bvalues = scbva;
1294 modtail = &mod->sml_next;
1296 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1297 mod->sml_op = LDAP_MOD_REPLACE;
1298 mod->sml_desc = slap_schema.si_ad_subtreeSpecification;
1299 mod->sml_type = mod->sml_desc->ad_cname;
1300 mod->sml_bvalues = ssbva;
1302 modtail = &mod->sml_next;
1306 op->o_tag = LDAP_REQ_ADD;
1307 rc = slap_mods_opattrs( op, modlist, modtail,
1308 &text,txtbuf, textlen );
1310 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
1311 ml->sml_op = LDAP_MOD_REPLACE;
1314 if( rc != LDAP_SUCCESS ) {
1316 LDAP_LOG( OPERATION, ERR,
1317 "syncrepl_updateCookie: mods opattrs (%s)\n", text, 0, 0 );
1319 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods opattrs (%s)\n",
1324 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1326 slap_syncrepl_cn_bv.bv_val = syncrepl_cbuf;
1327 slap_syncrepl_cn_bv.bv_len = snprintf( slap_syncrepl_cn_bv.bv_val,
1328 slap_syncrepl_cn_bvc.bv_len,
1329 "cn=syncrepl%d", si->id );
1331 build_new_dn( &slap_syncrepl_dn_bv, pdn, &slap_syncrepl_cn_bv, op->o_tmpmemctx );
1332 ber_dupbv( &e->e_name, &slap_syncrepl_dn_bv );
1333 ber_dupbv( &e->e_nname, &slap_syncrepl_dn_bv );
1335 if ( slap_syncrepl_dn_bv.bv_val )
1336 sl_free( slap_syncrepl_dn_bv.bv_val, op->o_tmpmemctx );
1340 rc = slap_mods2entry( modlist, &e, 1, 1, &text, txtbuf, textlen );
1342 if( rc != LDAP_SUCCESS ) {
1344 LDAP_LOG( OPERATION, ERR,
1345 "syncrepl_updateCookie: mods2entry (%s)\n", text, 0, 0 );
1347 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods2entry (%s)\n",
1352 cb.sc_response = null_callback;
1355 op->o_callback = &cb;
1356 op->o_req_dn = e->e_name;
1357 op->o_req_ndn = e->e_nname;
1359 /* update persistent cookie */
1360 update_cookie_retry:
1361 op->o_tag = LDAP_REQ_MODIFY;
1362 op->orm_modlist = modlist;
1363 rc = be->be_modify( op, &rs );
1365 if ( rc != LDAP_SUCCESS ) {
1366 if ( rc == LDAP_REFERRAL ||
1367 rc == LDAP_NO_SUCH_OBJECT ) {
1368 op->o_tag = LDAP_REQ_ADD;
1370 rc = be->be_add( op, &rs );
1371 if ( rc != LDAP_SUCCESS ) {
1372 if ( rc == LDAP_ALREADY_EXISTS ) {
1373 goto update_cookie_retry;
1374 } else if ( rc == LDAP_REFERRAL ||
1375 rc == LDAP_NO_SUCH_OBJECT ) {
1377 LDAP_LOG( OPERATION, ERR,
1378 "cookie will be non-persistent\n",
1381 Debug( LDAP_DEBUG_ANY,
1382 "cookie will be non-persistent\n",
1387 LDAP_LOG( OPERATION, ERR,
1388 "be_add failed (%d)\n",
1391 Debug( LDAP_DEBUG_ANY,
1392 "be_add failed (%d)\n",
1397 be_entry_release_w( op, e );
1402 LDAP_LOG( OPERATION, ERR,
1403 "be_modify failed (%d)\n", rc, 0, 0 );
1405 Debug( LDAP_DEBUG_ANY,
1406 "be_modify failed (%d)\n", rc, 0, 0 );
1417 if ( cnbva[0].bv_val ) {
1418 ch_free( cnbva[0].bv_val );
1419 cnbva[0].bv_val = NULL;
1421 if ( scbva[0].bv_val ) {
1422 ch_free( scbva[0].bv_val );
1423 scbva[0].bv_val = NULL;
1426 if ( mlnext->sml_next ) {
1427 slap_mods_free( mlnext->sml_next );
1428 mlnext->sml_next = NULL;
1431 for (ml = modlist ; ml != NULL; ml = mlnext ) {
1432 mlnext = ml->sml_next;
1440 avl_ber_bvfree( void *bv )
1445 if ( ((struct berval *)bv)->bv_val != NULL ) {
1446 ch_free ( ((struct berval *)bv)->bv_val );
1448 ch_free ( (char *) bv );
1457 syncinfo_t *si = op->o_callback->sc_private;
1459 if ( rs->sr_type == REP_SEARCH ) {
1460 if ( si->syncUUID_ndn != NULL ) {
1462 LDAP_LOG( OPERATION, ERR,
1463 "dn_callback : multiple entries match dn\n", 0, 0, 0 );
1465 Debug( LDAP_DEBUG_ANY,
1466 "dn_callback : multiple entries match dn\n", 0, 0, 0 );
1469 if ( rs->sr_entry == NULL ) {
1470 si->syncUUID_ndn = NULL;
1472 si->syncUUID_ndn = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1477 return LDAP_SUCCESS;
1481 nonpresent_callback(
1486 syncinfo_t *si = op->o_callback->sc_private;
1489 struct berval* present_uuid = NULL;
1490 struct nonpresent_entry *np_entry;
1492 if ( rs->sr_type == REP_RESULT ) {
1493 count = avl_free( si->presentlist, avl_ber_bvfree );
1494 si->presentlist = NULL;
1495 return LDAP_SUCCESS;
1496 } else if ( rs->sr_type == REP_SEARCH ) {
1497 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
1502 present_uuid = avl_find( si->presentlist, &a->a_vals[0], syncuuid_cmp );
1504 if ( present_uuid == NULL ) {
1505 np_entry = (struct nonpresent_entry *)
1506 ch_calloc( 1, sizeof( struct nonpresent_entry ));
1507 np_entry->dn = ber_dupbv( NULL, &rs->sr_entry->e_name );
1508 np_entry->ndn = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1509 LDAP_LIST_INSERT_HEAD( &si->nonpresentlist, np_entry, np_link );
1511 avl_delete( &si->presentlist,
1512 &a->a_vals[0], syncuuid_cmp );
1513 ch_free( present_uuid->bv_val );
1514 ch_free( present_uuid );
1516 return LDAP_SUCCESS;
1518 return LDAP_SUCCESS;
1529 if ( rs->sr_err != LDAP_SUCCESS &&
1530 rs->sr_err != LDAP_REFERRAL &&
1531 rs->sr_err != LDAP_ALREADY_EXISTS &&
1532 rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
1534 LDAP_LOG( OPERATION, ERR,
1535 "null_callback : error code 0x%x\n",
1538 Debug( LDAP_DEBUG_ANY,
1539 "null_callback : error code 0x%x\n",
1543 return LDAP_SUCCESS;
1547 slap_create_syncrepl_entry(
1549 struct berval *context_csn,
1558 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1560 attr_merge( e, slap_schema.si_ad_objectClass, ocbva, NULL );
1562 attr_merge_one( e, slap_schema.si_ad_structuralObjectClass, &ocbva[1], NULL );
1564 attr_merge_one( e, slap_schema.si_ad_cn, cn, NULL );
1566 if ( context_csn ) {
1567 attr_merge_one( e, slap_schema.si_ad_syncreplCookie,
1568 context_csn, NULL );
1572 bv.bv_len = sizeof("{}")-1;
1573 attr_merge_one( e, slap_schema.si_ad_subtreeSpecification, &bv, NULL );
1575 build_new_dn( &e->e_name, &be->be_nsuffix[0], rdn, NULL );
1576 ber_dupbv( &e->e_nname, &e->e_name );