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 ) return NULL;
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 fprintf( stderr, "not compiled with SASL support\n" );
357 rc = ldap_bind_s( ld, si->si_binddn, si->si_passwd, si->si_bindmethod );
358 if ( rc != LDAP_SUCCESS ) {
360 LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
361 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
363 Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
364 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
370 /* set thread context in syncinfo */
377 conn.c_send_ldap_result = slap_send_ldap_result;
378 conn.c_send_search_entry = slap_send_search_entry;
379 conn.c_send_search_reference = slap_send_search_reference;
380 conn.c_listener = (Listener *)&dummy_list;
381 conn.c_peer_name = slap_empty_bv;
383 /* set memory context */
384 #define SLAB_SIZE 1048576
386 memctx = sl_mem_create( memsiz, ctx );
387 op.o_tmpmemctx = memctx;
388 op.o_tmpmfuncs = &sl_mfuncs;
390 op.o_dn = si->si_updatedn;
391 op.o_ndn = si->si_updatedn;
393 op.o_time = slap_get_time();
394 op.o_threadctx = si->si_ctx;
395 op.o_managedsait = 1;
398 op.o_connid = op.o_conn->c_connid;
399 #if defined( LDAP_SLAPI )
400 op.o_pb = slapi_pblock_new();
401 slapi_x_create_object_extensions( SLAPI_X_EXT_OPERATION, &op );
402 #endif /* defined( LDAP_SLAPI ) */
404 /* get syncrepl cookie of shadow replica from subentry */
406 assert( si->si_id < 1000 );
407 syncrepl_cn_bv.bv_val = syncrepl_cbuf;
408 syncrepl_cn_bv.bv_len = snprintf(syncrepl_cbuf, sizeof(syncrepl_cbuf),
409 CN_STR "syncrepl%d", si->si_id );
410 build_new_dn( &op.o_req_ndn, &si->si_base, &syncrepl_cn_bv,
412 op.o_req_dn = op.o_req_ndn;
414 si->si_syncCookie = NULL;
415 backend_attribute( &op, NULL, &op.o_req_ndn,
416 slap_schema.si_ad_syncreplCookie, &si->si_syncCookie );
418 ber_dupbv( &syncCookie_req, &si->si_syncCookie[0] );
420 psub = be->be_nsuffix[0];
422 rc = ldap_sync_search( si, ld, memctx, &msgid );
423 if( rc != LDAP_SUCCESS ) {
425 LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
426 "ldap_search_ext: %s (%d)\n", ldap_err2string( rc ), rc, 0 );
428 Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
429 "ldap_search_ext: %s (%d)\n", ldap_err2string( rc ), rc, 0 );
434 if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ){
440 while (( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, tout_p, &res ))
444 if ( slapd_abrupt_shutdown ) {
451 for( msg = ldap_first_message( ld, res );
453 msg = ldap_next_message( ld, msg ) )
455 syncCookie.bv_len = 0; syncCookie.bv_val = NULL;
456 switch( ldap_msgtype( msg ) ) {
457 case LDAP_RES_SEARCH_ENTRY:
458 entry = syncrepl_message_to_entry( si, ld, &op, msg,
459 &modlist, &syncstate, &syncUUID, &syncCookie );
460 rc_efree = syncrepl_entry( si, ld, &op, entry, modlist,
461 syncstate, &syncUUID, &syncCookie, !syncinfo_arrived );
462 if ( syncCookie.bv_len ) {
463 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie );
466 slap_mods_free( modlist );
473 case LDAP_RES_SEARCH_REFERENCE:
475 LDAP_LOG( OPERATION, ERR,
476 "do_syncrepl : reference received\n", 0, 0, 0 );
478 Debug( LDAP_DEBUG_ANY,
479 "do_syncrepl : reference received\n", 0, 0, 0 );
483 case LDAP_RES_SEARCH_RESULT:
484 ldap_parse_result( ld, msg, &err, NULL, NULL, NULL,
487 BerElementBuffer berbuf;
488 BerElement *ctrl_ber;
490 ctrl_ber = (BerElement *)&berbuf;
491 ber_init2( ctrl_ber, &rctrlp->ldctl_value, LBER_USE_DER );
493 ber_scanf( ctrl_ber, "{" /*"}"*/);
494 if ( ber_peek_tag( ctrl_ber, &len )
495 == LDAP_SYNC_TAG_COOKIE )
497 ber_scanf( ctrl_ber, "o", &syncCookie );
499 ldap_controls_free( rctrls );
501 value_match( &match, slap_schema.si_ad_entryCSN,
502 slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
503 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
504 &syncCookie_req, &syncCookie, &text );
505 if (si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST) {
506 /* FIXME : different error behaviors according to
507 * 1) err code : LDAP_BUSY ...
508 * 2) on err policy : stop service, stop sync, retry
510 if ( syncCookie.bv_len && match < 0) {
511 syncrepl_updateCookie( si, ld, &op,
512 &psub, &syncCookie );
516 /* FIXME : different error behaviors according to
517 * 1) err code : LDAP_BUSY ...
518 * 2) on err policy : stop service, stop sync, retry
520 if ( syncCookie.bv_len && match < 0 ) {
521 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie);
523 if ( si->si_sync_mode == LDAP_SYNC_STATE_MODE && match
526 syncrepl_del_nonpresent( ld, &op, si );
532 case LDAP_RES_INTERMEDIATE:
533 rc = ldap_parse_intermediate( ld, msg,
534 &retoid, &retdata, NULL, 0 );
535 if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
536 sync_info_arrived = 1;
537 res_ber = ber_init( retdata );
538 ber_scanf( res_ber, "{e" /*"}"*/, &syncstate );
540 if ( ber_peek_tag( res_ber, &len )
541 == LDAP_SYNC_TAG_COOKIE ) {
542 ber_scanf( res_ber, /*"{"*/ "o}", &syncCookie );
544 if ( syncstate == LDAP_SYNC_NEW_COOKIE ) {
546 LDAP_LOG( OPERATION, ERR,
547 "do_syncrepl : cookie required\n", 0, 0, 0 );
549 Debug( LDAP_DEBUG_ANY,
550 "do_syncrepl : cookie required\n", 0, 0, 0 );
555 value_match( &match, slap_schema.si_ad_entryCSN,
556 slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
557 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
558 &syncCookie_req, &syncCookie, &text );
560 if ( syncCookie.bv_len && match < 0 ) {
561 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie);
564 if ( syncstate == LDAP_SYNC_STATE_MODE_DONE ) {
566 syncrepl_del_nonpresent( ld, &op, si );
568 si->si_sync_mode = LDAP_SYNC_LOG_MODE;
569 } else if ( syncstate == LDAP_SYNC_LOG_MODE_DONE ) {
570 si->si_sync_mode = LDAP_SYNC_PERSIST_MODE;
571 } else if ( syncstate == LDAP_SYNC_REFRESH_DONE ) {
572 si->si_sync_mode = LDAP_SYNC_PERSIST_MODE;
573 } else if ( syncstate != LDAP_SYNC_NEW_COOKIE ||
574 syncstate != LDAP_SYNC_LOG_MODE_DONE )
577 LDAP_LOG( OPERATION, ERR,
578 "do_syncrepl : unknown sync info\n", 0, 0, 0 );
580 Debug( LDAP_DEBUG_ANY,
581 "do_syncrepl : unknown sync info\n", 0, 0, 0 );
585 ldap_memfree( retoid );
586 ber_bvfree( retdata );
587 ber_free( res_ber, 1 );
591 LDAP_LOG( OPERATION, ERR,"do_syncrepl :"
592 " unknown intermediate "
593 "response\n", 0, 0, 0 );
595 Debug( LDAP_DEBUG_ANY, "do_syncrepl : "
596 "unknown intermediate response (%d)\n",
599 ldap_memfree( retoid );
600 ber_bvfree( retdata );
606 LDAP_LOG( OPERATION, ERR, "do_syncrepl : "
607 "unknown message\n", 0, 0, 0 );
609 Debug( LDAP_DEBUG_ANY, "do_syncrepl : "
610 "unknown message\n", 0, 0, 0 );
615 if ( syncCookie.bv_val ) {
616 ch_free( syncCookie.bv_val );
617 syncCookie.bv_val = NULL;
619 if ( syncUUID.bv_val ) {
620 ch_free( syncUUID.bv_val );
621 syncUUID.bv_val = NULL;
631 ldap_get_option( ld, LDAP_OPT_ERROR_NUMBER, &errno );
632 errstr = ldap_err2string( errno );
635 LDAP_LOG( OPERATION, ERR,
636 "do_syncrepl : %s\n", errstr, 0, 0 );
638 Debug( LDAP_DEBUG_ANY,
639 "do_syncrepl : %s\n", errstr, 0, 0 );
644 #if defined( LDAP_SLAPI )
645 if ( op.o_pb ) slapi_pblock_destroy( op.o_pb );
646 slapi_x_free_object_extensions( SLAPI_X_EXT_OPERATION, &op );
647 #endif /* defined( LDAP_SLAPI ) */
649 if ( syncCookie.bv_val )
650 ch_free( syncCookie.bv_val );
651 if ( syncCookie_req.bv_val )
652 ch_free( syncCookie_req.bv_val );
653 if ( syncUUID.bv_val )
654 ch_free( syncUUID.bv_val );
656 if ( res ) ldap_msgfree( res );
660 ber_bvarray_free_x( si->si_syncCookie, op.o_tmpmemctx );
661 si->si_syncCookie = NULL;
663 ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
664 ldap_pvt_runqueue_stoptask( &syncrepl_rq, rtask );
665 if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
666 ldap_pvt_runqueue_resched( &syncrepl_rq, rtask );
668 ldap_pvt_runqueue_remove( &syncrepl_rq, rtask );
670 ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
676 syncrepl_message_to_entry(
681 Modifications **modlist,
683 struct berval *syncUUID,
684 struct berval *syncCookie
688 BerElement *ber = NULL;
691 Modifications **modtail = modlist;
694 char txtbuf[SLAP_TEXT_BUFLEN];
695 size_t textlen = sizeof txtbuf;
697 struct berval bdn = {0, NULL}, dn, ndn;
702 LDAPControl** rctrls = NULL;
706 if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
708 LDAP_LOG( OPERATION, ERR,
709 "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
711 Debug( LDAP_DEBUG_ANY,
712 "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
717 op->o_tag = LDAP_REQ_ADD;
719 rc = ldap_get_entry_controls( ld, msg, &rctrls );
720 if ( rc != LDAP_SUCCESS ) {
722 LDAP_LOG( OPERATION, ERR,
723 "syncrepl_message_to_entry : control get failed (%d)", rc, 0, 0 );
725 Debug( LDAP_DEBUG_ANY,
726 "syncrepl_message_to_entry : control get failed (%d)", rc, 0, 0 );
732 BerElementBuffer berbuf;
733 BerElement *ctrl_ber;
736 ctrl_ber = (BerElement *)&berbuf;
737 ber_init2( ctrl_ber, &rctrlp->ldctl_value, LBER_USE_DER );
738 ber_scanf( ctrl_ber, "{eo", syncstate, syncUUID );
739 if ( ber_peek_tag( ctrl_ber, &len ) == LDAP_SYNC_TAG_COOKIE ) {
740 ber_scanf( ctrl_ber, "o}", syncCookie );
742 ldap_controls_free( rctrls );
745 LDAP_LOG( OPERATION, ERR,"syncrepl_message_to_entry : "
746 " rctrls absent\n", 0, 0, 0 );
748 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry :"
749 " rctrls absent\n", 0, 0, 0 );
753 rc = ldap_get_dn_ber( ld, msg, &ber, &bdn );
755 if ( rc != LDAP_SUCCESS ) {
757 LDAP_LOG( OPERATION, ERR,
758 "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
760 Debug( LDAP_DEBUG_ANY,
761 "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
766 dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
767 ber_dupbv( &op->o_req_dn, &dn );
768 ber_dupbv( &op->o_req_ndn, &ndn );
769 sl_free( ndn.bv_val, op->o_tmpmemctx );
770 sl_free( dn.bv_val, op->o_tmpmemctx );
772 if ( *syncstate == LDAP_SYNC_PRESENT || *syncstate == LDAP_SYNC_DELETE ) {
776 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ) );
777 e->e_name = op->o_req_dn;
778 e->e_nname = op->o_req_ndn;
780 while ( ber_remaining( ber ) ) {
781 if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) ==
782 LBER_ERROR ) || ( tmp.sml_type.bv_val == NULL ))
787 mod = (Modifications *) ch_malloc( sizeof( Modifications ));
789 mod->sml_op = LDAP_MOD_REPLACE;
790 mod->sml_next = NULL;
791 mod->sml_desc = NULL;
792 mod->sml_type = tmp.sml_type;
793 mod->sml_bvalues = tmp.sml_bvalues;
794 mod->sml_nvalues = NULL;
797 modtail = &mod->sml_next;
800 if ( *modlist == NULL ) {
802 LDAP_LOG( OPERATION, ERR,
803 "syncrepl_message_to_entry: no attributes\n", 0, 0, 0 );
805 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: no attributes\n",
810 rc = slap_mods_check( *modlist, 1, &text, txtbuf, textlen, NULL );
812 if ( rc != LDAP_SUCCESS ) {
814 LDAP_LOG( OPERATION, ERR,
815 "syncrepl_message_to_entry: mods check (%s)\n", text, 0, 0 );
817 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods check (%s)\n",
823 rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
824 if( rc != LDAP_SUCCESS ) {
826 LDAP_LOG( OPERATION, ERR,
827 "syncrepl_message_to_entry: mods2entry (%s)\n", text, 0, 0 );
829 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods2entry (%s)\n",
836 if ( rc != LDAP_SUCCESS ) {
845 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
847 const struct berval *uuid1 = v_uuid1;
848 const struct berval *uuid2 = v_uuid2;
849 int rc = uuid1->bv_len - uuid2->bv_len;
851 return ( strcmp( uuid1->bv_val, uuid2->bv_val ) );
860 Modifications* modlist,
862 struct berval* syncUUID,
863 struct berval* syncCookie,
867 Backend *be = op->o_bd;
869 struct berval *syncuuid_bv = NULL;
871 SlapReply rs = {REP_RESULT};
872 int rc = LDAP_SUCCESS;
873 int ret = LDAP_SUCCESS;
876 ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ))
878 syncuuid_bv = ber_dupbv( NULL, syncUUID );
879 avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
880 syncuuid_cmp, avl_dup_error );
883 if ( syncstate == LDAP_SYNC_PRESENT ) {
887 op->ors_filterstr.bv_len = (sizeof("entryUUID=")-1) + syncUUID->bv_len;
888 op->ors_filterstr.bv_val = (char *) sl_malloc(
889 op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
890 AC_MEMCPY( op->ors_filterstr.bv_val, "entryUUID=", sizeof("entryUUID=")-1 );
891 AC_MEMCPY( &op->ors_filterstr.bv_val[sizeof("entryUUID=")-1],
892 syncUUID->bv_val, syncUUID->bv_len );
893 op->ors_filterstr.bv_val[op->ors_filterstr.bv_len] = '\0';
896 si->si_syncUUID_ndn = NULL;
898 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
899 op->ors_scope = LDAP_SCOPE_SUBTREE;
901 /* get syncrepl cookie of shadow replica from subentry */
902 op->o_req_dn = si->si_base;
903 op->o_req_ndn = si->si_base;
905 /* set callback function */
906 op->o_callback = &cb;
907 cb.sc_response = dn_callback;
910 si->si_syncUUID_ndn = NULL;
912 rc = be->be_search( op, &rs );
914 if ( op->ors_filter ) filter_free_x( op, op->ors_filter );
915 if ( op->ors_filterstr.bv_val ) {
916 sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
919 cb.sc_response = null_callback;
922 if ( rc == LDAP_SUCCESS && si->si_syncUUID_ndn &&
923 si->si_sync_mode != LDAP_SYNC_LOG_MODE )
925 op->o_req_dn = *si->si_syncUUID_ndn;
926 op->o_req_ndn = *si->si_syncUUID_ndn;
927 op->o_tag = LDAP_REQ_DELETE;
928 rc = be->be_delete( op, &rs );
931 switch ( syncstate ) {
933 case LDAP_SYNC_MODIFY:
934 if ( rc == LDAP_SUCCESS ||
935 rc == LDAP_REFERRAL ||
936 rc == LDAP_NO_SUCH_OBJECT )
938 attr_delete( &e->e_attrs, slap_schema.si_ad_entryUUID );
939 attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID,
940 syncUUID, op->o_tmpmemctx );
942 op->o_tag = LDAP_REQ_ADD;
944 op->o_req_dn = e->e_name;
945 op->o_req_ndn = e->e_nname;
946 rc = be->be_add( op, &rs );
948 if ( rc != LDAP_SUCCESS ) {
949 if ( rc == LDAP_ALREADY_EXISTS ) {
950 op->o_tag = LDAP_REQ_MODIFY;
951 op->orm_modlist = modlist;
952 op->o_req_dn = e->e_name;
953 op->o_req_ndn = e->e_nname;
954 rc = be->be_modify( op, &rs );
956 if ( rc != LDAP_SUCCESS ) {
958 LDAP_LOG( OPERATION, ERR,
959 "syncrepl_entry : be_modify failed (%d)\n",
962 Debug( LDAP_DEBUG_ANY,
963 "syncrepl_entry : be_modify failed (%d)\n",
969 } else if ( rc == LDAP_REFERRAL || rc == LDAP_NO_SUCH_OBJECT ) {
970 syncrepl_add_glue( si, ld, op, e,
972 syncUUID, syncCookie);
978 LDAP_LOG( OPERATION, ERR,
979 "syncrepl_entry : be_add failed (%d)\n",
982 Debug( LDAP_DEBUG_ANY,
983 "syncrepl_entry : be_add failed (%d)\n",
992 be_entry_release_w( op, e );
998 LDAP_LOG( OPERATION, ERR,
999 "syncrepl_entry : be_search failed (%d)\n", rc, 0, 0 );
1001 Debug( LDAP_DEBUG_ANY,
1002 "syncrepl_entry : be_search failed (%d)\n", rc, 0, 0 );
1009 case LDAP_SYNC_DELETE :
1010 if ( si->si_sync_mode == LDAP_SYNC_LOG_MODE ) {
1011 if ( si->si_syncUUID_ndn ) {
1012 op->o_req_dn = *si->si_syncUUID_ndn;
1013 op->o_req_ndn = *si->si_syncUUID_ndn;
1014 op->o_tag = LDAP_REQ_DELETE;
1015 rc = be->be_delete( op, &rs );
1018 /* Already deleted otherwise */
1024 LDAP_LOG( OPERATION, ERR,
1025 "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1027 Debug( LDAP_DEBUG_ANY,
1028 "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1036 if ( si->si_syncUUID_ndn ) {
1037 ber_bvfree( si->si_syncUUID_ndn );
1043 syncrepl_del_nonpresent(
1049 Backend* be = op->o_bd;
1051 SlapReply rs = {REP_RESULT};
1052 struct nonpresent_entry *np_list, *np_prev;
1054 op->o_req_dn = si->si_base;
1055 op->o_req_ndn = si->si_base;
1057 cb.sc_response = nonpresent_callback;
1060 op->o_callback = &cb;
1061 op->o_tag = LDAP_REQ_SEARCH;
1062 op->ors_scope = si->si_scope;
1063 op->ors_deref = LDAP_DEREF_NEVER;
1066 op->ors_attrsonly = 0;
1067 op->ors_attrs = NULL;
1068 op->ors_filter = str2filter_x( op, si->si_filterstr.bv_val );
1069 op->ors_filterstr = si->si_filterstr;
1071 op->o_nocaching = 1;
1072 be->be_search( op, &rs );
1073 op->o_nocaching = 0;
1075 if ( op->ors_filter ) filter_free_x( op, op->ors_filter );
1077 if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
1078 np_list = LDAP_LIST_FIRST( &si->si_nonpresentlist );
1079 while ( np_list != NULL ) {
1080 LDAP_LIST_REMOVE( np_list, npe_link );
1082 np_list = LDAP_LIST_NEXT( np_list, npe_link );
1083 op->o_tag = LDAP_REQ_DELETE;
1084 op->o_callback = &cb;
1085 cb.sc_response = null_callback;
1087 op->o_req_dn = *np_prev->npe_name;
1088 op->o_req_ndn = *np_prev->npe_nname;
1089 op->o_bd->be_delete( op, &rs );
1090 ber_bvfree( np_prev->npe_name );
1091 ber_bvfree( np_prev->npe_nname );
1092 op->o_req_dn.bv_val = NULL;
1093 op->o_req_ndn.bv_val = NULL;
1102 static struct berval gcbva[] = {
1113 Modifications* modlist,
1115 struct berval* syncUUID,
1116 struct berval* syncCookie
1119 Backend *be = op->o_bd;
1125 struct berval dn = {0, NULL};
1126 struct berval ndn = {0, NULL};
1128 SlapReply rs = {REP_RESULT};
1131 op->o_tag = LDAP_REQ_ADD;
1132 op->o_callback = &cb;
1133 cb.sc_response = null_callback;
1139 /* count RDNs in suffix */
1140 if ( be->be_nsuffix[0].bv_len ) {
1141 for (i=0, ptr=be->be_nsuffix[0].bv_val; ptr; ptr=strchr( ptr, ',' )) {
1151 /* Start with BE suffix */
1152 for ( i = 0, ptr = NULL; i < suffrdns; i++ ) {
1153 comma = strrchr(dn.bv_val, ',');
1154 if ( ptr ) *ptr = ',';
1155 if ( comma ) *comma = '\0';
1160 dn.bv_len -= ptr - dn.bv_val;
1163 /* the normalizedDNs are always the same length, no counting
1166 if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) {
1167 ndn.bv_val += ndn.bv_len - be->be_nsuffix[0].bv_len;
1168 ndn.bv_len = be->be_nsuffix[0].bv_len;
1171 while ( ndn.bv_val > e->e_nname.bv_val ) {
1172 glue = (Entry *) ch_calloc( 1, sizeof(Entry) );
1173 ber_dupbv( &glue->e_name, &dn );
1174 ber_dupbv( &glue->e_nname, &ndn );
1176 a = ch_calloc( 1, sizeof( Attribute ));
1177 a->a_desc = slap_schema.si_ad_objectClass;
1179 a->a_vals = ch_calloc( 3, sizeof( struct berval ));
1180 ber_dupbv( &a->a_vals[0], &gcbva[0] );
1181 ber_dupbv( &a->a_vals[1], &gcbva[1] );
1182 a->a_vals[2].bv_len = 0;
1183 a->a_vals[2].bv_val = NULL;
1185 a->a_nvals = a->a_vals;
1187 a->a_next = glue->e_attrs;
1190 a = ch_calloc( 1, sizeof( Attribute ));
1191 a->a_desc = slap_schema.si_ad_structuralObjectClass;
1193 a->a_vals = ch_calloc( 2, sizeof( struct berval ));
1194 ber_dupbv( &a->a_vals[0], &gcbva[1] );
1195 a->a_vals[1].bv_len = 0;
1196 a->a_vals[1].bv_val = NULL;
1198 a->a_nvals = a->a_vals;
1200 a->a_next = glue->e_attrs;
1203 op->o_req_dn = glue->e_name;
1204 op->o_req_ndn = glue->e_nname;
1206 rc = be->be_add ( op, &rs );
1207 if ( rc == LDAP_SUCCESS ) {
1208 be_entry_release_w( op, glue );
1210 /* incl. ALREADY EXIST */
1214 /* Move to next child */
1215 for (ptr = dn.bv_val-2; ptr > e->e_name.bv_val && *ptr != ','; ptr--) {
1218 if ( ptr == e->e_name.bv_val ) break;
1220 dn.bv_len = e->e_name.bv_len - (ptr-e->e_name.bv_val);
1221 for( ptr = ndn.bv_val-2;
1222 ptr > e->e_nname.bv_val && *ptr != ',';
1228 ndn.bv_len = e->e_nname.bv_len - (ptr-e->e_nname.bv_val);
1231 op->o_req_dn = e->e_name;
1232 op->o_req_ndn = e->e_nname;
1234 rc = be->be_add ( op, &rs );
1235 if ( rc == LDAP_SUCCESS ) {
1236 be_entry_release_w( op, e );
1244 static struct berval ocbva[] = {
1246 BER_BVC("subentry"),
1247 BER_BVC("syncConsumerSubentry"),
1251 static struct berval cnbva[] = {
1256 static struct berval ssbva[] = {
1261 static struct berval scbva[] = {
1267 syncrepl_updateCookie(
1272 struct berval *syncCookie
1275 Backend *be = op->o_bd;
1277 Modifications *mlnext;
1279 Modifications *modlist = NULL;
1280 Modifications **modtail = &modlist;
1283 char txtbuf[SLAP_TEXT_BUFLEN];
1284 size_t textlen = sizeof txtbuf;
1289 char syncrepl_cbuf[sizeof(CN_STR SYNCREPL_STR)];
1290 struct berval slap_syncrepl_dn_bv = BER_BVNULL;
1291 struct berval slap_syncrepl_cn_bv = BER_BVNULL;
1294 SlapReply rs = {REP_RESULT};
1296 struct berval *dup_syncCookie = NULL;
1298 /* update in memory cookie */
1299 ber_bvarray_free_x( si->si_syncCookie, op->o_tmpmemctx );
1300 si->si_syncCookie = NULL;
1302 /* ber_bvarray_add() doesn't have dup option */
1303 dup_syncCookie = ber_dupbv_x( NULL, syncCookie, op->o_tmpmemctx );
1304 ber_bvarray_add_x( &si->si_syncCookie, dup_syncCookie, op->o_tmpmemctx );
1305 op->o_tmpfree( dup_syncCookie, op->o_tmpmemctx );
1307 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1308 mod->sml_op = LDAP_MOD_REPLACE;
1309 mod->sml_desc = slap_schema.si_ad_objectClass;
1310 mod->sml_type = mod->sml_desc->ad_cname;
1311 mod->sml_bvalues = ocbva;
1313 modtail = &mod->sml_next;
1315 ber_dupbv( &cnbva[0], (struct berval *) &slap_syncrepl_bvc );
1316 assert( si->si_id < 1000 );
1317 cnbva[0].bv_len = snprintf( cnbva[0].bv_val,
1318 slap_syncrepl_bvc.bv_len,
1319 "syncrepl%d", si->si_id );
1320 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1321 mod->sml_op = LDAP_MOD_REPLACE;
1322 mod->sml_desc = slap_schema.si_ad_cn;
1323 mod->sml_type = mod->sml_desc->ad_cname;
1324 mod->sml_bvalues = cnbva;
1326 modtail = &mod->sml_next;
1328 if ( scbva[0].bv_val ) ch_free( scbva[0].bv_val );
1329 ber_dupbv( &scbva[0], &si->si_syncCookie[0] );
1330 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1331 mod->sml_op = LDAP_MOD_REPLACE;
1332 mod->sml_desc = slap_schema.si_ad_syncreplCookie;
1333 mod->sml_type = mod->sml_desc->ad_cname;
1334 mod->sml_bvalues = scbva;
1336 modtail = &mod->sml_next;
1338 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1339 mod->sml_op = LDAP_MOD_REPLACE;
1340 mod->sml_desc = slap_schema.si_ad_subtreeSpecification;
1341 mod->sml_type = mod->sml_desc->ad_cname;
1342 mod->sml_bvalues = ssbva;
1344 modtail = &mod->sml_next;
1348 op->o_tag = LDAP_REQ_ADD;
1349 rc = slap_mods_opattrs( op, modlist, modtail,
1350 &text,txtbuf, textlen );
1352 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
1353 ml->sml_op = LDAP_MOD_REPLACE;
1356 if( rc != LDAP_SUCCESS ) {
1358 LDAP_LOG( OPERATION, ERR,
1359 "syncrepl_updateCookie: mods opattrs (%s)\n", text, 0, 0 );
1361 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods opattrs (%s)\n",
1366 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1368 slap_syncrepl_cn_bv.bv_val = syncrepl_cbuf;
1369 assert( si->si_id < 1000 );
1370 slap_syncrepl_cn_bv.bv_len = snprintf( slap_syncrepl_cn_bv.bv_val,
1371 slap_syncrepl_cn_bvc.bv_len,
1372 "cn=syncrepl%d", si->si_id );
1374 build_new_dn( &slap_syncrepl_dn_bv, pdn, &slap_syncrepl_cn_bv,
1376 ber_dupbv( &e->e_name, &slap_syncrepl_dn_bv );
1377 ber_dupbv( &e->e_nname, &slap_syncrepl_dn_bv );
1379 if ( slap_syncrepl_dn_bv.bv_val ) {
1380 sl_free( slap_syncrepl_dn_bv.bv_val, op->o_tmpmemctx );
1385 rc = slap_mods2entry( modlist, &e, 1, 1, &text, txtbuf, textlen );
1387 if( rc != LDAP_SUCCESS ) {
1389 LDAP_LOG( OPERATION, ERR,
1390 "syncrepl_updateCookie: mods2entry (%s)\n", text, 0, 0 );
1392 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods2entry (%s)\n",
1397 cb.sc_response = null_callback;
1400 op->o_callback = &cb;
1401 op->o_req_dn = e->e_name;
1402 op->o_req_ndn = e->e_nname;
1404 /* update persistent cookie */
1405 update_cookie_retry:
1406 op->o_tag = LDAP_REQ_MODIFY;
1407 op->orm_modlist = modlist;
1408 rc = be->be_modify( op, &rs );
1410 if ( rc != LDAP_SUCCESS ) {
1411 if ( rc == LDAP_REFERRAL ||
1412 rc == LDAP_NO_SUCH_OBJECT ) {
1413 op->o_tag = LDAP_REQ_ADD;
1415 rc = be->be_add( op, &rs );
1416 if ( rc != LDAP_SUCCESS ) {
1417 if ( rc == LDAP_ALREADY_EXISTS ) {
1418 goto update_cookie_retry;
1419 } else if ( rc == LDAP_REFERRAL ||
1420 rc == LDAP_NO_SUCH_OBJECT ) {
1422 LDAP_LOG( OPERATION, ERR,
1423 "cookie will be non-persistent\n",
1426 Debug( LDAP_DEBUG_ANY,
1427 "cookie will be non-persistent\n",
1432 LDAP_LOG( OPERATION, ERR,
1433 "be_add failed (%d)\n",
1436 Debug( LDAP_DEBUG_ANY,
1437 "be_add failed (%d)\n",
1442 be_entry_release_w( op, e );
1447 LDAP_LOG( OPERATION, ERR,
1448 "be_modify failed (%d)\n", rc, 0, 0 );
1450 Debug( LDAP_DEBUG_ANY,
1451 "be_modify failed (%d)\n", rc, 0, 0 );
1462 if ( cnbva[0].bv_val ) {
1463 ch_free( cnbva[0].bv_val );
1464 cnbva[0].bv_val = NULL;
1466 if ( scbva[0].bv_val ) {
1467 ch_free( scbva[0].bv_val );
1468 scbva[0].bv_val = NULL;
1471 if ( mlnext->sml_next ) {
1472 slap_mods_free( mlnext->sml_next );
1473 mlnext->sml_next = NULL;
1476 for (ml = modlist ; ml != NULL; ml = mlnext ) {
1477 mlnext = ml->sml_next;
1485 avl_ber_bvfree( void *bv )
1490 if ( ((struct berval *)bv)->bv_val != NULL ) {
1491 ch_free ( ((struct berval *)bv)->bv_val );
1493 ch_free ( (char *) bv );
1502 syncinfo_t *si = op->o_callback->sc_private;
1504 if ( rs->sr_type == REP_SEARCH ) {
1505 if ( si->si_syncUUID_ndn != NULL ) {
1507 LDAP_LOG( OPERATION, ERR,
1508 "dn_callback : multiple entries match dn\n", 0, 0, 0 );
1510 Debug( LDAP_DEBUG_ANY,
1511 "dn_callback : multiple entries match dn\n", 0, 0, 0 );
1514 if ( rs->sr_entry == NULL ) {
1515 si->si_syncUUID_ndn = NULL;
1517 si->si_syncUUID_ndn = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1522 return LDAP_SUCCESS;
1526 nonpresent_callback(
1531 syncinfo_t *si = op->o_callback->sc_private;
1534 struct berval* present_uuid = NULL;
1535 struct nonpresent_entry *np_entry;
1537 if ( rs->sr_type == REP_RESULT ) {
1538 count = avl_free( si->si_presentlist, avl_ber_bvfree );
1539 si->si_presentlist = NULL;
1541 } else if ( rs->sr_type == REP_SEARCH ) {
1542 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
1544 if ( a == NULL ) return 0;
1546 present_uuid = avl_find( si->si_presentlist, &a->a_vals[0],
1549 if ( present_uuid == NULL ) {
1550 np_entry = (struct nonpresent_entry *)
1551 ch_calloc( 1, sizeof( struct nonpresent_entry ));
1552 np_entry->npe_name = ber_dupbv( NULL, &rs->sr_entry->e_name );
1553 np_entry->npe_nname = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1554 LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link );
1557 avl_delete( &si->si_presentlist,
1558 &a->a_vals[0], syncuuid_cmp );
1559 ch_free( present_uuid->bv_val );
1560 ch_free( present_uuid );
1563 return LDAP_SUCCESS;
1572 if ( rs->sr_err != LDAP_SUCCESS &&
1573 rs->sr_err != LDAP_REFERRAL &&
1574 rs->sr_err != LDAP_ALREADY_EXISTS &&
1575 rs->sr_err != LDAP_NO_SUCH_OBJECT )
1578 LDAP_LOG( OPERATION, ERR,
1579 "null_callback : error code 0x%x\n",
1582 Debug( LDAP_DEBUG_ANY,
1583 "null_callback : error code 0x%x\n",
1587 return LDAP_SUCCESS;
1591 slap_create_syncrepl_entry(
1593 struct berval *context_csn,
1602 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1604 attr_merge( e, slap_schema.si_ad_objectClass, ocbva, NULL );
1606 attr_merge_one( e, slap_schema.si_ad_structuralObjectClass,
1609 attr_merge_one( e, slap_schema.si_ad_cn, cn, NULL );
1611 if ( context_csn ) {
1612 attr_merge_one( e, slap_schema.si_ad_syncreplCookie,
1613 context_csn, NULL );
1617 bv.bv_len = sizeof("{}")-1;
1618 attr_merge_one( e, slap_schema.si_ad_subtreeSpecification, &bv, NULL );
1620 build_new_dn( &e->e_name, &be->be_nsuffix[0], rdn, NULL );
1621 ber_dupbv( &e->e_nname, &e->e_name );