3 * Replication Engine which uses the LDAP Sync protocol
5 /* Copyright (c) 2003 by International Business Machines, Inc.
7 * International Business Machines, Inc. (hereinafter called IBM) grants
8 * permission under its copyrights to use, copy, modify, and distribute this
9 * Software with or without fee, provided that the above copyright notice and
10 * all paragraphs of this notice appear in all copies, and that the name of IBM
11 * not be used in connection with the marketing of any product incorporating
12 * the Software or modifications thereof, without specific, written prior
15 * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
17 * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
18 * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
19 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
20 * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
27 #include <ac/string.h>
28 #include <ac/socket.h>
34 #include "lutil_ldap.h"
41 syncrepl_del_nonpresent( LDAP *, Operation * );
43 /* callback functions */
44 static int cookie_callback( struct slap_op *, struct slap_rep * );
45 static int dn_callback( struct slap_op *, struct slap_rep * );
46 static int nonpresent_callback( struct slap_op *, struct slap_rep * );
47 static int null_callback( struct slap_op *, struct slap_rep * );
49 static AttributeDescription **add_descs;
50 static AttributeDescription **add_descs_lastmod;
51 static AttributeDescription **del_descs;
52 static AttributeDescription **del_descs_lastmod;
54 struct runqueue_s syncrepl_rq;
59 add_descs = ch_malloc( 2 * sizeof( AttributeDescription * ));
60 add_descs[0] = slap_schema.si_ad_objectClass;
63 add_descs_lastmod = ch_malloc( 7 * sizeof( AttributeDescription * ));
64 add_descs_lastmod[0] = slap_schema.si_ad_objectClass;
65 add_descs_lastmod[1] = slap_schema.si_ad_creatorsName;
66 add_descs_lastmod[2] = slap_schema.si_ad_modifiersName;
67 add_descs_lastmod[3] = slap_schema.si_ad_createTimestamp;
68 add_descs_lastmod[4] = slap_schema.si_ad_modifyTimestamp;
69 add_descs_lastmod[5] = slap_schema.si_ad_entryCSN;
70 add_descs_lastmod[6] = NULL;
72 del_descs = ch_malloc( 9 * sizeof( AttributeDescription * ));
73 del_descs[0] = slap_schema.si_ad_structuralObjectClass;
74 del_descs[1] = slap_schema.si_ad_subschemaSubentry;
75 del_descs[2] = slap_schema.si_ad_hasSubordinates;
76 del_descs[3] = slap_schema.si_ad_creatorsName;
77 del_descs[4] = slap_schema.si_ad_modifiersName;
78 del_descs[5] = slap_schema.si_ad_createTimestamp;
79 del_descs[6] = slap_schema.si_ad_modifyTimestamp;
80 del_descs[7] = slap_schema.si_ad_entryCSN;
83 del_descs_lastmod = ch_malloc( 4 * sizeof( AttributeDescription * ));
84 del_descs_lastmod[0] = slap_schema.si_ad_structuralObjectClass;
85 del_descs_lastmod[1] = slap_schema.si_ad_subschemaSubentry;
86 del_descs_lastmod[2] = slap_schema.si_ad_hasSubordinates;
87 del_descs_lastmod[3] = NULL;
103 BerElement *sync_ber = NULL;
104 struct berval *sync_bvalp = NULL;
108 struct timeval timeout;
110 /* setup LDAP SYNC control */
111 sync_ber = ber_alloc_t( LBER_USE_DER );
112 ber_set_option( sync_ber, LBER_OPT_BER_MEMCTX, NULL );
114 if ( si->syncCookie ) {
115 ber_printf( sync_ber, "{eO}", abs(si->type), si->syncCookie );
117 ber_printf( sync_ber, "{e}", abs(si->type) );
120 if ( ber_flatten( sync_ber, &sync_bvalp ) == LBER_ERROR ) {
121 ber_free( sync_ber, 1 );
124 ber_free( sync_ber, 1 );
126 ctrls = (LDAPControl**) sl_calloc( 3, sizeof(LDAPControl*), NULL );
128 c[0].ldctl_oid = LDAP_CONTROL_SYNC;
129 c[0].ldctl_value = (*sync_bvalp);
130 c[0].ldctl_iscritical = si->type < 0;
134 c[1].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
135 c[1].ldctl_value.bv_val = si->authzId;
136 c[1].ldctl_value.bv_len = strlen( si->authzId );
137 c[1].ldctl_iscritical = 1;
145 err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
147 ber_bvfree( sync_bvalp );
150 if ( err != LDAP_OPT_SUCCESS )
151 fprintf( stderr, "Could not set controls : %d\n", err );
153 timeout.tv_sec = si->tlimit > 0 ? si->tlimit : 1;
155 rc = ldap_search_ext( ld, si->base, si->scope, si->filterstr,
156 si->attrs, si->attrsonly, sctrls, cctrls,
157 si->tlimit < 0 ? NULL : &timeout,
158 si->slimit, msgidp );
168 struct re_s* rtask = arg;
169 syncinfo_t *si = ( syncinfo_t * ) rtask->arg;
170 Backend *be = si->be;
172 SlapReply rs = {REP_RESULT};
175 LDAPControl **sctrls = NULL;
176 LDAPControl **rctrls = NULL;
177 LDAPControl *rctrlp = NULL;
178 BerElement *sync_ber = NULL;
179 struct berval *sync_bvalp = NULL;
181 BerElement *ctrl_ber = NULL;
182 BerElement *res_ber = NULL;
185 LDAPMessage *res = NULL;
186 LDAPMessage *msg = NULL;
190 int nresponses, nreferences, nextended, npartial;
191 int nresponses_psearch;
193 int cancel_msgid = -1;
195 struct berval *retdata = NULL;
197 int sync_info_arrived = 0;
201 struct berval syncUUID = { 0, NULL };
202 struct berval syncCookie = { 0, NULL };
207 int syncinfo_arrived = 0;
208 int cancel_response = 0;
211 AttributeDescription** descs = NULL;
223 struct berval base_bv = { 0, NULL };
224 struct berval pbase = { 0, NULL };
225 struct berval nbase = { 0, NULL };
226 struct berval sub_bv = { 0, NULL };
227 struct berval psubrdn = { 0, NULL };
228 struct berval nsubrdn = { 0, NULL };
229 struct berval psub = { 0, NULL };
230 struct berval nsub = { 0, NULL };
232 Modifications *modlist = NULL;
233 Modifications *ml, *mlnext;
234 char *def_filter_str = NULL;
237 LDAP_LOG ( OPERATION, DETAIL1, "do_syncrepl\n", 0, 0, 0 );
239 Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl\n", 0, 0, 0 );
245 if ( abs(si->type) != LDAP_SYNC_REFRESH_ONLY &&
246 abs(si->type) != LDAP_SYNC_REFRESH_AND_PERSIST ) {
250 /* Init connection to master */
252 rc = ldap_initialize( &ld, si->provideruri );
253 if ( rc != LDAP_SUCCESS ) {
255 LDAP_LOG( OPERATION, ERR, "do_syncrepl: "
256 "ldap_initialize failed (%s)\n",
257 si->provideruri, 0, 0 );
259 Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
260 "ldap_initialize failed (%s)\n",
261 si->provideruri, 0, 0 );
265 op.o_protocol = LDAP_VERSION3;
266 ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &op.o_protocol );
271 rc = ldap_start_tls_s( ld, NULL, NULL );
272 if( rc != LDAP_SUCCESS ) {
274 LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
275 "%s: ldap_start_tls failed (%d)\n",
276 si->tls == TLS_CRITICAL ? "Error" : "Warning",
279 Debug( LDAP_DEBUG_ANY,
280 "%s: ldap_start_tls failed (%d)\n",
281 si->tls == TLS_CRITICAL ? "Error" : "Warning",
284 if( si->tls == TLS_CRITICAL )
289 if ( si->bindmethod == LDAP_AUTH_SASL ) {
290 #ifdef HAVE_CYRUS_SASL
293 if ( si->secprops != NULL ) {
294 int err = ldap_set_option( ld,
295 LDAP_OPT_X_SASL_SECPROPS, si->secprops);
297 if( err != LDAP_OPT_SUCCESS ) {
299 LDAP_LOG ( OPERATION, ERR, "do_bind: Error: "
300 "ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
301 si->provideruri, si->secprops, 0 );
303 Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
304 "(%s,SECPROPS,\"%s\") failed!\n",
305 si->provideruri, si->secprops, NULL );
311 defaults = lutil_sasl_defaults( ld,
318 rc = ldap_sasl_interactive_bind_s( ld,
326 if ( rc != LDAP_SUCCESS ) {
328 LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
329 "ldap_sasl_interactive_bind_s failed (%d)\n",
332 Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
333 "ldap_sasl_interactive_bind_s failed (%d)\n",
338 #else /* HAVE_CYRUS_SASL */
339 fprintf( stderr, "not compiled with SASL support\n" );
343 rc = ldap_bind_s( ld, si->binddn, si->passwd, si->bindmethod );
344 if ( rc != LDAP_SUCCESS ) {
346 LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
347 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
349 Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
350 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
356 /* set thread context in syncinfo */
359 /* set memory context */
360 #define SLAB_SIZE 1048576
362 memctx = sl_mem_create( memsiz, ctx );
363 op.o_tmpmemctx = memctx;
364 op.o_tmpmfuncs = &sl_mfuncs;
367 op.o_tag = LDAP_REQ_SEARCH;
368 op.o_dn = si->updatedn;
369 op.o_ndn = si->updatedn;
371 op.o_time = slap_get_time();
372 op.o_managedsait = 1;
373 op.o_threadctx = si->ctx;
376 op.o_connid = op.o_conn->c_connid;
377 op.ors_scope = LDAP_SCOPE_BASE;
378 op.ors_deref = LDAP_DEREF_NEVER;
381 op.ors_attrsonly = 0;
383 op.ors_filter = str2filter( def_filter_str = "(objectClass=*)" );
384 ber_str2bv( def_filter_str, strlen( def_filter_str ), 1,
388 conn.c_send_ldap_result = slap_send_ldap_result;
389 conn.c_send_search_entry = slap_send_search_entry;
390 conn.c_send_search_reference = slap_send_search_reference;
392 /* get syncrepl cookie of shadow replica from subentry */
393 ber_str2bv( si->base, strlen(si->base), 1, &base_bv );
394 dnPrettyNormal( 0, &base_bv, &pbase, &nbase, op.o_tmpmemctx );
396 sprintf( substr, "cn=syncrepl%d", si->id );
397 ber_str2bv( substr, strlen(substr), 1, &sub_bv );
398 dnPrettyNormal( 0, &sub_bv, &psubrdn, &nsubrdn, op.o_tmpmemctx );
400 build_new_dn( &op.o_req_dn, &pbase, &psubrdn );
401 build_new_dn( &op.o_req_ndn, &nbase, &nsubrdn );
403 ch_free( base_bv.bv_val );
404 ch_free( pbase.bv_val );
405 ch_free( nbase.bv_val );
406 ch_free( sub_bv.bv_val );
407 ch_free( psubrdn.bv_val );
408 ch_free( nsubrdn.bv_val );
410 /* set callback function */
411 cb.sc_response = cookie_callback;
414 /* search subentry to retrieve cookie */
415 si->syncCookie = NULL;
416 be->be_search( &op, &rs );
418 ch_free( op.o_req_dn.bv_val );
419 ch_free( op.o_req_ndn.bv_val );
420 filter_free( op.ors_filter );
421 ch_free( op.ors_filterstr.bv_val );
423 psub = be->be_nsuffix[0];
425 /* Delete Attributes */
426 if ( si->lastmod == LASTMOD_REQ ) {
427 descs = del_descs_lastmod;
432 for ( i = 0; descs[i] != NULL; i++ ) {
433 for ( j = 0; si->attrs[j] != NULL; j++ ) {
434 if ( !strcmp( si->attrs[j], descs[i]->ad_cname.bv_val )) {
435 ch_free( si->attrs[j] );
436 for ( k = j; si->attrs[k] != NULL; k++ ) {
437 si->attrs[k] = si->attrs[k+1];
445 for ( n = 0; si->attrs[ n ] != NULL; n++ ) ;
447 if ( si->lastmod == LASTMOD_REQ ) {
448 descs = add_descs_lastmod;
453 for ( i = 0; descs[i] != NULL; i++ ) {
454 tmp = ( char ** ) ch_realloc( si->attrs,
455 ( n + 2 ) * sizeof( char * ));
458 LDAP_LOG( OPERATION, ERR, "out of memory\n", 0,0,0 );
460 Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
464 si->attrs[ n++ ] = ch_strdup ( descs[i]->ad_cname.bv_val );
465 si->attrs[ n ] = NULL;
468 rc = ldap_sync_search( si, ld, NULL, NULL, &msgid );
469 if( rc != LDAP_SUCCESS ) {
470 fprintf( stderr, "syncrepl: ldap_search_ext: %s (%d)\n",
471 ldap_err2string( rc ), rc );
475 while (( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res )) > 0 ) {
477 for ( msg = ldap_first_message( ld, res );
479 msg = ldap_next_message( ld, msg ) )
481 switch( ldap_msgtype( msg ) ) {
482 case LDAP_RES_SEARCH_ENTRY:
483 entry = syncrepl_message_to_entry( si, ld, &op, msg,
484 &modlist, &syncstate, &syncUUID, &syncCookie );
485 rc_efree = syncrepl_entry( si, ld, &op, entry, modlist,
486 syncstate, &syncUUID, &syncCookie, !syncinfo_arrived );
487 if ( syncCookie.bv_len ) {
488 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie );
492 for ( ml = modlist; ml != NULL; ml = mlnext ) {
493 mlnext = ml->sml_next;
498 case LDAP_RES_SEARCH_REFERENCE:
500 LDAP_LOG( OPERATION, ERR,
501 "do_syncrepl : reference received\n", 0, 0, 0 );
503 Debug( LDAP_DEBUG_ANY,
504 "do_syncrepl : reference received\n", 0, 0, 0 );
508 case LDAP_RES_SEARCH_RESULT:
509 ldap_parse_result( ld, msg, &err, NULL, NULL, NULL, &rctrls, 0 );
512 ctrl_ber = ber_alloc_t( LBER_USE_DER );
513 ber_set_option( ctrl_ber, LBER_OPT_BER_MEMCTX, &op.o_tmpmemctx );
514 ber_write( ctrl_ber, rctrlp->ldctl_value.bv_val, rctrlp->ldctl_value.bv_len, 0 );
515 ber_reset( ctrl_ber, 1 );
517 ber_scanf( ctrl_ber, "{" /*"}"*/);
518 if ( ber_peek_tag( ctrl_ber, &len )
519 == LDAP_SYNC_TAG_COOKIE ) {
520 ber_scanf( ctrl_ber, "o", &syncCookie );
523 if (si->type == LDAP_SYNC_REFRESH_AND_PERSIST) {
524 if ( cancel_response ) {
525 if ( syncCookie.bv_len ) {
526 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie );
529 ber_free( ctrl_ber, 1 );
534 ber_free( ctrl_ber, 1 );
538 if ( syncCookie.bv_len ) {
539 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie);
541 syncrepl_del_nonpresent( ld, &op );
543 ber_free( ctrl_ber, 1 );
548 case LDAP_RES_INTERMEDIATE:
549 rc = ldap_parse_intermediate( ld, msg,
550 &retoid, &retdata, NULL, 0 );
551 if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
552 sync_info_arrived = 1;
553 res_ber = ber_init( retdata );
554 ber_scanf( res_ber, "{e" /*"}"*/, &syncstate );
556 if ( syncstate == LDAP_SYNC_REFRESH_DONE ) {
557 syncrepl_del_nonpresent( ld, &op );
558 } else if ( syncstate != LDAP_SYNC_NEW_COOKIE ) {
560 LDAP_LOG( OPERATION, ERR,
561 "do_syncrepl : unknown sync info\n", 0, 0, 0 );
563 Debug( LDAP_DEBUG_ANY,
564 "do_syncrepl : unknown sync info\n", 0, 0, 0 );
568 if ( ber_peek_tag( res_ber, &len )
569 == LDAP_SYNC_TAG_COOKIE ) {
570 ber_scanf( res_ber, /*"{"*/ "o}", &syncCookie );
571 if ( syncCookie.bv_len ) {
572 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie);
575 if ( syncstate == LDAP_SYNC_NEW_COOKIE ) {
577 LDAP_LOG( OPERATION, ERR,
578 "do_syncrepl : cookie required\n", 0, 0, 0 );
580 Debug( LDAP_DEBUG_ANY,
581 "do_syncrepl : cookie required\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 );
622 LDAP_LOG( OPERATION, ERR,
623 "do_syncrepl : unknown result\n", 0, 0, 0 );
625 Debug( LDAP_DEBUG_ANY,
626 "do_syncrepl : unknown result\n", 0, 0, 0 );
631 if ( syncCookie.bv_val )
632 ch_free( syncCookie.bv_val );
633 if ( syncUUID.bv_val )
634 ch_free( syncUUID.bv_val );
640 ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
641 ldap_pvt_runqueue_stoptask( &syncrepl_rq, rtask );
642 if ( si->type == LDAP_SYNC_REFRESH_ONLY ) {
643 ldap_pvt_runqueue_resched( &syncrepl_rq, rtask );
645 ldap_pvt_runqueue_remove( &syncrepl_rq, rtask );
647 ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
653 syncrepl_message_to_entry(
658 Modifications **modlist,
660 struct berval *syncUUID,
661 struct berval *syncCookie
665 BerElement *ber = NULL;
667 struct berval bv = {0, NULL};
670 Modifications **modtail = modlist;
671 Backend *be = op->o_bd;
674 char txtbuf[SLAP_TEXT_BUFLEN];
675 size_t textlen = sizeof txtbuf;
677 struct berval **bvals = NULL;
679 struct berval bdn = {0, NULL};
681 struct berval empty_bv = { 0, NULL };
687 LDAPControl** rctrls = NULL;
688 BerElement* ctrl_ber;
692 Modifications *prevml = NULL;
693 Modifications *nextml = NULL;
694 Modifications *ml = NULL;
695 AttributeDescription** descs;
700 if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
702 LDAP_LOG( OPERATION, ERR,
703 "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
705 Debug( LDAP_DEBUG_ANY,
706 "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
711 op->o_tag = LDAP_REQ_ADD;
713 rc = ldap_get_dn_ber( ld, msg, &ber, &bdn );
715 if ( rc != LDAP_SUCCESS ) {
717 LDAP_LOG( OPERATION, ERR,
718 "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
720 Debug( LDAP_DEBUG_ANY,
721 "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
726 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
727 dnPrettyNormal( NULL, &bdn, &e->e_name, &e->e_nname, NULL );
731 while ( ber_remaining( ber ) ) {
732 tag = ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values );
734 if ( tag == LBER_ERROR ) break;
735 if ( tmp.sml_type.bv_val == NULL ) break;
737 mod = (Modifications *) ch_malloc( sizeof( Modifications ));
739 mod->sml_op = LDAP_MOD_REPLACE;
740 mod->sml_next = NULL;
741 mod->sml_desc = NULL;
742 mod->sml_type = tmp.sml_type;
743 mod->sml_bvalues = tmp.sml_bvalues;
744 mod->sml_nvalues = tmp.sml_bvalues;
747 modtail = &mod->sml_next;
750 if ( ber_scanf( ber, "}") == LBER_ERROR ) {
752 LDAP_LOG( OPERATION, ERR,
753 "syncrepl_message_to_entry: ber_scanf failed\n", 0, 0, 0 );
755 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: ber_scanf failed\n",
762 tmpber = ldap_get_message_ber( msg );
763 ber = ber_dup( tmpber );
765 ber_scanf( ber, "{xx" );
767 rc = ldap_int_get_controls( ber, &rctrls );
769 if ( rc != LDAP_SUCCESS ) {
771 LDAP_LOG( OPERATION, ERR,
772 "syncrepl_message_to_entry : control get failed (%d)", rc, 0, 0 );
774 Debug( LDAP_DEBUG_ANY,
775 "syncrepl_message_to_entry : control get failed (%d)", rc, 0, 0 );
782 ctrl_ber = ber_alloc_t( LBER_USE_DER );
783 ber_set_option( ctrl_ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
784 ber_write( ctrl_ber, rctrlp->ldctl_value.bv_val, rctrlp->ldctl_value.bv_len, 0 );
785 ber_reset( ctrl_ber, 1 );
786 ber_scanf( ctrl_ber, "{eo", syncstate, syncUUID );
787 if ( ber_peek_tag( ctrl_ber, &len ) == LDAP_SYNC_TAG_COOKIE ) {
788 ber_scanf( ctrl_ber, "o}", syncCookie );
790 ber_free( ctrl_ber, 1 );
793 LDAP_LOG( OPERATION, ERR,"syncrepl_message_to_entry : "
794 " rctrls absent\n", 0, 0, 0 );
796 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry :"
797 " rctrls absent\n", 0, 0, 0 );
801 if ( *syncstate == LDAP_SYNC_PRESENT ) {
804 } else if ( *syncstate == LDAP_SYNC_DELETE ) {
808 if ( *modlist == NULL ) {
810 LDAP_LOG( OPERATION, ERR,
811 "syncrepl_message_to_entry: no attributes\n", 0, 0, 0 );
813 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: no attributes\n",
819 while ( ml != NULL ) {
820 AttributeDescription *ad = NULL;
821 rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, &text );
823 if( rc != LDAP_SUCCESS ) {
831 if ( si->lastmod == LASTMOD_REQ ) {
832 descs = del_descs_lastmod;
837 for ( i = 0; descs[i] != NULL; i++ ) {
838 if ( ad == descs[i] ) {
839 if ( prevml == NULL ) {
840 modlist = &ml->sml_next;
843 prevml->sml_next = ml->sml_next;
845 slap_mod_free( &ml->sml_mod, 0 );
846 nextml = ml->sml_next;
856 rc = slap_mods_check( *modlist, 1, &text, txtbuf, textlen, NULL );
858 if ( rc != LDAP_SUCCESS ) {
860 LDAP_LOG( OPERATION, ERR,
861 "syncrepl_message_to_entry: mods check (%s)\n", text, 0, 0 );
863 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods check (%s)\n",
869 rc = slap_mods_opattrs( op, *modlist, modtail,
870 &text,txtbuf, textlen );
872 if( rc != LDAP_SUCCESS ) {
874 LDAP_LOG( OPERATION, ERR,
875 "syncrepl_message_to_entry: mods opattrs (%s)\n", text, 0, 0 );
877 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods opattrs (%s)\n",
883 rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
884 if( rc != LDAP_SUCCESS ) {
886 LDAP_LOG( OPERATION, ERR,
887 "syncrepl_message_to_entry: mods2entry (%s)\n", text, 0, 0 );
889 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods2entry (%s)\n",
902 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
904 const struct berval *uuid1 = v_uuid1;
905 const struct berval *uuid2 = v_uuid2;
906 int rc = uuid1->bv_len - uuid2->bv_len;
908 return ( strcmp( uuid1->bv_val, uuid2->bv_val ) );
917 Modifications* modlist,
919 struct berval* syncUUID,
920 struct berval* syncCookie,
924 Backend *be = op->o_bd;
926 struct berval csn_bv = {0, NULL};
927 struct berval *syncuuid_bv = NULL;
928 char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
930 SlapReply rs = {REP_RESULT};
931 int rc = LDAP_SUCCESS;
933 struct berval base_bv = {0, NULL};
941 ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD )) {
942 syncuuid_bv = ber_dupbv( NULL, syncUUID );
943 avl_insert( &si->presentlist, (caddr_t) syncuuid_bv,
944 syncuuid_cmp, avl_dup_error );
947 if ( syncstate == LDAP_SYNC_PRESENT ) {
954 filterstr = (char *) sl_malloc( strlen("entryUUID=") + syncUUID->bv_len + 1,
956 strcpy( filterstr, "entryUUID=" );
957 strcat( filterstr, syncUUID->bv_val );
960 si->syncUUID = syncUUID;
961 si->syncUUID_ndn = NULL;
963 filter = str2filter( filterstr );
964 ber_str2bv( filterstr, strlen(filterstr), 1, &op->ors_filterstr );
965 ch_free( filterstr );
966 op->ors_filter = filter;
967 op->ors_scope = LDAP_SCOPE_SUBTREE;
969 /* get syncrepl cookie of shadow replica from subentry */
970 ber_str2bv( si->base, strlen(si->base), 1, &base_bv );
971 dnPrettyNormal( 0, &base_bv, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx );
972 ch_free( base_bv.bv_val );
974 /* set callback function */
975 op->o_callback = &cb;
976 cb.sc_response = dn_callback;
979 be->be_search( op, &rs );
981 ch_free( op->o_req_dn.bv_val );
982 ch_free( op->o_req_ndn.bv_val );
983 filter_free( op->ors_filter );
984 ch_free( op->ors_filterstr.bv_val );
986 cb.sc_response = null_callback;
991 if ( si->syncUUID_ndn ) {
992 op->o_req_dn = *si->syncUUID_ndn;
993 op->o_req_ndn = *si->syncUUID_ndn;
994 op->o_tag = LDAP_REQ_DELETE;
995 rc = be->be_delete( op, &rs );
998 switch ( syncstate ) {
1000 case LDAP_SYNC_MODIFY :
1002 if ( rc == LDAP_SUCCESS ||
1003 rc == LDAP_REFERRAL ||
1004 rc == LDAP_NO_SUCH_OBJECT ) {
1006 if ( !attr_find( e->e_attrs, slap_schema.si_ad_entryUUID )) {
1007 attr_merge_one( e, slap_schema.si_ad_entryUUID, syncUUID, syncUUID );
1010 op->o_tag = LDAP_REQ_ADD;
1012 op->o_req_dn = e->e_name;
1013 op->o_req_ndn = e->e_nname;
1014 rc = be->be_add( op, &rs );
1016 if ( rc != LDAP_SUCCESS ) {
1017 if ( rc == LDAP_ALREADY_EXISTS ) {
1018 op->o_tag = LDAP_REQ_MODIFY;
1019 op->orm_modlist = modlist;
1020 op->o_req_dn = e->e_name;
1021 op->o_req_ndn = e->e_nname;
1022 rc = be->be_modify( op, &rs );
1025 } else if ( rc == LDAP_REFERRAL ||
1026 rc == LDAP_NO_SUCH_OBJECT ) {
1027 syncrepl_add_glue( si, ld, op, e,
1029 syncUUID, syncCookie);
1034 LDAP_LOG( OPERATION, ERR,
1035 "be_modify failed (%d)\n",
1038 Debug( LDAP_DEBUG_ANY,
1039 "be_modify failed (%d)\n",
1051 LDAP_LOG( OPERATION, ERR,
1052 "be_modify/be_delete failed (%d)\n", rc, 0, 0 );
1054 Debug( LDAP_DEBUG_ANY,
1055 "be_modify/be_delete failed (%d)\n", rc, 0, 0 );
1061 case LDAP_SYNC_DELETE :
1062 /* Already deleted */
1067 LDAP_LOG( OPERATION, ERR,
1068 "unknown syncstate\n", 0, 0, 0 );
1070 Debug( LDAP_DEBUG_ANY,
1071 "unknown syncstate\n", 0, 0, 0 );
1078 syncrepl_del_nonpresent(
1083 Backend* be = op->o_bd;
1084 syncinfo_t *si = op->o_si;
1086 struct berval base_bv = {0, NULL};
1088 SlapReply rs = {REP_RESULT};
1089 struct berval filterstr_bv = {0, NULL};
1090 struct nonpresent_entry *np_list, *np_prev;
1092 ber_str2bv( si->base, strlen(si->base), 1, &base_bv );
1093 dnPrettyNormal(0, &base_bv, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx );
1094 ch_free( base_bv.bv_val );
1096 filter = str2filter( si->filterstr );
1098 cb.sc_response = nonpresent_callback;
1101 op->o_callback = &cb;
1102 op->o_tag = LDAP_REQ_SEARCH;
1103 op->ors_scope = si->scope;
1104 op->ors_deref = LDAP_DEREF_NEVER;
1107 op->ors_attrsonly = 0;
1108 op->ors_attrs = NULL;
1109 op->ors_filter = filter;
1110 ber_str2bv( si->filterstr, strlen( si->filterstr ), 1, &op->ors_filterstr );
1112 be->be_search( op, &rs );
1114 if ( !LDAP_LIST_EMPTY( &si->nonpresentlist ) ) {
1115 np_list = LDAP_LIST_FIRST( &si->nonpresentlist );
1116 while ( np_list != NULL ) {
1117 LDAP_LIST_REMOVE( np_list, np_link );
1119 np_list = LDAP_LIST_NEXT( np_list, np_link );
1120 op->o_tag = LDAP_REQ_DELETE;
1121 op->o_callback = &cb;
1122 cb.sc_response = null_callback;
1124 op->o_req_dn = *np_prev->dn;
1125 op->o_req_ndn = *np_prev->ndn;
1126 op->o_bd->be_delete( op, &rs );
1127 ber_bvfree( np_prev->dn );
1128 ber_bvfree( np_prev->ndn );
1129 op->o_req_dn.bv_val = NULL;
1130 op->o_req_ndn.bv_val = NULL;
1135 if ( op->o_req_dn.bv_val )
1136 ch_free( op->o_req_dn.bv_val );
1137 if ( op->o_req_ndn.bv_val )
1138 ch_free( op->o_req_ndn.bv_val );
1139 filter_free( op->ors_filter );
1140 ch_free( op->ors_filterstr.bv_val );
1152 Modifications* modlist,
1154 struct berval* syncUUID,
1155 struct berval* syncCookie
1158 Backend *be = op->o_bd;
1159 struct berval uuid_bv = {0, NULL};
1163 char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
1166 struct berval dn = {0, NULL};
1167 struct berval pdn = {0, NULL};
1168 struct berval ndn = {0, NULL};
1169 struct berval rdn = {0, NULL};
1171 SlapReply rs = {REP_RESULT};
1172 Connection *conn = op->o_conn;
1175 op->o_tag = LDAP_REQ_ADD;
1176 op->o_callback = &cb;
1177 cb.sc_response = null_callback;
1180 ber_dupbv( &dn, &e->e_nname );
1181 ber_dupbv( &pdn, &e->e_nname );
1184 while ( !be_issuffix ( be, &pdn )) {
1185 dnParent( &dn, &pdn );
1186 dn.bv_val = pdn.bv_val;
1187 dn.bv_len = pdn.bv_len;
1192 for ( i = 0; i <= levels; i++ ) {
1193 glue = (Entry*) ch_calloc( 1, sizeof(Entry) );
1194 ber_dupbv( &dn, &e->e_nname );
1198 for ( k = 0; k < j; k++ ) {
1199 dnParent( &dn, &pdn );
1200 dn.bv_val = pdn.bv_val;
1201 dn.bv_len = pdn.bv_len;
1204 dnPrettyNormal( 0, &dn, &pdn, &ndn, op->o_tmpmemctx );
1205 ber_dupbv( &glue->e_name, &pdn );
1206 ber_dupbv( &glue->e_nname, &ndn );
1208 ch_free( pdn.bv_val );
1209 ch_free( ndn.bv_val );
1211 a = ch_calloc( 1, sizeof( Attribute ));
1212 a->a_desc = slap_schema.si_ad_objectClass;
1214 a->a_vals = ch_calloc( 3, sizeof( struct berval ));
1215 ber_str2bv( "top", strlen("top"), 1, &a->a_vals[0] );
1216 ber_str2bv( "glue", strlen("glue"), 1, &a->a_vals[1] );
1217 a->a_vals[2].bv_len = 0;
1218 a->a_vals[2].bv_val = NULL;
1220 a->a_nvals = ch_calloc( 3, sizeof( struct berval ));
1221 ber_str2bv( "top", strlen("top"), 1, &a->a_nvals[0] );
1222 ber_str2bv( "glue", strlen("glue"), 1, &a->a_nvals[1] );
1223 a->a_nvals[2].bv_len = 0;
1224 a->a_nvals[2].bv_val = NULL;
1226 a->a_next = glue->e_attrs;
1229 a = ch_calloc( 1, sizeof( Attribute ));
1230 a->a_desc = slap_schema.si_ad_structuralObjectClass;
1232 a->a_vals = ch_calloc( 2, sizeof( struct berval ));
1233 ber_str2bv( "glue", strlen("glue"), 1, &a->a_vals[0] );
1234 a->a_vals[1].bv_len = 0;
1235 a->a_vals[1].bv_val = NULL;
1237 a->a_nvals = ch_calloc( 2, sizeof( struct berval ));
1238 ber_str2bv( "glue", strlen("glue"), 1, &a->a_nvals[0] );
1239 a->a_nvals[1].bv_len = 0;
1240 a->a_nvals[1].bv_val = NULL;
1242 a->a_next = glue->e_attrs;
1245 if ( !strcmp( e->e_nname.bv_val, glue->e_nname.bv_val )) {
1246 op->o_req_dn = e->e_name;
1247 op->o_req_ndn = e->e_nname;
1249 rc = be->be_add ( op, &rs );
1250 if ( rc == LDAP_SUCCESS )
1251 be_entry_release_w( op, e );
1256 op->o_req_dn = glue->e_name;
1257 op->o_req_ndn = glue->e_nname;
1259 rc = be->be_add ( op, &rs );
1260 if ( rc == LDAP_SUCCESS ) {
1261 be_entry_release_w( op, glue );
1263 /* incl. ALREADY EXIST */
1273 syncrepl_updateCookie(
1278 struct berval *syncCookie
1281 Backend *be = op->o_bd;
1283 Modifications *mlnext;
1285 Modifications *modlist;
1286 Modifications **modtail = &modlist;
1288 struct berval* ocbva = NULL;
1289 struct berval* cnbva = NULL;
1290 struct berval* ssbva = NULL;
1291 struct berval* scbva = NULL;
1296 char txtbuf[SLAP_TEXT_BUFLEN];
1297 size_t textlen = sizeof txtbuf;
1302 struct berval sub_bv = { 0, NULL };
1303 struct berval psubrdn = { 0, NULL };
1306 SlapReply rs = {REP_RESULT};
1308 ocbva = ( struct berval * ) ch_calloc( 4, sizeof( struct berval ));
1309 cnbva = ( struct berval * ) ch_calloc( 2, sizeof( struct berval ));
1310 ssbva = ( struct berval * ) ch_calloc( 2, sizeof( struct berval ));
1311 scbva = ( struct berval * ) ch_calloc( 2, sizeof( struct berval ));
1313 /* update in memory cookie */
1314 if ( si->syncCookie != NULL ) {
1315 ber_bvfree( si->syncCookie );
1317 si->syncCookie = ber_dupbv( NULL, syncCookie );
1318 ber_str2bv( "top", strlen("top"), 1, &ocbva[0] );
1319 ber_str2bv( "subentry", strlen("subentry"), 1, &ocbva[1] );
1320 ber_str2bv( "syncConsumerSubentry",
1321 strlen("syncConsumerSubentry"), 1, &ocbva[2] );
1322 ocbva[3].bv_len = 0;
1323 ocbva[3].bv_val = NULL;
1325 mod = (Modifications *) ch_malloc( sizeof( Modifications ));
1326 mod->sml_op = LDAP_MOD_REPLACE;
1327 mod->sml_next = NULL;
1328 mod->sml_desc = NULL;
1329 ber_str2bv( "objectClass", strlen("objectClass"), 1, &mod->sml_type );
1330 mod->sml_bvalues = ocbva;
1331 mod->sml_nvalues = ocbva;
1333 modtail = &mod->sml_next;
1335 sprintf( substr, "syncrepl%d", si->id );
1336 sprintf( rdnstr, "cn=%s", substr );
1337 ber_str2bv( substr, strlen( substr ), 1, &cnbva[0] );
1338 ber_str2bv( rdnstr, strlen( rdnstr ), 1, &psubrdn );
1339 cnbva[1].bv_len = 0;
1340 cnbva[1].bv_val = NULL;
1341 mod = (Modifications *) ch_malloc( sizeof( Modifications ));
1342 mod->sml_op = LDAP_MOD_REPLACE;
1343 mod->sml_next = NULL;
1344 mod->sml_desc = NULL;
1345 ber_str2bv( "cn", strlen("cn"), 1, &mod->sml_type );
1346 mod->sml_bvalues = cnbva;
1347 mod->sml_nvalues = cnbva;
1349 modtail = &mod->sml_next;
1351 ber_dupbv( &scbva[0], si->syncCookie );
1352 scbva[1].bv_len = 0;
1353 scbva[1].bv_val = NULL;
1354 mod = (Modifications *) ch_malloc( sizeof( Modifications ));
1355 mod->sml_op = LDAP_MOD_REPLACE;
1356 mod->sml_next = NULL;
1357 mod->sml_desc = NULL;
1358 ber_str2bv( "syncreplCookie", strlen("syncreplCookie"),
1359 1, &mod->sml_type );
1360 mod->sml_bvalues = scbva;
1361 mod->sml_nvalues = scbva;
1363 modtail = &mod->sml_next;
1365 ber_str2bv( "{}", strlen("{}"), 1, &ssbva[0] );
1366 ssbva[1].bv_len = 0;
1367 ssbva[1].bv_val = NULL;
1368 mod = (Modifications *) ch_malloc( sizeof( Modifications ));
1369 mod->sml_op = LDAP_MOD_REPLACE;
1370 mod->sml_next = NULL;
1371 mod->sml_desc = NULL;
1372 ber_str2bv( "subtreeSpecification",
1373 strlen("subtreeSpecification"), 1, &mod->sml_type );
1374 mod->sml_bvalues = ssbva;
1375 mod->sml_nvalues = ssbva;
1377 modtail = &mod->sml_next;
1379 rc = slap_mods_check( modlist, 1, &text, txtbuf, textlen, NULL );
1381 if ( rc != LDAP_SUCCESS ) {
1383 LDAP_LOG( OPERATION, ERR,
1384 "syncrepl_updateCookie: mods check (%s)\n", text, 0, 0 );
1386 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods check (%s)\n",
1391 op->o_tag = LDAP_REQ_ADD;
1392 rc = slap_mods_opattrs( op, modlist, modtail,
1393 &text,txtbuf, textlen );
1395 if( rc != LDAP_SUCCESS ) {
1397 LDAP_LOG( OPERATION, ERR,
1398 "syncrepl_updateCookie: mods opattrs (%s)\n", text, 0, 0 );
1400 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods opattrs (%s)\n",
1405 e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1407 build_new_dn( &sub_bv, pdn, &psubrdn );
1408 dnPrettyNormal( NULL, &sub_bv, &e->e_name, &e->e_nname, NULL );
1409 ch_free( sub_bv.bv_val );
1410 ch_free( psubrdn.bv_val );
1414 rc = slap_mods2entry( modlist, &e, 1, 1, &text, txtbuf, textlen );
1416 if( rc != LDAP_SUCCESS ) {
1418 LDAP_LOG( OPERATION, ERR,
1419 "syncrepl_updateCookie: mods2entry (%s)\n", text, 0, 0 );
1421 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods2entry (%s)\n",
1426 cb.sc_response = null_callback;
1429 op->o_callback = &cb;
1430 op->o_req_dn = e->e_name;
1431 op->o_req_ndn = e->e_nname;
1433 /* update persistent cookie */
1434 update_cookie_retry:
1435 op->o_tag = LDAP_REQ_MODIFY;
1436 op->orm_modlist = modlist;
1437 rc = be->be_modify( op, &rs );
1438 if ( rc != LDAP_SUCCESS ) {
1439 if ( rc == LDAP_REFERRAL ||
1440 rc == LDAP_NO_SUCH_OBJECT ) {
1441 op->o_tag = LDAP_REQ_ADD;
1443 rc = be->be_add( op, &rs );
1444 if ( rc != LDAP_SUCCESS ) {
1445 if ( rc == LDAP_ALREADY_EXISTS ) {
1446 goto update_cookie_retry;
1447 } else if ( rc == LDAP_REFERRAL ||
1448 rc == LDAP_NO_SUCH_OBJECT ) {
1450 LDAP_LOG( OPERATION, ERR,
1451 "cookie will be non-persistent\n",
1454 Debug( LDAP_DEBUG_ANY,
1455 "cookie will be non-persistent\n",
1460 LDAP_LOG( OPERATION, ERR,
1461 "be_add failed (%d)\n",
1464 Debug( LDAP_DEBUG_ANY,
1465 "be_add failed (%d)\n",
1474 LDAP_LOG( OPERATION, ERR,
1475 "be_modify failed (%d)\n", rc, 0, 0 );
1477 Debug( LDAP_DEBUG_ANY,
1478 "be_modify failed (%d)\n", rc, 0, 0 );
1488 for ( ml = modlist; ml != NULL; ml = mlnext ) {
1489 mlnext = ml->sml_next;
1497 avl_ber_bvfree( void *bv )
1502 if ( ((struct berval *)bv)->bv_val != NULL ) {
1503 ber_memfree ( ((struct berval *)bv)->bv_val );
1505 ber_memfree ( (char *) bv );
1514 syncinfo_t *si = op->o_callback->sc_private;
1517 if ( rs->sr_type != REP_SEARCH ) return LDAP_SUCCESS;
1519 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_syncreplCookie );
1522 si->syncCookie = NULL;
1524 si->syncCookie = ber_dupbv( NULL, &a->a_vals[0] );
1526 return LDAP_SUCCESS;
1535 syncinfo_t *si = op->o_callback->sc_private;
1537 if ( rs->sr_type == REP_SEARCH ) {
1538 si->syncUUID_ndn = &rs->sr_entry->e_nname;
1541 return LDAP_SUCCESS;
1545 nonpresent_callback(
1550 syncinfo_t *si = op->o_callback->sc_private;
1553 struct berval* present_uuid = NULL;
1555 SlapReply rs_cb = {REP_RESULT};
1556 struct nonpresent_entry *np_entry;
1558 if ( rs->sr_type == REP_RESULT ) {
1559 count = avl_free( si->presentlist, avl_ber_bvfree );
1560 si->presentlist = NULL;
1561 return LDAP_SUCCESS;
1562 } else if ( rs->sr_type == REP_SEARCH ) {
1563 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
1568 present_uuid = avl_find( si->presentlist, &a->a_vals[0], syncuuid_cmp );
1570 if ( present_uuid == NULL ) {
1571 np_entry = (struct nonpresent_entry *)
1572 ch_calloc( 1, sizeof( struct nonpresent_entry ));
1573 np_entry->dn = ber_dupbv( NULL, &rs->sr_entry->e_name );
1574 np_entry->ndn = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1575 LDAP_LIST_INSERT_HEAD( &si->nonpresentlist, np_entry, np_link );
1577 avl_delete( &si->presentlist,
1578 &a->a_vals[0], syncuuid_cmp );
1580 return LDAP_SUCCESS;
1582 return LDAP_SUCCESS;
1593 syncinfo_t *si = op->o_callback->sc_private;
1595 if ( rs->sr_err != LDAP_SUCCESS &&
1596 rs->sr_err != LDAP_REFERRAL &&
1597 rs->sr_err != LDAP_ALREADY_EXISTS &&
1598 rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
1600 LDAP_LOG( OPERATION, ERR,
1601 "null_callback : error code 0x%x\n",
1604 Debug( LDAP_DEBUG_ANY,
1605 "null_callback : error code 0x%x\n",
1609 return LDAP_SUCCESS;
1614 str2clist( char ***out, char *in, const char *brkstr )
1623 /* find last element in list */
1624 for (i = 0; *out && *out[i]; i++);
1626 /* protect the input string from strtok */
1627 str = ch_strdup( in );
1629 /* Count words in string */
1631 for ( s = str; *s; s++ ) {
1632 if ( strchr( brkstr, *s ) != NULL ) {
1637 *out = ch_realloc( *out, ( i + j + 1 ) * sizeof( char * ) );
1639 for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
1641 s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
1643 *new = ch_strdup( s );