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;
875 ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ))
877 syncuuid_bv = ber_dupbv( NULL, syncUUID );
878 avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
879 syncuuid_cmp, avl_dup_error );
882 if ( syncstate == LDAP_SYNC_PRESENT ) {
886 op->ors_filterstr.bv_len = (sizeof("entryUUID=")-1) + syncUUID->bv_len;
887 op->ors_filterstr.bv_val = (char *) sl_malloc(
888 op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
889 AC_MEMCPY( op->ors_filterstr.bv_val, "entryUUID=", sizeof("entryUUID=")-1 );
890 AC_MEMCPY( &op->ors_filterstr.bv_val[sizeof("entryUUID=")-1],
891 syncUUID->bv_val, syncUUID->bv_len );
892 op->ors_filterstr.bv_val[op->ors_filterstr.bv_len] = '\0';
895 si->si_syncUUID_ndn = NULL;
897 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
898 op->ors_scope = LDAP_SCOPE_SUBTREE;
900 /* get syncrepl cookie of shadow replica from subentry */
901 op->o_req_dn = si->si_base;
902 op->o_req_ndn = si->si_base;
904 /* set callback function */
905 op->o_callback = &cb;
906 cb.sc_response = dn_callback;
909 si->si_syncUUID_ndn = NULL;
911 rc = be->be_search( op, &rs );
913 if ( op->ors_filter ) filter_free_x( op, op->ors_filter );
914 if ( op->ors_filterstr.bv_val ) {
915 sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
918 cb.sc_response = null_callback;
921 if ( rc == LDAP_SUCCESS && si->si_syncUUID_ndn &&
922 si->si_sync_mode != LDAP_SYNC_LOG_MODE )
924 op->o_req_dn = *si->si_syncUUID_ndn;
925 op->o_req_ndn = *si->si_syncUUID_ndn;
926 op->o_tag = LDAP_REQ_DELETE;
927 rc = be->be_delete( op, &rs );
930 if ( si->si_syncUUID_ndn ) {
931 ber_bvfree( si->si_syncUUID_ndn );
934 switch ( syncstate ) {
936 case LDAP_SYNC_MODIFY:
937 if ( rc == LDAP_SUCCESS ||
938 rc == LDAP_REFERRAL ||
939 rc == LDAP_NO_SUCH_OBJECT )
941 attr_delete( &e->e_attrs, slap_schema.si_ad_entryUUID );
942 attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID,
943 syncUUID, op->o_tmpmemctx );
945 op->o_tag = LDAP_REQ_ADD;
947 op->o_req_dn = e->e_name;
948 op->o_req_ndn = e->e_nname;
949 rc = be->be_add( op, &rs );
951 if ( rc != LDAP_SUCCESS ) {
952 if ( rc == LDAP_ALREADY_EXISTS ) {
953 op->o_tag = LDAP_REQ_MODIFY;
954 op->orm_modlist = modlist;
955 op->o_req_dn = e->e_name;
956 op->o_req_ndn = e->e_nname;
957 rc = be->be_modify( op, &rs );
959 if ( rc != LDAP_SUCCESS ) {
961 LDAP_LOG( OPERATION, ERR,
962 "syncrepl_entry : be_modify failed (%d)\n",
965 Debug( LDAP_DEBUG_ANY,
966 "syncrepl_entry : be_modify failed (%d)\n",
971 } else if ( rc == LDAP_REFERRAL || rc == LDAP_NO_SUCH_OBJECT ) {
972 syncrepl_add_glue( si, ld, op, e,
974 syncUUID, syncCookie);
979 LDAP_LOG( OPERATION, ERR,
980 "syncrepl_entry : be_add failed (%d)\n",
983 Debug( LDAP_DEBUG_ANY,
984 "syncrepl_entry : be_add failed (%d)\n",
992 be_entry_release_w( op, e );
997 LDAP_LOG( OPERATION, ERR,
998 "syncrepl_entry : be_search failed (%d)\n", rc, 0, 0 );
1000 Debug( LDAP_DEBUG_ANY,
1001 "syncrepl_entry : be_search failed (%d)\n", rc, 0, 0 );
1007 case LDAP_SYNC_DELETE :
1008 if ( si->si_sync_mode == LDAP_SYNC_LOG_MODE ) {
1009 op->o_req_dn = *si->si_syncUUID_ndn;
1010 op->o_req_ndn = *si->si_syncUUID_ndn;
1011 op->o_tag = LDAP_REQ_DELETE;
1012 rc = be->be_delete( op, &rs );
1014 /* Already deleted otherwise */
1019 LDAP_LOG( OPERATION, ERR,
1020 "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1022 Debug( LDAP_DEBUG_ANY,
1023 "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1030 syncrepl_del_nonpresent(
1036 Backend* be = op->o_bd;
1038 SlapReply rs = {REP_RESULT};
1039 struct nonpresent_entry *np_list, *np_prev;
1041 op->o_req_dn = si->si_base;
1042 op->o_req_ndn = si->si_base;
1044 cb.sc_response = nonpresent_callback;
1047 op->o_callback = &cb;
1048 op->o_tag = LDAP_REQ_SEARCH;
1049 op->ors_scope = si->si_scope;
1050 op->ors_deref = LDAP_DEREF_NEVER;
1053 op->ors_attrsonly = 0;
1054 op->ors_attrs = NULL;
1055 op->ors_filter = str2filter_x( op, si->si_filterstr.bv_val );
1056 op->ors_filterstr = si->si_filterstr;
1058 op->o_nocaching = 1;
1059 be->be_search( op, &rs );
1060 op->o_nocaching = 0;
1062 if ( op->ors_filter ) filter_free_x( op, op->ors_filter );
1064 if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
1065 np_list = LDAP_LIST_FIRST( &si->si_nonpresentlist );
1066 while ( np_list != NULL ) {
1067 LDAP_LIST_REMOVE( np_list, npe_link );
1069 np_list = LDAP_LIST_NEXT( np_list, npe_link );
1070 op->o_tag = LDAP_REQ_DELETE;
1071 op->o_callback = &cb;
1072 cb.sc_response = null_callback;
1074 op->o_req_dn = *np_prev->npe_name;
1075 op->o_req_ndn = *np_prev->npe_nname;
1076 op->o_bd->be_delete( op, &rs );
1077 ber_bvfree( np_prev->npe_name );
1078 ber_bvfree( np_prev->npe_nname );
1079 op->o_req_dn.bv_val = NULL;
1080 op->o_req_ndn.bv_val = NULL;
1089 static struct berval gcbva[] = {
1100 Modifications* modlist,
1102 struct berval* syncUUID,
1103 struct berval* syncCookie
1106 Backend *be = op->o_bd;
1112 struct berval dn = {0, NULL};
1113 struct berval ndn = {0, NULL};
1115 SlapReply rs = {REP_RESULT};
1118 op->o_tag = LDAP_REQ_ADD;
1119 op->o_callback = &cb;
1120 cb.sc_response = null_callback;
1126 /* count RDNs in suffix */
1127 if ( be->be_nsuffix[0].bv_len ) {
1128 for (i=0, ptr=be->be_nsuffix[0].bv_val; ptr; ptr=strchr( ptr, ',' )) {
1138 /* Start with BE suffix */
1139 for ( i = 0, ptr = NULL; i < suffrdns; i++ ) {
1140 comma = strrchr(dn.bv_val, ',');
1141 if ( ptr ) *ptr = ',';
1142 if ( comma ) *comma = '\0';
1147 dn.bv_len -= ptr - dn.bv_val;
1150 /* the normalizedDNs are always the same length, no counting
1153 if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) {
1154 ndn.bv_val += ndn.bv_len - be->be_nsuffix[0].bv_len;
1155 ndn.bv_len = be->be_nsuffix[0].bv_len;
1158 while ( ndn.bv_val > e->e_nname.bv_val ) {
1159 glue = (Entry *) ch_calloc( 1, sizeof(Entry) );
1160 ber_dupbv( &glue->e_name, &dn );
1161 ber_dupbv( &glue->e_nname, &ndn );
1163 a = ch_calloc( 1, sizeof( Attribute ));
1164 a->a_desc = slap_schema.si_ad_objectClass;
1166 a->a_vals = ch_calloc( 3, sizeof( struct berval ));
1167 ber_dupbv( &a->a_vals[0], &gcbva[0] );
1168 ber_dupbv( &a->a_vals[1], &gcbva[1] );
1169 a->a_vals[2].bv_len = 0;
1170 a->a_vals[2].bv_val = NULL;
1172 a->a_nvals = a->a_vals;
1174 a->a_next = glue->e_attrs;
1177 a = ch_calloc( 1, sizeof( Attribute ));
1178 a->a_desc = slap_schema.si_ad_structuralObjectClass;
1180 a->a_vals = ch_calloc( 2, sizeof( struct berval ));
1181 ber_dupbv( &a->a_vals[0], &gcbva[1] );
1182 a->a_vals[1].bv_len = 0;
1183 a->a_vals[1].bv_val = NULL;
1185 a->a_nvals = a->a_vals;
1187 a->a_next = glue->e_attrs;
1190 op->o_req_dn = glue->e_name;
1191 op->o_req_ndn = glue->e_nname;
1193 rc = be->be_add ( op, &rs );
1194 if ( rc == LDAP_SUCCESS ) {
1195 be_entry_release_w( op, glue );
1197 /* incl. ALREADY EXIST */
1201 /* Move to next child */
1202 for (ptr = dn.bv_val-2; ptr > e->e_name.bv_val && *ptr != ','; ptr--) {
1205 if ( ptr == e->e_name.bv_val ) break;
1207 dn.bv_len = e->e_name.bv_len - (ptr-e->e_name.bv_val);
1208 for( ptr = ndn.bv_val-2;
1209 ptr > e->e_nname.bv_val && *ptr != ',';
1215 ndn.bv_len = e->e_nname.bv_len - (ptr-e->e_nname.bv_val);
1218 op->o_req_dn = e->e_name;
1219 op->o_req_ndn = e->e_nname;
1221 rc = be->be_add ( op, &rs );
1222 if ( rc == LDAP_SUCCESS ) {
1223 be_entry_release_w( op, e );
1231 static struct berval ocbva[] = {
1233 BER_BVC("subentry"),
1234 BER_BVC("syncConsumerSubentry"),
1238 static struct berval cnbva[] = {
1243 static struct berval ssbva[] = {
1248 static struct berval scbva[] = {
1254 syncrepl_updateCookie(
1259 struct berval *syncCookie
1262 Backend *be = op->o_bd;
1264 Modifications *mlnext;
1266 Modifications *modlist = NULL;
1267 Modifications **modtail = &modlist;
1270 char txtbuf[SLAP_TEXT_BUFLEN];
1271 size_t textlen = sizeof txtbuf;
1276 char syncrepl_cbuf[sizeof(CN_STR SYNCREPL_STR)];
1277 struct berval slap_syncrepl_dn_bv = BER_BVNULL;
1278 struct berval slap_syncrepl_cn_bv = BER_BVNULL;
1281 SlapReply rs = {REP_RESULT};
1283 struct berval *dup_syncCookie = NULL;
1285 /* update in memory cookie */
1286 ber_bvarray_free_x( si->si_syncCookie, op->o_tmpmemctx );
1287 si->si_syncCookie = NULL;
1289 /* ber_bvarray_add() doesn't have dup option */
1290 dup_syncCookie = ber_dupbv_x( NULL, syncCookie, op->o_tmpmemctx );
1291 ber_bvarray_add_x( &si->si_syncCookie, dup_syncCookie, op->o_tmpmemctx );
1292 op->o_tmpfree( dup_syncCookie, op->o_tmpmemctx );
1294 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1295 mod->sml_op = LDAP_MOD_REPLACE;
1296 mod->sml_desc = slap_schema.si_ad_objectClass;
1297 mod->sml_type = mod->sml_desc->ad_cname;
1298 mod->sml_bvalues = ocbva;
1300 modtail = &mod->sml_next;
1302 ber_dupbv( &cnbva[0], (struct berval *) &slap_syncrepl_bvc );
1303 assert( si->si_id < 1000 );
1304 cnbva[0].bv_len = snprintf( cnbva[0].bv_val,
1305 slap_syncrepl_bvc.bv_len,
1306 "syncrepl%d", si->si_id );
1307 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1308 mod->sml_op = LDAP_MOD_REPLACE;
1309 mod->sml_desc = slap_schema.si_ad_cn;
1310 mod->sml_type = mod->sml_desc->ad_cname;
1311 mod->sml_bvalues = cnbva;
1313 modtail = &mod->sml_next;
1315 if ( scbva[0].bv_val ) ch_free( scbva[0].bv_val );
1316 ber_dupbv( &scbva[0], &si->si_syncCookie[0] );
1317 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1318 mod->sml_op = LDAP_MOD_REPLACE;
1319 mod->sml_desc = slap_schema.si_ad_syncreplCookie;
1320 mod->sml_type = mod->sml_desc->ad_cname;
1321 mod->sml_bvalues = scbva;
1323 modtail = &mod->sml_next;
1325 mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1326 mod->sml_op = LDAP_MOD_REPLACE;
1327 mod->sml_desc = slap_schema.si_ad_subtreeSpecification;
1328 mod->sml_type = mod->sml_desc->ad_cname;
1329 mod->sml_bvalues = ssbva;
1331 modtail = &mod->sml_next;
1335 op->o_tag = LDAP_REQ_ADD;
1336 rc = slap_mods_opattrs( op, modlist, modtail,
1337 &text,txtbuf, textlen );
1339 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
1340 ml->sml_op = LDAP_MOD_REPLACE;
1343 if( rc != LDAP_SUCCESS ) {
1345 LDAP_LOG( OPERATION, ERR,
1346 "syncrepl_updateCookie: mods opattrs (%s)\n", text, 0, 0 );
1348 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods opattrs (%s)\n",
1353 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1355 slap_syncrepl_cn_bv.bv_val = syncrepl_cbuf;
1356 assert( si->si_id < 1000 );
1357 slap_syncrepl_cn_bv.bv_len = snprintf( slap_syncrepl_cn_bv.bv_val,
1358 slap_syncrepl_cn_bvc.bv_len,
1359 "cn=syncrepl%d", si->si_id );
1361 build_new_dn( &slap_syncrepl_dn_bv, pdn, &slap_syncrepl_cn_bv,
1363 ber_dupbv( &e->e_name, &slap_syncrepl_dn_bv );
1364 ber_dupbv( &e->e_nname, &slap_syncrepl_dn_bv );
1366 if ( slap_syncrepl_dn_bv.bv_val ) {
1367 sl_free( slap_syncrepl_dn_bv.bv_val, op->o_tmpmemctx );
1372 rc = slap_mods2entry( modlist, &e, 1, 1, &text, txtbuf, textlen );
1374 if( rc != LDAP_SUCCESS ) {
1376 LDAP_LOG( OPERATION, ERR,
1377 "syncrepl_updateCookie: mods2entry (%s)\n", text, 0, 0 );
1379 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods2entry (%s)\n",
1384 cb.sc_response = null_callback;
1387 op->o_callback = &cb;
1388 op->o_req_dn = e->e_name;
1389 op->o_req_ndn = e->e_nname;
1391 /* update persistent cookie */
1392 update_cookie_retry:
1393 op->o_tag = LDAP_REQ_MODIFY;
1394 op->orm_modlist = modlist;
1395 rc = be->be_modify( op, &rs );
1397 if ( rc != LDAP_SUCCESS ) {
1398 if ( rc == LDAP_REFERRAL ||
1399 rc == LDAP_NO_SUCH_OBJECT ) {
1400 op->o_tag = LDAP_REQ_ADD;
1402 rc = be->be_add( op, &rs );
1403 if ( rc != LDAP_SUCCESS ) {
1404 if ( rc == LDAP_ALREADY_EXISTS ) {
1405 goto update_cookie_retry;
1406 } else if ( rc == LDAP_REFERRAL ||
1407 rc == LDAP_NO_SUCH_OBJECT ) {
1409 LDAP_LOG( OPERATION, ERR,
1410 "cookie will be non-persistent\n",
1413 Debug( LDAP_DEBUG_ANY,
1414 "cookie will be non-persistent\n",
1419 LDAP_LOG( OPERATION, ERR,
1420 "be_add failed (%d)\n",
1423 Debug( LDAP_DEBUG_ANY,
1424 "be_add failed (%d)\n",
1429 be_entry_release_w( op, e );
1434 LDAP_LOG( OPERATION, ERR,
1435 "be_modify failed (%d)\n", rc, 0, 0 );
1437 Debug( LDAP_DEBUG_ANY,
1438 "be_modify failed (%d)\n", rc, 0, 0 );
1449 if ( cnbva[0].bv_val ) {
1450 ch_free( cnbva[0].bv_val );
1451 cnbva[0].bv_val = NULL;
1453 if ( scbva[0].bv_val ) {
1454 ch_free( scbva[0].bv_val );
1455 scbva[0].bv_val = NULL;
1458 if ( mlnext->sml_next ) {
1459 slap_mods_free( mlnext->sml_next );
1460 mlnext->sml_next = NULL;
1463 for (ml = modlist ; ml != NULL; ml = mlnext ) {
1464 mlnext = ml->sml_next;
1472 avl_ber_bvfree( void *bv )
1477 if ( ((struct berval *)bv)->bv_val != NULL ) {
1478 ch_free ( ((struct berval *)bv)->bv_val );
1480 ch_free ( (char *) bv );
1489 syncinfo_t *si = op->o_callback->sc_private;
1491 if ( rs->sr_type == REP_SEARCH ) {
1492 if ( si->si_syncUUID_ndn != NULL ) {
1494 LDAP_LOG( OPERATION, ERR,
1495 "dn_callback : multiple entries match dn\n", 0, 0, 0 );
1497 Debug( LDAP_DEBUG_ANY,
1498 "dn_callback : multiple entries match dn\n", 0, 0, 0 );
1501 if ( rs->sr_entry == NULL ) {
1502 si->si_syncUUID_ndn = NULL;
1504 si->si_syncUUID_ndn = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1509 return LDAP_SUCCESS;
1513 nonpresent_callback(
1518 syncinfo_t *si = op->o_callback->sc_private;
1521 struct berval* present_uuid = NULL;
1522 struct nonpresent_entry *np_entry;
1524 if ( rs->sr_type == REP_RESULT ) {
1525 count = avl_free( si->si_presentlist, avl_ber_bvfree );
1526 si->si_presentlist = NULL;
1528 } else if ( rs->sr_type == REP_SEARCH ) {
1529 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
1531 if ( a == NULL ) return 0;
1533 present_uuid = avl_find( si->si_presentlist, &a->a_vals[0],
1536 if ( present_uuid == NULL ) {
1537 np_entry = (struct nonpresent_entry *)
1538 ch_calloc( 1, sizeof( struct nonpresent_entry ));
1539 np_entry->npe_name = ber_dupbv( NULL, &rs->sr_entry->e_name );
1540 np_entry->npe_nname = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1541 LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link );
1544 avl_delete( &si->si_presentlist,
1545 &a->a_vals[0], syncuuid_cmp );
1546 ch_free( present_uuid->bv_val );
1547 ch_free( present_uuid );
1550 return LDAP_SUCCESS;
1559 if ( rs->sr_err != LDAP_SUCCESS &&
1560 rs->sr_err != LDAP_REFERRAL &&
1561 rs->sr_err != LDAP_ALREADY_EXISTS &&
1562 rs->sr_err != LDAP_NO_SUCH_OBJECT )
1565 LDAP_LOG( OPERATION, ERR,
1566 "null_callback : error code 0x%x\n",
1569 Debug( LDAP_DEBUG_ANY,
1570 "null_callback : error code 0x%x\n",
1574 return LDAP_SUCCESS;
1578 slap_create_syncrepl_entry(
1580 struct berval *context_csn,
1589 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1591 attr_merge( e, slap_schema.si_ad_objectClass, ocbva, NULL );
1593 attr_merge_one( e, slap_schema.si_ad_structuralObjectClass,
1596 attr_merge_one( e, slap_schema.si_ad_cn, cn, NULL );
1598 if ( context_csn ) {
1599 attr_merge_one( e, slap_schema.si_ad_syncreplCookie,
1600 context_csn, NULL );
1604 bv.bv_len = sizeof("{}")-1;
1605 attr_merge_one( e, slap_schema.si_ad_subtreeSpecification, &bv, NULL );
1607 build_new_dn( &e->e_name, &be->be_nsuffix[0], rdn, NULL );
1608 ber_dupbv( &e->e_nname, &e->e_name );