3 * Replication Engine which uses the LDAP Sync protocol
6 * Copyright 2003 The OpenLDAP Foundation, All Rights Reserved.
7 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
9 /* Copyright (c) 2003 by International Business Machines, Inc.
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
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.
26 /* Modified by Howard Chu
28 * Copyright (c) 2003 by Howard Chu, Symas Corporation
30 * Modifications provided under the terms of the OpenLDAP public license.
37 #include <ac/string.h>
38 #include <ac/socket.h>
43 #include "lutil_ldap.h"
51 #define SYNCREPL_STR "syncreplxxx"
54 static const struct berval slap_syncrepl_bvc = BER_BVC(SYNCREPL_STR);
55 static const struct berval slap_syncrepl_cn_bvc = BER_BVC(CN_STR SYNCREPL_STR);
58 syncrepl_del_nonpresent( LDAP *, Operation *, syncinfo_t * );
60 /* callback functions */
61 static int dn_callback( struct slap_op *, struct slap_rep * );
62 static int nonpresent_callback( struct slap_op *, struct slap_rep * );
63 static int null_callback( struct slap_op *, struct slap_rep * );
65 static AttributeDescription *sync_descs[4];
67 struct runqueue_s syncrepl_rq;
70 init_syncrepl(syncinfo_t *si)
75 if ( !sync_descs[0] ) {
76 sync_descs[0] = slap_schema.si_ad_objectClass;
77 sync_descs[1] = slap_schema.si_ad_structuralObjectClass;
78 sync_descs[2] = slap_schema.si_ad_entryCSN;
82 for ( n = 0; si->si_attrs[ n ] != NULL; n++ ) /* empty */;
85 /* Delete Attributes */
86 for ( i = 0; sync_descs[i] != NULL; i++ ) {
87 for ( j = 0; si->si_attrs[j] != NULL; j++ ) {
88 if ( strcmp( si->si_attrs[j], sync_descs[i]->ad_cname.bv_val )
91 ch_free( si->si_attrs[j] );
92 for ( k = j; si->si_attrs[k] != NULL; k++ ) {
93 si->si_attrs[k] = si->si_attrs[k+1];
98 for ( n = 0; si->si_attrs[ n ] != NULL; n++ ) /* empty */;
99 tmp = ( char ** ) ch_realloc( si->si_attrs, (n + 4)*sizeof( char * ));
102 LDAP_LOG( OPERATION, ERR, "out of memory\n", 0,0,0 );
104 Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
108 tmp = ( char ** ) ch_realloc( si->si_attrs, 5 * sizeof( char * ));
111 LDAP_LOG( OPERATION, ERR, "out of memory\n", 0,0,0 );
113 Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
116 tmp[ n++ ] = ch_strdup( "*" );
123 for ( i = 0; sync_descs[ i ] != NULL; i++ ) {
124 si->si_attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val );
125 si->si_attrs[ n ] = NULL;
136 BerElementBuffer berbuf;
137 BerElement *ber = (BerElement *)&berbuf;
138 LDAPControl c[2], *ctrls[3];
139 struct timeval timeout;
142 /* setup LDAP SYNC control */
143 ber_init2( ber, NULL, LBER_USE_DER );
144 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &ctx );
146 if ( si->si_syncCookie ) {
147 ber_printf( ber, "{eO}", abs(si->si_type), si->si_syncCookie );
149 ber_printf( ber, "{e}", abs(si->si_type) );
152 if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 )) == LBER_ERROR ) {
157 c[0].ldctl_oid = LDAP_CONTROL_SYNC;
158 c[0].ldctl_iscritical = si->si_type < 0;
161 if ( si->si_authzId ) {
162 c[1].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
163 ber_str2bv( si->si_authzId, 0, 0, &c[1].ldctl_value );
164 c[1].ldctl_iscritical = 1;
171 timeout.tv_sec = si->si_tlimit > 0 ? si->si_tlimit : 1;
174 rc = ldap_search_ext( ld, si->si_base.bv_val, si->si_scope,
175 si->si_filterstr.bv_val, si->si_attrs, si->si_attrsonly,
176 ctrls, NULL, si->si_tlimit < 0 ? NULL : &timeout,
177 si->si_slimit, msgidp );
183 static const Listener dummy_list = { {0, ""}, {0, ""} };
190 struct re_s* rtask = arg;
191 syncinfo_t *si = ( syncinfo_t * ) rtask->arg;
194 LDAPControl **rctrls = NULL;
195 LDAPControl *rctrlp = NULL;
197 BerElement *res_ber = NULL;
200 LDAPMessage *res = NULL;
201 LDAPMessage *msg = NULL;
206 struct berval *retdata = NULL;
208 int sync_info_arrived = 0;
212 struct berval syncUUID = { 0, NULL };
213 struct berval syncCookie = { 0, NULL };
214 struct berval syncCookie_req = { 0, NULL };
219 int syncinfo_arrived = 0;
221 Connection conn = {0};
230 struct berval psub = { 0, NULL };
231 Modifications *modlist = NULL;
233 char syncrepl_cbuf[sizeof(CN_STR SYNCREPL_STR)];
234 struct berval syncrepl_cn_bv;
239 struct timeval *tout_p = NULL;
240 struct timeval tout = { 10, 0 };
243 LDAP_LOG ( OPERATION, DETAIL1, "do_syncrepl\n", 0, 0, 0 );
245 Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl\n", 0, 0, 0 );
251 switch( abs( si->si_type )) {
252 case LDAP_SYNC_REFRESH_ONLY:
253 case LDAP_SYNC_REFRESH_AND_PERSIST:
259 si->si_sync_mode = LDAP_SYNC_STATE_MODE;
261 /* Init connection to master */
263 rc = ldap_initialize( &ld, si->si_provideruri );
264 if ( rc != LDAP_SUCCESS ) {
266 LDAP_LOG( OPERATION, ERR,
267 "do_syncrepl: ldap_initialize failed (%s)\n",
268 si->si_provideruri, 0, 0 );
270 Debug( LDAP_DEBUG_ANY,
271 "do_syncrepl: ldap_initialize failed (%s)\n",
272 si->si_provideruri, 0, 0 );
277 op.o_protocol = LDAP_VERSION3;
278 ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &op.o_protocol );
283 rc = ldap_start_tls_s( ld, NULL, NULL );
284 if( rc != LDAP_SUCCESS ) {
286 LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
287 "%s: ldap_start_tls failed (%d)\n",
288 si->si_tls == SYNCINFO_TLS_CRITICAL ? "Error" : "Warning",
291 Debug( LDAP_DEBUG_ANY,
292 "%s: ldap_start_tls failed (%d)\n",
293 si->si_tls == SYNCINFO_TLS_CRITICAL ? "Error" : "Warning",
296 if( si->si_tls == SYNCINFO_TLS_CRITICAL ) goto done;
300 if ( si->si_bindmethod == LDAP_AUTH_SASL ) {
301 #ifdef HAVE_CYRUS_SASL
304 if ( si->si_secprops != NULL ) {
305 int err = ldap_set_option( ld,
306 LDAP_OPT_X_SASL_SECPROPS, si->si_secprops);
308 if( err != LDAP_OPT_SUCCESS ) {
310 LDAP_LOG ( OPERATION, ERR, "do_bind: Error: "
311 "ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
312 si->si_provideruri, si->si_secprops, 0 );
314 Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
315 "(%s,SECPROPS,\"%s\") failed!\n",
316 si->si_provideruri, si->si_secprops, 0 );
322 defaults = lutil_sasl_defaults( ld,
323 si->si_saslmech, si->si_realm,
324 si->si_authcId, si->si_passwd, si->si_authzId );
326 rc = ldap_sasl_interactive_bind_s( ld,
334 lutil_sasl_freedefs( defaults );
336 /* FIXME : different error behaviors according to
338 * 2) on err policy : exit, retry, backoff ...
340 if ( rc != LDAP_SUCCESS ) {
342 LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
343 "ldap_sasl_interactive_bind_s failed (%d)\n",
346 Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
347 "ldap_sasl_interactive_bind_s failed (%d)\n",
352 #else /* HAVE_CYRUS_SASL */
353 /* Should never get here, we trapped this at config time */
354 fprintf( stderr, "not compiled with SASL support\n" );
358 rc = ldap_bind_s( ld, si->si_binddn, si->si_passwd, si->si_bindmethod );
359 if ( rc != LDAP_SUCCESS ) {
361 LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
362 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
364 Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
365 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
371 /* set thread context in syncinfo */
378 conn.c_send_ldap_result = slap_send_ldap_result;
379 conn.c_send_search_entry = slap_send_search_entry;
380 conn.c_send_search_reference = slap_send_search_reference;
381 conn.c_listener = (Listener *)&dummy_list;
382 conn.c_peer_name = slap_empty_bv;
384 /* set memory context */
385 #define SLAB_SIZE 1048576
387 memctx = sl_mem_create( memsiz, ctx );
388 op.o_tmpmemctx = memctx;
389 op.o_tmpmfuncs = &sl_mfuncs;
391 op.o_dn = si->si_updatedn;
392 op.o_ndn = si->si_updatedn;
394 op.o_time = slap_get_time();
395 op.o_threadctx = si->si_ctx;
396 op.o_managedsait = 1;
399 op.o_connid = op.o_conn->c_connid;
400 #if defined( LDAP_SLAPI )
401 op.o_pb = slapi_pblock_new();
402 slapi_x_create_object_extensions( SLAPI_X_EXT_OPERATION, &op );
403 #endif /* defined( LDAP_SLAPI ) */
405 /* get syncrepl cookie of shadow replica from subentry */
407 assert( si->si_id < 1000 );
408 syncrepl_cn_bv.bv_val = syncrepl_cbuf;
409 syncrepl_cn_bv.bv_len = snprintf(syncrepl_cbuf, sizeof(syncrepl_cbuf),
410 CN_STR "syncrepl%d", si->si_id );
411 build_new_dn( &op.o_req_ndn, &si->si_base, &syncrepl_cn_bv,
413 op.o_req_dn = op.o_req_ndn;
415 si->si_syncCookie = NULL;
416 backend_attribute( &op, NULL, &op.o_req_ndn,
417 slap_schema.si_ad_syncreplCookie, &si->si_syncCookie );
419 ber_dupbv( &syncCookie_req, &si->si_syncCookie[0] );
421 psub = be->be_nsuffix[0];
423 rc = ldap_sync_search( si, ld, memctx, &msgid );
424 if( rc != LDAP_SUCCESS ) {
426 LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
427 "ldap_search_ext: %s (%d)\n", ldap_err2string( rc ), rc, 0 );
429 Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
430 "ldap_search_ext: %s (%d)\n", ldap_err2string( rc ), rc, 0 );
435 if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ){
441 while (( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, tout_p, &res ))
445 if ( slapd_abrupt_shutdown ) {
452 for( msg = ldap_first_message( ld, res );
454 msg = ldap_next_message( ld, msg ) )
456 syncCookie.bv_len = 0; syncCookie.bv_val = NULL;
457 switch( ldap_msgtype( msg ) ) {
458 case LDAP_RES_SEARCH_ENTRY:
459 entry = syncrepl_message_to_entry( si, ld, &op, msg,
460 &modlist, &syncstate, &syncUUID, &syncCookie );
461 rc_efree = syncrepl_entry( si, ld, &op, entry, modlist,
462 syncstate, &syncUUID, &syncCookie, !syncinfo_arrived );
463 if ( syncCookie.bv_len ) {
464 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie );
467 slap_mods_free( modlist );
469 if ( rc_efree && entry ) {
474 case LDAP_RES_SEARCH_REFERENCE:
476 LDAP_LOG( OPERATION, ERR,
477 "do_syncrepl : reference received\n", 0, 0, 0 );
479 Debug( LDAP_DEBUG_ANY,
480 "do_syncrepl : reference received\n", 0, 0, 0 );
484 case LDAP_RES_SEARCH_RESULT:
485 ldap_parse_result( ld, msg, &err, NULL, NULL, NULL,
488 BerElementBuffer berbuf;
489 BerElement *ctrl_ber;
491 ctrl_ber = (BerElement *)&berbuf;
492 ber_init2( ctrl_ber, &rctrlp->ldctl_value, LBER_USE_DER );
494 ber_scanf( ctrl_ber, "{" /*"}"*/);
495 if ( ber_peek_tag( ctrl_ber, &len )
496 == LDAP_SYNC_TAG_COOKIE )
498 ber_scanf( ctrl_ber, "o", &syncCookie );
500 ldap_controls_free( rctrls );
502 value_match( &match, slap_schema.si_ad_entryCSN,
503 slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
504 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
505 &syncCookie_req, &syncCookie, &text );
506 if (si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST) {
507 /* FIXME : different error behaviors according to
508 * 1) err code : LDAP_BUSY ...
509 * 2) on err policy : stop service, stop sync, retry
511 if ( syncCookie.bv_len && match < 0) {
512 syncrepl_updateCookie( si, ld, &op,
513 &psub, &syncCookie );
517 /* FIXME : different error behaviors according to
518 * 1) err code : LDAP_BUSY ...
519 * 2) on err policy : stop service, stop sync, retry
521 if ( syncCookie.bv_len && match < 0 ) {
522 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie);
524 if ( si->si_sync_mode == LDAP_SYNC_STATE_MODE && match
527 syncrepl_del_nonpresent( ld, &op, si );
533 case LDAP_RES_INTERMEDIATE:
534 rc = ldap_parse_intermediate( ld, msg,
535 &retoid, &retdata, NULL, 0 );
536 if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
537 sync_info_arrived = 1;
538 res_ber = ber_init( retdata );
539 ber_scanf( res_ber, "{e" /*"}"*/, &syncstate );
541 if ( ber_peek_tag( res_ber, &len )
542 == LDAP_SYNC_TAG_COOKIE ) {
543 ber_scanf( res_ber, /*"{"*/ "o}", &syncCookie );
545 if ( syncstate == LDAP_SYNC_NEW_COOKIE ) {
547 LDAP_LOG( OPERATION, ERR,
548 "do_syncrepl : cookie required\n", 0, 0, 0 );
550 Debug( LDAP_DEBUG_ANY,
551 "do_syncrepl : cookie required\n", 0, 0, 0 );
556 value_match( &match, slap_schema.si_ad_entryCSN,
557 slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
558 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
559 &syncCookie_req, &syncCookie, &text );
561 if ( syncCookie.bv_len && match < 0 ) {
562 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie);
565 if ( syncstate == LDAP_SYNC_STATE_MODE_DONE ) {
567 syncrepl_del_nonpresent( ld, &op, si );
569 si->si_sync_mode = LDAP_SYNC_LOG_MODE;
570 } else if ( syncstate == LDAP_SYNC_LOG_MODE_DONE ) {
571 si->si_sync_mode = LDAP_SYNC_PERSIST_MODE;
572 } else if ( syncstate == LDAP_SYNC_REFRESH_DONE ) {
573 si->si_sync_mode = LDAP_SYNC_PERSIST_MODE;
574 } else if ( syncstate != LDAP_SYNC_NEW_COOKIE ||
575 syncstate != LDAP_SYNC_LOG_MODE_DONE )
578 LDAP_LOG( OPERATION, ERR,
579 "do_syncrepl : unknown sync info\n", 0, 0, 0 );
581 Debug( LDAP_DEBUG_ANY,
582 "do_syncrepl : unknown sync info\n", 0, 0, 0 );
586 ldap_memfree( retoid );
587 ber_bvfree( retdata );
588 ber_free( res_ber, 1 );
592 LDAP_LOG( OPERATION, ERR,"do_syncrepl :"
593 " unknown intermediate "
594 "response\n", 0, 0, 0 );
596 Debug( LDAP_DEBUG_ANY, "do_syncrepl : "
597 "unknown intermediate response (%d)\n",
600 ldap_memfree( retoid );
601 ber_bvfree( retdata );
607 LDAP_LOG( OPERATION, ERR, "do_syncrepl : "
608 "unknown message\n", 0, 0, 0 );
610 Debug( LDAP_DEBUG_ANY, "do_syncrepl : "
611 "unknown message\n", 0, 0, 0 );
616 if ( syncCookie.bv_val ) {
617 ch_free( syncCookie.bv_val );
618 syncCookie.bv_val = NULL;
620 if ( syncUUID.bv_val ) {
621 ch_free( syncUUID.bv_val );
622 syncUUID.bv_val = NULL;
633 ldap_get_option( ld, LDAP_OPT_ERROR_NUMBER, &errno );
634 errstr = ldap_err2string( errno );
637 LDAP_LOG( OPERATION, ERR,
638 "do_syncrepl : %s\n", errstr, 0, 0 );
640 Debug( LDAP_DEBUG_ANY,
641 "do_syncrepl : %s\n", errstr, 0, 0 );
646 #if defined( LDAP_SLAPI )
648 slapi_pblock_destroy( op.o_pb );
649 slapi_x_free_object_extensions( SLAPI_X_EXT_OPERATION, &op );
651 #endif /* defined( LDAP_SLAPI ) */
653 if ( syncCookie.bv_val )
654 ch_free( syncCookie.bv_val );
655 if ( syncCookie_req.bv_val )
656 ch_free( syncCookie_req.bv_val );
657 if ( syncUUID.bv_val )
658 ch_free( syncUUID.bv_val );
660 if ( res ) ldap_msgfree( res );
662 if ( ld ) ldap_unbind( ld );
664 if ( si->si_syncCookie ) {
665 ber_bvarray_free_x( si->si_syncCookie, op.o_tmpmemctx );
666 si->si_syncCookie = NULL;
669 ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
670 ldap_pvt_runqueue_stoptask( &syncrepl_rq, rtask );
671 ldap_pvt_runqueue_resched( &syncrepl_rq, rtask );
672 ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
678 syncrepl_message_to_entry(
683 Modifications **modlist,
685 struct berval *syncUUID,
686 struct berval *syncCookie
690 BerElement *ber = NULL;
693 Modifications **modtail = modlist;
696 char txtbuf[SLAP_TEXT_BUFLEN];
697 size_t textlen = sizeof txtbuf;
699 struct berval bdn = {0, NULL}, dn, ndn;
704 LDAPControl** rctrls = NULL;
708 if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
710 LDAP_LOG( OPERATION, ERR,
711 "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
713 Debug( LDAP_DEBUG_ANY,
714 "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
719 op->o_tag = LDAP_REQ_ADD;
721 rc = ldap_get_entry_controls( ld, msg, &rctrls );
722 if ( rc != LDAP_SUCCESS ) {
724 LDAP_LOG( OPERATION, ERR,
725 "syncrepl_message_to_entry : control get failed (%d)", rc, 0, 0 );
727 Debug( LDAP_DEBUG_ANY,
728 "syncrepl_message_to_entry : control get failed (%d)", rc, 0, 0 );
734 BerElementBuffer berbuf;
735 BerElement *ctrl_ber;
738 ctrl_ber = (BerElement *)&berbuf;
739 ber_init2( ctrl_ber, &rctrlp->ldctl_value, LBER_USE_DER );
740 ber_scanf( ctrl_ber, "{eo", syncstate, syncUUID );
741 if ( ber_peek_tag( ctrl_ber, &len ) == LDAP_SYNC_TAG_COOKIE ) {
742 ber_scanf( ctrl_ber, "o}", syncCookie );
744 ldap_controls_free( rctrls );
747 LDAP_LOG( OPERATION, ERR,"syncrepl_message_to_entry : "
748 " rctrls absent\n", 0, 0, 0 );
750 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry :"
751 " rctrls absent\n", 0, 0, 0 );
755 rc = ldap_get_dn_ber( ld, msg, &ber, &bdn );
757 if ( rc != LDAP_SUCCESS ) {
759 LDAP_LOG( OPERATION, ERR,
760 "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
762 Debug( LDAP_DEBUG_ANY,
763 "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
768 dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
769 ber_dupbv( &op->o_req_dn, &dn );
770 ber_dupbv( &op->o_req_ndn, &ndn );
771 sl_free( ndn.bv_val, op->o_tmpmemctx );
772 sl_free( dn.bv_val, op->o_tmpmemctx );
774 if ( *syncstate == LDAP_SYNC_PRESENT || *syncstate == LDAP_SYNC_DELETE ) {
778 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ) );
779 e->e_name = op->o_req_dn;
780 e->e_nname = op->o_req_ndn;
782 while ( ber_remaining( ber ) ) {
783 if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) ==
784 LBER_ERROR ) || ( tmp.sml_type.bv_val == NULL ))
789 mod = (Modifications *) ch_malloc( sizeof( Modifications ));
791 mod->sml_op = LDAP_MOD_REPLACE;
792 mod->sml_next = NULL;
793 mod->sml_desc = NULL;
794 mod->sml_type = tmp.sml_type;
795 mod->sml_bvalues = tmp.sml_bvalues;
796 mod->sml_nvalues = NULL;
799 modtail = &mod->sml_next;
802 if ( *modlist == NULL ) {
804 LDAP_LOG( OPERATION, ERR,
805 "syncrepl_message_to_entry: no attributes\n", 0, 0, 0 );
807 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: no attributes\n",
812 rc = slap_mods_check( *modlist, 1, &text, txtbuf, textlen, NULL );
814 if ( rc != LDAP_SUCCESS ) {
816 LDAP_LOG( OPERATION, ERR,
817 "syncrepl_message_to_entry: mods check (%s)\n", text, 0, 0 );
819 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods check (%s)\n",
825 rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
826 if( rc != LDAP_SUCCESS ) {
828 LDAP_LOG( OPERATION, ERR,
829 "syncrepl_message_to_entry: mods2entry (%s)\n", text, 0, 0 );
831 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods2entry (%s)\n",
838 if ( rc != LDAP_SUCCESS ) {
847 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
849 const struct berval *uuid1 = v_uuid1;
850 const struct berval *uuid2 = v_uuid2;
851 int rc = uuid1->bv_len - uuid2->bv_len;
853 return ( strcmp( uuid1->bv_val, uuid2->bv_val ) );
862 Modifications* modlist,
864 struct berval* syncUUID,
865 struct berval* syncCookie,
869 Backend *be = op->o_bd;
871 struct berval *syncuuid_bv = NULL;
873 SlapReply rs = {REP_RESULT};
875 AttributeAssertion ava;
876 int rc = LDAP_SUCCESS;
877 int ret = LDAP_SUCCESS;
880 ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ))
882 syncuuid_bv = ber_dupbv( NULL, syncUUID );
883 avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
884 syncuuid_cmp, avl_dup_error );
887 if ( syncstate == LDAP_SYNC_PRESENT ) {
891 op->ors_filterstr.bv_len = (sizeof("entryUUID=")-1) + syncUUID->bv_len;
892 op->ors_filterstr.bv_val = (char *) sl_malloc(
893 op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
894 AC_MEMCPY( op->ors_filterstr.bv_val, "entryUUID=", sizeof("entryUUID=")-1 );
895 AC_MEMCPY( &op->ors_filterstr.bv_val[sizeof("entryUUID=")-1],
896 syncUUID->bv_val, syncUUID->bv_len );
897 op->ors_filterstr.bv_val[op->ors_filterstr.bv_len] = '\0';
900 si->si_syncUUID_ndn = NULL;
902 f.f_choice = LDAP_FILTER_EQUALITY;
904 ava.aa_desc = slap_schema.si_ad_entryUUID;
905 ava.aa_value = *syncUUID;
907 op->ors_scope = LDAP_SCOPE_SUBTREE;
909 /* get syncrepl cookie of shadow replica from subentry */
910 op->o_req_dn = si->si_base;
911 op->o_req_ndn = si->si_base;
913 /* set callback function */
914 op->o_callback = &cb;
915 cb.sc_response = dn_callback;
918 si->si_syncUUID_ndn = NULL;
920 rc = be->be_search( op, &rs );
922 if ( op->ors_filterstr.bv_val ) {
923 sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
926 cb.sc_response = null_callback;
929 if ( rc == LDAP_SUCCESS && si->si_syncUUID_ndn &&
930 si->si_sync_mode != LDAP_SYNC_LOG_MODE )
932 op->o_req_dn = *si->si_syncUUID_ndn;
933 op->o_req_ndn = *si->si_syncUUID_ndn;
934 op->o_tag = LDAP_REQ_DELETE;
935 rc = be->be_delete( op, &rs );
938 switch ( syncstate ) {
940 case LDAP_SYNC_MODIFY:
941 if ( rc == LDAP_SUCCESS ||
942 rc == LDAP_REFERRAL ||
943 rc == LDAP_NO_SUCH_OBJECT )
945 attr_delete( &e->e_attrs, slap_schema.si_ad_entryUUID );
946 attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID,
947 syncUUID, op->o_tmpmemctx );
949 op->o_tag = LDAP_REQ_ADD;
951 op->o_req_dn = e->e_name;
952 op->o_req_ndn = e->e_nname;
953 rc = be->be_add( op, &rs );
955 if ( rc != LDAP_SUCCESS ) {
956 if ( rc == LDAP_ALREADY_EXISTS ) {
957 op->o_tag = LDAP_REQ_MODIFY;
958 op->orm_modlist = modlist;
959 op->o_req_dn = e->e_name;
960 op->o_req_ndn = e->e_nname;
961 rc = be->be_modify( op, &rs );
963 if ( rc != LDAP_SUCCESS ) {
965 LDAP_LOG( OPERATION, ERR,
966 "syncrepl_entry : be_modify failed (%d)\n",
969 Debug( LDAP_DEBUG_ANY,
970 "syncrepl_entry : be_modify failed (%d)\n",
976 } else if ( rc == LDAP_REFERRAL || rc == LDAP_NO_SUCH_OBJECT ) {
977 syncrepl_add_glue( si, ld, op, e,
979 syncUUID, syncCookie);
985 LDAP_LOG( OPERATION, ERR,
986 "syncrepl_entry : be_add failed (%d)\n",
989 Debug( LDAP_DEBUG_ANY,
990 "syncrepl_entry : be_add failed (%d)\n",
999 be_entry_release_w( op, e );
1005 LDAP_LOG( OPERATION, ERR,
1006 "syncrepl_entry : be_search failed (%d)\n", rc, 0, 0 );
1008 Debug( LDAP_DEBUG_ANY,
1009 "syncrepl_entry : be_search failed (%d)\n", rc, 0, 0 );
1016 case LDAP_SYNC_DELETE :
1017 if ( si->si_sync_mode == LDAP_SYNC_LOG_MODE ) {
1018 if ( si->si_syncUUID_ndn ) {
1019 op->o_req_dn = *si->si_syncUUID_ndn;
1020 op->o_req_ndn = *si->si_syncUUID_ndn;
1021 op->o_tag = LDAP_REQ_DELETE;
1022 rc = be->be_delete( op, &rs );
1025 /* Already deleted otherwise */
1031 LDAP_LOG( OPERATION, ERR,
1032 "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1034 Debug( LDAP_DEBUG_ANY,
1035 "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1043 if ( si->si_syncUUID_ndn ) {
1044 ber_bvfree( si->si_syncUUID_ndn );
1050 syncrepl_del_nonpresent(
1056 Backend* be = op->o_bd;
1058 SlapReply rs = {REP_RESULT};
1059 struct nonpresent_entry *np_list, *np_prev;
1061 op->o_req_dn = si->si_base;
1062 op->o_req_ndn = si->si_base;
1064 cb.sc_response = nonpresent_callback;
1067 op->o_callback = &cb;
1068 op->o_tag = LDAP_REQ_SEARCH;
1069 op->ors_scope = si->si_scope;
1070 op->ors_deref = LDAP_DEREF_NEVER;
1073 op->ors_attrsonly = 0;
1074 op->ors_attrs = NULL;
1075 op->ors_filter = str2filter_x( op, si->si_filterstr.bv_val );
1076 op->ors_filterstr = si->si_filterstr;
1078 op->o_nocaching = 1;
1079 be->be_search( op, &rs );
1080 op->o_nocaching = 0;
1082 if ( op->ors_filter ) filter_free_x( op, op->ors_filter );
1084 if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
1085 np_list = LDAP_LIST_FIRST( &si->si_nonpresentlist );
1086 while ( np_list != NULL ) {
1087 LDAP_LIST_REMOVE( np_list, npe_link );
1089 np_list = LDAP_LIST_NEXT( np_list, npe_link );
1090 op->o_tag = LDAP_REQ_DELETE;
1091 op->o_callback = &cb;
1092 cb.sc_response = null_callback;
1094 op->o_req_dn = *np_prev->npe_name;
1095 op->o_req_ndn = *np_prev->npe_nname;
1096 op->o_bd->be_delete( op, &rs );
1097 ber_bvfree( np_prev->npe_name );
1098 ber_bvfree( np_prev->npe_nname );
1099 op->o_req_dn.bv_val = NULL;
1100 op->o_req_ndn.bv_val = NULL;
1109 static struct berval gcbva[] = {
1120 Modifications* modlist,
1122 struct berval* syncUUID,
1123 struct berval* syncCookie
1126 Backend *be = op->o_bd;
1132 struct berval dn = {0, NULL};
1133 struct berval ndn = {0, NULL};
1135 SlapReply rs = {REP_RESULT};
1138 op->o_tag = LDAP_REQ_ADD;
1139 op->o_callback = &cb;
1140 cb.sc_response = null_callback;
1146 /* count RDNs in suffix */
1147 if ( be->be_nsuffix[0].bv_len ) {
1148 for (i=0, ptr=be->be_nsuffix[0].bv_val; ptr; ptr=strchr( ptr, ',' )) {
1158 /* Start with BE suffix */
1159 for ( i = 0, ptr = NULL; i < suffrdns; i++ ) {
1160 comma = strrchr(dn.bv_val, ',');
1161 if ( ptr ) *ptr = ',';
1162 if ( comma ) *comma = '\0';
1167 dn.bv_len -= ptr - dn.bv_val;
1170 /* the normalizedDNs are always the same length, no counting
1173 if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) {
1174 ndn.bv_val += ndn.bv_len - be->be_nsuffix[0].bv_len;
1175 ndn.bv_len = be->be_nsuffix[0].bv_len;
1178 while ( ndn.bv_val > e->e_nname.bv_val ) {
1179 glue = (Entry *) ch_calloc( 1, sizeof(Entry) );
1180 ber_dupbv( &glue->e_name, &dn );
1181 ber_dupbv( &glue->e_nname, &ndn );
1183 a = ch_calloc( 1, sizeof( Attribute ));
1184 a->a_desc = slap_schema.si_ad_objectClass;
1186 a->a_vals = ch_calloc( 3, sizeof( struct berval ));
1187 ber_dupbv( &a->a_vals[0], &gcbva[0] );
1188 ber_dupbv( &a->a_vals[1], &gcbva[1] );
1189 a->a_vals[2].bv_len = 0;
1190 a->a_vals[2].bv_val = NULL;
1192 a->a_nvals = a->a_vals;
1194 a->a_next = glue->e_attrs;
1197 a = ch_calloc( 1, sizeof( Attribute ));
1198 a->a_desc = slap_schema.si_ad_structuralObjectClass;
1200 a->a_vals = ch_calloc( 2, sizeof( struct berval ));
1201 ber_dupbv( &a->a_vals[0], &gcbva[1] );
1202 a->a_vals[1].bv_len = 0;
1203 a->a_vals[1].bv_val = NULL;
1205 a->a_nvals = a->a_vals;
1207 a->a_next = glue->e_attrs;
1210 op->o_req_dn = glue->e_name;
1211 op->o_req_ndn = glue->e_nname;
1213 rc = be->be_add ( op, &rs );
1214 if ( rc == LDAP_SUCCESS ) {
1215 be_entry_release_w( op, glue );
1217 /* incl. ALREADY EXIST */
1221 /* Move to next child */
1222 for (ptr = dn.bv_val-2; ptr > e->e_name.bv_val && *ptr != ','; ptr--) {
1225 if ( ptr == e->e_name.bv_val ) break;
1227 dn.bv_len = e->e_name.bv_len - (ptr-e->e_name.bv_val);
1228 for( ptr = ndn.bv_val-2;
1229 ptr > e->e_nname.bv_val && *ptr != ',';
1235 ndn.bv_len = e->e_nname.bv_len - (ptr-e->e_nname.bv_val);
1238 op->o_req_dn = e->e_name;
1239 op->o_req_ndn = e->e_nname;
1241 rc = be->be_add ( op, &rs );
1242 if ( rc == LDAP_SUCCESS ) {
1243 be_entry_release_w( op, e );
1251 static struct berval ocbva[] = {
1253 BER_BVC("subentry"),
1254 BER_BVC("syncConsumerSubentry"),
1258 static struct berval cnbva[] = {
1263 static struct berval ssbva[] = {
1268 static struct berval scbva[] = {
1274 syncrepl_updateCookie(
1279 struct berval *syncCookie
1282 Backend *be = op->o_bd;
1284 Modifications *mlnext;
1286 Modifications *modlist = NULL;
1287 Modifications **modtail = &modlist;
1290 char txtbuf[SLAP_TEXT_BUFLEN];
1291 size_t textlen = sizeof txtbuf;
1296 char syncrepl_cbuf[sizeof(CN_STR SYNCREPL_STR)];
1297 struct berval slap_syncrepl_dn_bv = BER_BVNULL;
1298 struct berval slap_syncrepl_cn_bv = BER_BVNULL;
1301 SlapReply rs = {REP_RESULT};
1303 struct berval *dup_syncCookie = NULL;
1305 /* update in memory cookie */
1306 ber_bvarray_free_x( si->si_syncCookie, op->o_tmpmemctx );
1307 si->si_syncCookie = NULL;
1309 /* ber_bvarray_add() doesn't have dup option */
1310 dup_syncCookie = ber_dupbv_x( NULL, syncCookie, op->o_tmpmemctx );
1311 ber_bvarray_add_x( &si->si_syncCookie, dup_syncCookie, op->o_tmpmemctx );
1312 op->o_tmpfree( dup_syncCookie, op->o_tmpmemctx );
1314 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1315 mod->sml_op = LDAP_MOD_REPLACE;
1316 mod->sml_desc = slap_schema.si_ad_objectClass;
1317 mod->sml_type = mod->sml_desc->ad_cname;
1318 mod->sml_bvalues = ocbva;
1320 modtail = &mod->sml_next;
1322 ber_dupbv( &cnbva[0], (struct berval *) &slap_syncrepl_bvc );
1323 assert( si->si_id < 1000 );
1324 cnbva[0].bv_len = snprintf( cnbva[0].bv_val,
1325 slap_syncrepl_bvc.bv_len,
1326 "syncrepl%d", si->si_id );
1327 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1328 mod->sml_op = LDAP_MOD_REPLACE;
1329 mod->sml_desc = slap_schema.si_ad_cn;
1330 mod->sml_type = mod->sml_desc->ad_cname;
1331 mod->sml_bvalues = cnbva;
1333 modtail = &mod->sml_next;
1335 if ( scbva[0].bv_val ) ch_free( scbva[0].bv_val );
1336 ber_dupbv( &scbva[0], &si->si_syncCookie[0] );
1337 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1338 mod->sml_op = LDAP_MOD_REPLACE;
1339 mod->sml_desc = slap_schema.si_ad_syncreplCookie;
1340 mod->sml_type = mod->sml_desc->ad_cname;
1341 mod->sml_bvalues = scbva;
1343 modtail = &mod->sml_next;
1345 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1346 mod->sml_op = LDAP_MOD_REPLACE;
1347 mod->sml_desc = slap_schema.si_ad_subtreeSpecification;
1348 mod->sml_type = mod->sml_desc->ad_cname;
1349 mod->sml_bvalues = ssbva;
1351 modtail = &mod->sml_next;
1355 op->o_tag = LDAP_REQ_ADD;
1356 rc = slap_mods_opattrs( op, modlist, modtail,
1357 &text,txtbuf, textlen );
1359 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
1360 ml->sml_op = LDAP_MOD_REPLACE;
1363 if( rc != LDAP_SUCCESS ) {
1365 LDAP_LOG( OPERATION, ERR,
1366 "syncrepl_updateCookie: mods opattrs (%s)\n", text, 0, 0 );
1368 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods opattrs (%s)\n",
1373 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1375 slap_syncrepl_cn_bv.bv_val = syncrepl_cbuf;
1376 assert( si->si_id < 1000 );
1377 slap_syncrepl_cn_bv.bv_len = snprintf( slap_syncrepl_cn_bv.bv_val,
1378 slap_syncrepl_cn_bvc.bv_len,
1379 "cn=syncrepl%d", si->si_id );
1381 build_new_dn( &slap_syncrepl_dn_bv, pdn, &slap_syncrepl_cn_bv,
1383 ber_dupbv( &e->e_name, &slap_syncrepl_dn_bv );
1384 ber_dupbv( &e->e_nname, &slap_syncrepl_dn_bv );
1386 if ( slap_syncrepl_dn_bv.bv_val ) {
1387 sl_free( slap_syncrepl_dn_bv.bv_val, op->o_tmpmemctx );
1392 rc = slap_mods2entry( modlist, &e, 1, 1, &text, txtbuf, textlen );
1394 if( rc != LDAP_SUCCESS ) {
1396 LDAP_LOG( OPERATION, ERR,
1397 "syncrepl_updateCookie: mods2entry (%s)\n", text, 0, 0 );
1399 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods2entry (%s)\n",
1404 cb.sc_response = null_callback;
1407 op->o_callback = &cb;
1408 op->o_req_dn = e->e_name;
1409 op->o_req_ndn = e->e_nname;
1411 /* update persistent cookie */
1412 update_cookie_retry:
1413 op->o_tag = LDAP_REQ_MODIFY;
1414 op->orm_modlist = modlist;
1415 rc = be->be_modify( op, &rs );
1417 if ( rc != LDAP_SUCCESS ) {
1418 if ( rc == LDAP_REFERRAL ||
1419 rc == LDAP_NO_SUCH_OBJECT ) {
1420 op->o_tag = LDAP_REQ_ADD;
1422 rc = be->be_add( op, &rs );
1423 if ( rc != LDAP_SUCCESS ) {
1424 if ( rc == LDAP_ALREADY_EXISTS ) {
1425 goto update_cookie_retry;
1426 } else if ( rc == LDAP_REFERRAL ||
1427 rc == LDAP_NO_SUCH_OBJECT ) {
1429 LDAP_LOG( OPERATION, ERR,
1430 "cookie will be non-persistent\n",
1433 Debug( LDAP_DEBUG_ANY,
1434 "cookie will be non-persistent\n",
1439 LDAP_LOG( OPERATION, ERR,
1440 "be_add failed (%d)\n",
1443 Debug( LDAP_DEBUG_ANY,
1444 "be_add failed (%d)\n",
1449 be_entry_release_w( op, e );
1454 LDAP_LOG( OPERATION, ERR,
1455 "be_modify failed (%d)\n", rc, 0, 0 );
1457 Debug( LDAP_DEBUG_ANY,
1458 "be_modify failed (%d)\n", rc, 0, 0 );
1469 if ( cnbva[0].bv_val ) {
1470 ch_free( cnbva[0].bv_val );
1471 cnbva[0].bv_val = NULL;
1473 if ( scbva[0].bv_val ) {
1474 ch_free( scbva[0].bv_val );
1475 scbva[0].bv_val = NULL;
1478 if ( mlnext->sml_next ) {
1479 slap_mods_free( mlnext->sml_next );
1480 mlnext->sml_next = NULL;
1483 for (ml = modlist ; ml != NULL; ml = mlnext ) {
1484 mlnext = ml->sml_next;
1492 avl_ber_bvfree( void *bv )
1497 if ( ((struct berval *)bv)->bv_val != NULL ) {
1498 ch_free ( ((struct berval *)bv)->bv_val );
1500 ch_free ( (char *) bv );
1509 syncinfo_t *si = op->o_callback->sc_private;
1511 if ( rs->sr_type == REP_SEARCH ) {
1512 if ( si->si_syncUUID_ndn != NULL ) {
1514 LDAP_LOG( OPERATION, ERR,
1515 "dn_callback : multiple entries match dn\n", 0, 0, 0 );
1517 Debug( LDAP_DEBUG_ANY,
1518 "dn_callback : multiple entries match dn\n", 0, 0, 0 );
1521 if ( rs->sr_entry == NULL ) {
1522 si->si_syncUUID_ndn = NULL;
1524 si->si_syncUUID_ndn = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1529 return LDAP_SUCCESS;
1533 nonpresent_callback(
1538 syncinfo_t *si = op->o_callback->sc_private;
1541 struct berval* present_uuid = NULL;
1542 struct nonpresent_entry *np_entry;
1544 if ( rs->sr_type == REP_RESULT ) {
1545 count = avl_free( si->si_presentlist, avl_ber_bvfree );
1546 si->si_presentlist = NULL;
1548 } else if ( rs->sr_type == REP_SEARCH ) {
1549 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
1551 if ( a == NULL ) return 0;
1553 present_uuid = avl_find( si->si_presentlist, &a->a_vals[0],
1556 if ( present_uuid == NULL ) {
1557 np_entry = (struct nonpresent_entry *)
1558 ch_calloc( 1, sizeof( struct nonpresent_entry ));
1559 np_entry->npe_name = ber_dupbv( NULL, &rs->sr_entry->e_name );
1560 np_entry->npe_nname = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1561 LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link );
1564 avl_delete( &si->si_presentlist,
1565 &a->a_vals[0], syncuuid_cmp );
1566 ch_free( present_uuid->bv_val );
1567 ch_free( present_uuid );
1570 return LDAP_SUCCESS;
1579 if ( rs->sr_err != LDAP_SUCCESS &&
1580 rs->sr_err != LDAP_REFERRAL &&
1581 rs->sr_err != LDAP_ALREADY_EXISTS &&
1582 rs->sr_err != LDAP_NO_SUCH_OBJECT )
1585 LDAP_LOG( OPERATION, ERR,
1586 "null_callback : error code 0x%x\n",
1589 Debug( LDAP_DEBUG_ANY,
1590 "null_callback : error code 0x%x\n",
1594 return LDAP_SUCCESS;
1598 slap_create_syncrepl_entry(
1600 struct berval *context_csn,
1609 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1611 attr_merge( e, slap_schema.si_ad_objectClass, ocbva, NULL );
1613 attr_merge_one( e, slap_schema.si_ad_structuralObjectClass,
1616 attr_merge_one( e, slap_schema.si_ad_cn, cn, NULL );
1618 if ( context_csn ) {
1619 attr_merge_one( e, slap_schema.si_ad_syncreplCookie,
1620 context_csn, NULL );
1624 bv.bv_len = sizeof("{}")-1;
1625 attr_merge_one( e, slap_schema.si_ad_subtreeSpecification, &bv, NULL );
1627 build_new_dn( &e->e_name, &be->be_nsuffix[0], rdn, NULL );
1628 ber_dupbv( &e->e_nname, &e->e_name );