]> git.sur5r.net Git - openldap/blob - servers/slapd/syncrepl.c
fix for persistent search termination (ITS#2724)
[openldap] / servers / slapd / syncrepl.c
1 /* $OpenLDAP$ */
2 /*
3  * Replication Engine which uses the LDAP Sync protocol
4  */
5 /* Copyright (c) 2003 by International Business Machines, Inc.
6  *
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
13  * permission.
14  *
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.
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26
27 #include <ac/string.h>
28 #include <ac/socket.h>
29 #include <db.h>
30
31 #include "ldap_pvt.h"
32 #include "lutil.h"
33 #include "slap.h"
34 #include "lutil_ldap.h"
35
36 #include "ldap_rq.h"
37
38 static void
39 syncrepl_del_nonpresent( LDAP *, Operation * );
40
41 /* callback functions */
42 static int cookie_callback( struct slap_op *, struct slap_rep * );
43 static int dn_callback( struct slap_op *, struct slap_rep * );
44 static int nonpresent_callback( struct slap_op *, struct slap_rep * );
45 static int null_callback( struct slap_op *, struct slap_rep * );
46 static int contextcsn_callback( Operation*, SlapReply* );
47
48 static AttributeDescription **sync_descs;
49
50 struct runqueue_s syncrepl_rq;
51
52 void
53 init_syncrepl()
54 {
55         sync_descs = ch_malloc( 4 * sizeof( AttributeDescription * ));
56         sync_descs[0] = slap_schema.si_ad_objectClass;
57         sync_descs[1] = slap_schema.si_ad_structuralObjectClass;
58         sync_descs[2] = slap_schema.si_ad_entryCSN;
59         sync_descs[3] = NULL;
60 }
61
62 int
63 ldap_sync_search(
64         syncinfo_t *si,
65         LDAP *ld,
66         LDAPControl **sctrls,
67         LDAPControl **cctrls,
68         int *msgidp )
69 {
70         BerElement      *ber;
71         int timelimit;
72         ber_int_t id;
73
74         int rc;
75         BerElement      *sync_ber = NULL;
76         struct berval *sync_bvalp = NULL;
77         LDAPControl c[2];
78         LDAPControl **ctrls;
79         int err;
80         struct timeval timeout;
81
82     /* setup LDAP SYNC control */
83     sync_ber = ber_alloc_t( LBER_USE_DER );
84     ber_set_option( sync_ber, LBER_OPT_BER_MEMCTX, NULL );
85
86     if ( si->syncCookie ) {
87         ber_printf( sync_ber, "{eO}", abs(si->type), si->syncCookie );
88     } else {
89         ber_printf( sync_ber, "{e}", abs(si->type) );
90     }
91
92     if ( ber_flatten( sync_ber, &sync_bvalp ) == LBER_ERROR ) {
93         ber_free( sync_ber, 1 );
94         return LBER_ERROR;
95     }
96     ber_free( sync_ber, 1 );
97
98     ctrls = (LDAPControl**) sl_calloc( 3, sizeof(LDAPControl*), NULL );
99
100     c[0].ldctl_oid = LDAP_CONTROL_SYNC;
101     c[0].ldctl_value = (*sync_bvalp);
102     c[0].ldctl_iscritical = si->type < 0;
103     ctrls[0] = &c[0];
104
105     if ( si->authzId ) {
106         c[1].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
107         c[1].ldctl_value.bv_val = si->authzId;
108         c[1].ldctl_value.bv_len = strlen( si->authzId );
109         c[1].ldctl_iscritical = 1;
110         ctrls[1] = &c[1];
111     } else {
112         ctrls[1] = NULL;
113     }
114
115     ctrls[2] = NULL;
116
117     err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
118
119     ber_bvfree( sync_bvalp );
120     ch_free( ctrls );
121
122     if ( err != LDAP_OPT_SUCCESS )
123         fprintf( stderr, "Could not set controls : %d\n", err );
124
125         timeout.tv_sec = si->tlimit > 0 ? si->tlimit : 1;
126
127         rc = ldap_search_ext( ld, si->base, si->scope, si->filterstr,
128                                                   si->attrs, si->attrsonly, sctrls, cctrls,
129                                                   si->tlimit < 0 ? NULL : &timeout,
130                                                   si->slimit, msgidp );
131
132         return rc;
133 }
134
135 void *
136 do_syncrepl(
137         void    *ctx,
138         void    *arg )
139 {
140         struct re_s* rtask = arg;
141         syncinfo_t *si = ( syncinfo_t * ) rtask->arg;
142         Backend *be = si->be;
143
144         SlapReply       rs = {REP_RESULT};
145
146         LDAPControl     c[2];
147         LDAPControl     **sctrls = NULL;
148         LDAPControl     **rctrls = NULL;
149         LDAPControl     *rctrlp = NULL;
150         BerElement      *sync_ber = NULL;
151         struct berval   *sync_bvalp = NULL;
152
153         BerElement      *ctrl_ber = NULL;
154         BerElement      *res_ber = NULL;
155
156         LDAP    *ld = NULL;
157         LDAPMessage     *res = NULL;
158         LDAPMessage     *msg = NULL;
159
160         ber_int_t       msgid;
161
162         int             nresponses, nreferences, nextended, npartial;
163         int             nresponses_psearch;
164
165         int             cancel_msgid = -1;
166         char            *retoid = NULL;
167         struct berval   *retdata = NULL;
168
169         int             sync_info_arrived = 0;
170         Entry           *entry = NULL;
171
172         int             syncstate;
173         struct berval   syncUUID = { 0, NULL };
174         struct berval   syncCookie = { 0, NULL };
175         struct berval   syncCookie_req = { 0, NULL };
176
177         int     rc;
178         int     err;
179         ber_len_t       len;
180         int     syncinfo_arrived = 0;
181         int     cancel_response = 0;
182
183         char **tmp = NULL;
184         AttributeDescription** descs = NULL;
185
186         Connection conn;
187         Operation op = {0};
188         slap_callback   cb;
189
190         void *memctx = NULL;
191         ber_len_t memsiz;
192         
193         int i, j, k, n;
194         int rc_efree;
195
196         struct berval base_bv = { 0, NULL };
197         struct berval pbase = { 0, NULL };
198         struct berval nbase = { 0, NULL };
199         struct berval sub_bv = { 0, NULL };
200         struct berval psubrdn = { 0, NULL };
201         struct berval nsubrdn = { 0, NULL };
202         struct berval psub = { 0, NULL };
203         struct berval nsub = { 0, NULL };
204         char substr[64];
205         Modifications   *modlist = NULL;
206         Modifications   *ml, *mlnext;
207         char *def_filter_str = NULL;
208
209         const char              *text;
210         int                             match;
211
212         struct timeval *tout_p = NULL;
213         struct timeval tout = { 10, 0 };
214
215 #ifdef NEW_LOGGING
216         LDAP_LOG ( OPERATION, DETAIL1, "do_syncrepl\n", 0, 0, 0 );
217 #else
218         Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl\n", 0, 0, 0 );
219 #endif
220
221         if ( si == NULL )
222                 return NULL;
223
224         if ( abs(si->type) != LDAP_SYNC_REFRESH_ONLY &&
225              abs(si->type) != LDAP_SYNC_REFRESH_AND_PERSIST ) {
226                 return NULL;
227         }
228
229         si->sync_mode = LDAP_SYNC_STATE_MODE;
230
231         /* Init connection to master */
232
233         rc = ldap_initialize( &ld, si->provideruri );
234         if ( rc != LDAP_SUCCESS ) {
235 #ifdef NEW_LOGGING
236                 LDAP_LOG( OPERATION, ERR, "do_syncrepl: "
237                         "ldap_initialize failed (%s)\n",
238                         si->provideruri, 0, 0 );
239 #else
240                 Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
241                         "ldap_initialize failed (%s)\n",
242                         si->provideruri, 0, 0 );
243 #endif
244         }
245
246         op.o_protocol = LDAP_VERSION3;
247         ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &op.o_protocol );
248
249         /* Bind to master */
250
251         if ( si->tls ) {
252                 rc = ldap_start_tls_s( ld, NULL, NULL );
253                 if( rc != LDAP_SUCCESS ) {
254 #ifdef NEW_LOGGING
255                         LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
256                                 "%s: ldap_start_tls failed (%d)\n",
257                                 si->tls == TLS_CRITICAL ? "Error" : "Warning",
258                                 rc, 0 );
259 #else
260                         Debug( LDAP_DEBUG_ANY,
261                                 "%s: ldap_start_tls failed (%d)\n",
262                                 si->tls == TLS_CRITICAL ? "Error" : "Warning",
263                                 rc, 0 );
264 #endif
265                         if( si->tls == TLS_CRITICAL )
266                                 return NULL;
267                 }
268         }
269
270         if ( si->bindmethod == LDAP_AUTH_SASL ) {
271 #ifdef HAVE_CYRUS_SASL
272                 void *defaults;
273
274                 if ( si->secprops != NULL ) {
275                         int err = ldap_set_option( ld,
276                                         LDAP_OPT_X_SASL_SECPROPS, si->secprops);
277
278                         if( err != LDAP_OPT_SUCCESS ) {
279 #ifdef NEW_LOGGING
280                                 LDAP_LOG ( OPERATION, ERR, "do_bind: Error: "
281                                         "ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
282                                         si->provideruri, si->secprops, 0 );
283 #else
284                                 Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
285                                         "(%s,SECPROPS,\"%s\") failed!\n",
286                                         si->provideruri, si->secprops, NULL );
287 #endif
288                                 return NULL;
289                         }
290                 }
291
292                 defaults = lutil_sasl_defaults( ld,
293                                 si->saslmech,
294                                 si->realm,
295                                 si->authcId,
296                                 si->passwd,
297                                 si->authzId );
298
299                 rc = ldap_sasl_interactive_bind_s( ld,
300                                 si->binddn,
301                                 si->saslmech,
302                                 NULL, NULL,
303                                 LDAP_SASL_QUIET,
304                                 lutil_sasl_interact,
305                                 defaults );
306
307                 if ( rc != LDAP_SUCCESS ) {
308 #ifdef NEW_LOGGING
309                         LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
310                                 "ldap_sasl_interactive_bind_s failed (%d)\n",
311                                 rc, 0, 0 );
312 #else
313                         Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
314                                 "ldap_sasl_interactive_bind_s failed (%d)\n",
315                                 rc, 0, 0 );
316 #endif
317                         return NULL;
318                 }
319 #else /* HAVE_CYRUS_SASL */
320                 fprintf( stderr, "not compiled with SASL support\n" );
321                 return NULL;
322 #endif
323         } else {
324                 rc = ldap_bind_s( ld, si->binddn, si->passwd, si->bindmethod );
325                 if ( rc != LDAP_SUCCESS ) {
326 #ifdef NEW_LOGGING
327                         LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
328                                 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
329 #else
330                         Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
331                                 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
332 #endif
333                         return NULL;
334                 }
335         }
336
337         /* set thread context in syncinfo */
338         si->ctx = ctx;
339
340         /* set memory context */
341 #define SLAB_SIZE 1048576
342         memsiz = SLAB_SIZE;
343         memctx = sl_mem_create( memsiz, ctx );
344         op.o_tmpmemctx = memctx;
345         op.o_tmpmfuncs = &sl_mfuncs;
346
347         op.o_si = si;
348         op.o_tag = LDAP_REQ_SEARCH;
349         op.o_dn = si->updatedn;
350         op.o_ndn = si->updatedn;
351         op.o_callback = &cb;
352         op.o_time = slap_get_time();
353         op.o_managedsait = 1;
354         op.o_threadctx = si->ctx;
355         op.o_bd = be;
356         op.o_conn = &conn;
357         op.o_connid = op.o_conn->c_connid;
358         op.ors_scope = LDAP_SCOPE_BASE;
359         op.ors_deref = LDAP_DEREF_NEVER;
360         op.ors_slimit = 0;
361         op.ors_tlimit = 0;
362         op.ors_attrsonly = 0;
363         op.ors_attrs = NULL;
364         op.ors_filter = str2filter( def_filter_str = "(objectClass=*)" );
365         ber_str2bv( def_filter_str, strlen( def_filter_str ), 1,
366                                 &op.ors_filterstr );
367
368         si->conn = &conn;
369         conn.c_send_ldap_result = slap_send_ldap_result;
370         conn.c_send_search_entry = slap_send_search_entry;
371         conn.c_send_search_reference = slap_send_search_reference;
372
373         /* get syncrepl cookie of shadow replica from subentry */
374         ber_str2bv( si->base, strlen(si->base), 1, &base_bv ); 
375         dnPrettyNormal( 0, &base_bv, &pbase, &nbase, op.o_tmpmemctx );
376
377         sprintf( substr, "cn=syncrepl%d", si->id );
378         ber_str2bv( substr, strlen(substr), 1, &sub_bv );
379         dnPrettyNormal( 0, &sub_bv, &psubrdn, &nsubrdn, op.o_tmpmemctx );
380
381         build_new_dn( &op.o_req_dn, &pbase, &psubrdn );
382         build_new_dn( &op.o_req_ndn, &nbase, &nsubrdn );
383
384         ch_free( base_bv.bv_val );
385         ch_free( pbase.bv_val );
386         ch_free( nbase.bv_val );
387         ch_free( sub_bv.bv_val );
388         ch_free( psubrdn.bv_val );
389         ch_free( nsubrdn.bv_val );
390
391         /* set callback function */
392         cb.sc_response = cookie_callback;
393         cb.sc_private = si;
394
395         /* search subentry to retrieve cookie */
396         si->syncCookie = NULL;
397         be->be_search( &op, &rs );
398
399         ber_dupbv( &syncCookie_req, si->syncCookie );
400
401         ch_free( op.o_req_dn.bv_val );
402         ch_free( op.o_req_ndn.bv_val );
403         filter_free( op.ors_filter );
404         ch_free( op.ors_filterstr.bv_val );
405
406         psub = be->be_nsuffix[0];
407
408         /* Delete Attributes */
409         descs = sync_descs;
410
411         for ( i = 0; descs[i] != NULL; i++ ) {
412                 for ( j = 0; si->attrs[j] != NULL; j++ ) {
413                         if ( !strcmp( si->attrs[j], descs[i]->ad_cname.bv_val )) {
414                                 ch_free( si->attrs[j] );
415                                 for ( k = j; si->attrs[k] != NULL; k++ ) {
416                                         si->attrs[k] = si->attrs[k+1];
417                                 }
418                         }
419                 }
420         }
421
422         /* Add Attributes */
423
424         for ( n = 0; si->attrs[ n ] != NULL; n++ ) ;
425         
426         descs = sync_descs;
427
428         for ( i = 0; descs[i] != NULL; i++ ) {
429                 tmp = ( char ** ) ch_realloc( si->attrs,
430                                 ( n + 3 ) * sizeof( char * ));
431                 if ( tmp == NULL ) {
432 #ifdef NEW_LOGGING
433                         LDAP_LOG( OPERATION, ERR, "out of memory\n", 0,0,0 );
434 #else
435                         Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
436 #endif
437                 }
438                 si->attrs = tmp;
439                 si->attrs[ n++ ] = ch_strdup ( descs[i]->ad_cname.bv_val );
440                 si->attrs[ n ] = NULL;
441         }
442
443         rc = ldap_sync_search( si, ld, NULL, NULL, &msgid );
444         if( rc != LDAP_SUCCESS ) {
445                 fprintf( stderr, "syncrepl: ldap_search_ext: %s (%d)\n",
446                                                         ldap_err2string( rc ), rc );
447                 return NULL;
448         }
449
450         if ( abs(si->type) == LDAP_SYNC_REFRESH_AND_PERSIST ){
451                 tout_p = &tout;
452         } else {
453                 tout_p = NULL;
454         }
455
456         while (( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, tout_p, &res )) >= 0 ) {
457
458                 if ( rc == 0 ) {
459                         if ( slapd_abrupt_shutdown ) {
460                                 break;
461                         } else {
462                                 continue;
463                         }
464                 }
465
466                 for ( msg = ldap_first_message( ld, res );
467                       msg != NULL;
468                       msg = ldap_next_message( ld, msg ) )
469                 {
470                         syncCookie.bv_len = 0; syncCookie.bv_val = NULL;
471                         switch( ldap_msgtype( msg ) ) {
472                         case LDAP_RES_SEARCH_ENTRY:
473                                 entry = syncrepl_message_to_entry( si, ld, &op, msg,
474                                         &modlist, &syncstate, &syncUUID, &syncCookie );
475                                 rc_efree = syncrepl_entry( si, ld, &op, entry, modlist,
476                                                 syncstate, &syncUUID, &syncCookie, !syncinfo_arrived );
477                                 if ( syncCookie.bv_len ) {
478                                         syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie );
479                                 }
480                                 if ( rc_efree )
481                                         entry_free( entry );
482                                 for ( ml = modlist; ml != NULL; ml = mlnext ) {
483                                         mlnext = ml->sml_next;
484                                         ber_memfree( ml );
485                                 }
486                                 break;
487
488                         case LDAP_RES_SEARCH_REFERENCE:
489 #ifdef NEW_LOGGING
490                                 LDAP_LOG( OPERATION, ERR,
491                                         "do_syncrepl : reference received\n", 0, 0, 0 );
492 #else
493                                 Debug( LDAP_DEBUG_ANY,
494                                         "do_syncrepl : reference received\n", 0, 0, 0 );
495 #endif
496                                 break;
497
498                         case LDAP_RES_SEARCH_RESULT:
499                                 ldap_parse_result( ld, msg, &err, NULL, NULL, NULL, &rctrls, 0 );
500                                 if ( rctrls ) {
501                                         rctrlp = *rctrls;
502                                         ctrl_ber = ber_alloc_t( LBER_USE_DER );
503                                         ber_set_option( ctrl_ber, LBER_OPT_BER_MEMCTX, &op.o_tmpmemctx );
504                                         ber_write( ctrl_ber, rctrlp->ldctl_value.bv_val, rctrlp->ldctl_value.bv_len, 0 );
505                                         ber_reset( ctrl_ber, 1 );
506
507                                         ber_scanf( ctrl_ber, "{" /*"}"*/);
508                                         if ( ber_peek_tag( ctrl_ber, &len )
509                                                 == LDAP_SYNC_TAG_COOKIE ) {
510                                                 ber_scanf( ctrl_ber, "o", &syncCookie );
511                                         }
512                                 }
513                                 value_match( &match, slap_schema.si_ad_entryCSN,
514                                                         slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
515                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
516                                                         &syncCookie_req, &syncCookie, &text );
517                                 if (si->type == LDAP_SYNC_REFRESH_AND_PERSIST) {
518                                         if ( cancel_response ) {
519                                                 if ( syncCookie.bv_len && match < 0) {
520                                                         syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie );
521                                                 }
522                                                 if ( ctrl_ber )
523                                                         ber_free( ctrl_ber, 1 );
524                                                 goto done;
525                                         }
526                                         else {
527                                                 if ( ctrl_ber )
528                                                         ber_free( ctrl_ber, 1 );
529                                                 break;
530                                         }
531                                 } else {
532                                         if ( syncCookie.bv_len && match < 0 ) {
533                                                 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie);
534                                         }
535                                         if ( si->sync_mode == LDAP_SYNC_STATE_MODE && match < 0 ) {
536                                                         syncrepl_del_nonpresent( ld, &op );
537                                         }
538                                         if ( ctrl_ber )
539                                                 ber_free( ctrl_ber, 1 );
540                                         goto done;
541                                 }
542                                 break;
543
544                         case LDAP_RES_INTERMEDIATE:
545                                 rc = ldap_parse_intermediate( ld, msg,
546                                         &retoid, &retdata, NULL, 0 );
547                                 if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
548                                         sync_info_arrived = 1;
549                                         res_ber = ber_init( retdata );
550                                         ber_scanf( res_ber, "{e" /*"}"*/, &syncstate );
551
552                                         if ( ber_peek_tag( res_ber, &len )
553                                                                 == LDAP_SYNC_TAG_COOKIE ) {
554                                                 ber_scanf( res_ber, /*"{"*/ "o}", &syncCookie );
555                                         } else {
556                                                 if ( syncstate == LDAP_SYNC_NEW_COOKIE ) {
557 #ifdef NEW_LOGGING
558                                                         LDAP_LOG( OPERATION, ERR,
559                                                                 "do_syncrepl : cookie required\n", 0, 0, 0 );
560 #else
561                                                         Debug( LDAP_DEBUG_ANY,
562                                                                 "do_syncrepl : cookie required\n", 0, 0, 0 );
563 #endif
564                                                 }
565                                         }
566
567                                         value_match( &match, slap_schema.si_ad_entryCSN,
568                                                                 slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
569                                                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
570                                                                 &syncCookie_req, &syncCookie, &text );
571
572                                         if ( syncCookie.bv_len && match < 0 ) {
573                                                 syncrepl_updateCookie( si, ld, &op, &psub, &syncCookie);
574                                         }
575
576                                         if ( syncstate == LDAP_SYNC_STATE_MODE_DONE ) {
577                                                 if ( match < 0 ) {
578                                                         syncrepl_del_nonpresent( ld, &op );
579                                                 }
580                                                 si->sync_mode = LDAP_SYNC_LOG_MODE;
581                                         } else if ( syncstate == LDAP_SYNC_LOG_MODE_DONE ) {
582                                                 si->sync_mode = LDAP_SYNC_PERSIST_MODE;
583                                         } else if ( syncstate == LDAP_SYNC_REFRESH_DONE ) {
584                                                 si->sync_mode = LDAP_SYNC_PERSIST_MODE;
585                                         } else if ( syncstate != LDAP_SYNC_NEW_COOKIE ||
586                                                                 syncstate != LDAP_SYNC_LOG_MODE_DONE ) {
587 #ifdef NEW_LOGGING
588                                                 LDAP_LOG( OPERATION, ERR,
589                                                         "do_syncrepl : unknown sync info\n", 0, 0, 0 );
590 #else
591                                                 Debug( LDAP_DEBUG_ANY,
592                                                         "do_syncrepl : unknown sync info\n", 0, 0, 0 );
593 #endif
594                                         }
595
596                                         ldap_memfree( retoid );
597                                         ber_bvfree( retdata );
598                                         ber_free( res_ber, 1 );
599                                         break;
600                                 } else {
601 #ifdef NEW_LOGGING
602                                         LDAP_LOG( OPERATION, ERR,"do_syncrepl :"
603                                                 " unknown intermediate "
604                                                 "response\n", 0, 0, 0 );
605 #else
606                                         Debug( LDAP_DEBUG_ANY, "do_syncrepl : "
607                                                 "unknown intermediate response (%d)\n",
608                                                 rc, 0, 0 );
609 #endif
610                                         ldap_memfree( retoid );
611                                         ber_bvfree( retdata );
612                                         break;
613                                 }
614                                 break;
615                         default:
616 #ifdef NEW_LOGGING
617                                 LDAP_LOG( OPERATION, ERR, "do_syncrepl : "
618                                         "unknown message\n", 0, 0, 0 );
619 #else
620                                 Debug( LDAP_DEBUG_ANY, "do_syncrepl : "
621                                         "unknown message\n", 0, 0, 0 );
622 #endif
623                                 break;
624
625                         }
626                 }
627                 ldap_msgfree( res );
628         }
629
630         if ( rc == -1 ) {
631 #ifdef NEW_LOGGING
632                 LDAP_LOG( OPERATION, ERR,
633                         "do_syncrepl : unknown result\n", 0, 0, 0 );
634 #else
635                 Debug( LDAP_DEBUG_ANY,
636                         "do_syncrepl : unknown result\n", 0, 0, 0 );
637 #endif
638         }
639
640 done:
641         if ( syncCookie.bv_val )
642                 ch_free( syncCookie.bv_val );
643         if ( syncCookie_req.bv_val )
644                 ch_free( syncCookie_req.bv_val );
645         if ( syncUUID.bv_val )
646                 ch_free( syncUUID.bv_val );
647
648         if ( res )
649                 ldap_msgfree( res );
650
651         ldap_unbind( ld );
652
653         ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
654         ldap_pvt_runqueue_stoptask( &syncrepl_rq, rtask );
655         if ( si->type == LDAP_SYNC_REFRESH_ONLY ) {
656                 ldap_pvt_runqueue_resched( &syncrepl_rq, rtask );
657         } else {
658                 ldap_pvt_runqueue_remove( &syncrepl_rq, rtask );
659         }
660         ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
661
662         return NULL;
663 }
664
665 Entry*
666 syncrepl_message_to_entry(
667         syncinfo_t      *si,
668         LDAP            *ld,
669         Operation       *op,
670         LDAPMessage     *msg,
671         Modifications   **modlist,
672         int             *syncstate,
673         struct berval   *syncUUID,
674         struct berval   *syncCookie
675 )
676 {
677         Entry           *e;
678         BerElement      *ber = NULL;
679         BerElement      *tmpber;
680         struct berval   bv = {0, NULL};
681         Modifications   tmp;
682         Modifications   *mod;
683         Modifications   **modtail = modlist;
684         Backend         *be = op->o_bd;
685
686         const char      *text;
687         char txtbuf[SLAP_TEXT_BUFLEN];
688         size_t textlen = sizeof txtbuf;
689
690         struct berval   **bvals = NULL;
691         char            *dn;
692         struct berval   bdn = {0, NULL};
693         Attribute       *attr;
694         struct berval   empty_bv = { 0, NULL };
695         int             rc;
696         char            *a;
697
698         ber_len_t       len;
699         LDAPControl*    rctrlp;
700         LDAPControl**   rctrls = NULL;
701         BerElement*     ctrl_ber;
702
703         ber_tag_t       tag;
704
705         Modifications *ml = NULL;
706         AttributeDescription** descs;
707         int i;
708
709         *modlist = NULL;
710
711         if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
712 #ifdef NEW_LOGGING
713                 LDAP_LOG( OPERATION, ERR,
714                         "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
715 #else
716                 Debug( LDAP_DEBUG_ANY,
717                         "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
718 #endif
719                 return NULL;
720         }
721
722         op->o_tag = LDAP_REQ_ADD;
723
724         rc = ldap_get_dn_ber( ld, msg, &ber, &bdn );
725
726         if ( rc != LDAP_SUCCESS ) {
727 #ifdef NEW_LOGGING
728                 LDAP_LOG( OPERATION, ERR,
729                         "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
730 #else
731                 Debug( LDAP_DEBUG_ANY,
732                         "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
733 #endif
734                 return NULL;
735         }
736
737         e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
738         dnPrettyNormal( NULL, &bdn, &e->e_name, &e->e_nname, NULL );
739
740         e->e_attrs = NULL;
741
742         while ( ber_remaining( ber ) ) {
743                 tag = ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values );
744
745                 if ( tag == LBER_ERROR ) break;
746                 if ( tmp.sml_type.bv_val == NULL ) break;
747
748                 mod  = (Modifications *) ch_malloc( sizeof( Modifications ));
749
750                 mod->sml_op = LDAP_MOD_REPLACE;
751                 mod->sml_next = NULL;
752                 mod->sml_desc = NULL;
753                 mod->sml_type = tmp.sml_type;
754                 mod->sml_bvalues = tmp.sml_bvalues;
755                 mod->sml_nvalues = NULL;
756
757                 *modtail = mod;
758                 modtail = &mod->sml_next;
759         }
760
761         if ( ber_scanf( ber, "}") == LBER_ERROR ) {
762 #ifdef NEW_LOGGING
763                 LDAP_LOG( OPERATION, ERR,
764                                 "syncrepl_message_to_entry: ber_scanf failed\n", 0, 0, 0 );
765 #else
766                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: ber_scanf failed\n",
767                                 0, 0, 0 );
768 #endif
769                 return NULL;
770         }
771
772         ber_free( ber, 0 );
773         tmpber = ldap_get_message_ber( msg );
774         ber = ber_dup( tmpber );
775
776         ber_scanf( ber, "{xx" );
777
778         rc = ldap_int_get_controls( ber, &rctrls );
779
780         if ( rc != LDAP_SUCCESS ) {
781 #ifdef NEW_LOGGING
782                 LDAP_LOG( OPERATION, ERR,
783                         "syncrepl_message_to_entry : control get failed (%d)", rc, 0, 0 );
784 #else
785                 Debug( LDAP_DEBUG_ANY,
786                         "syncrepl_message_to_entry : control get failed (%d)", rc, 0, 0 );
787 #endif
788                 return NULL;
789         }
790
791         if ( rctrls ) {
792                 rctrlp = *rctrls;
793                 ctrl_ber = ber_alloc_t( LBER_USE_DER );
794                 ber_set_option( ctrl_ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
795                 ber_write( ctrl_ber, rctrlp->ldctl_value.bv_val, rctrlp->ldctl_value.bv_len, 0 );
796                 ber_reset( ctrl_ber, 1 );
797                 ber_scanf( ctrl_ber, "{eo", syncstate, syncUUID );
798                 if ( ber_peek_tag( ctrl_ber, &len ) == LDAP_SYNC_TAG_COOKIE ) {
799                         ber_scanf( ctrl_ber, "o}", syncCookie );
800                 }
801                 ber_free( ctrl_ber, 1 );
802         } else {
803 #ifdef NEW_LOGGING
804                 LDAP_LOG( OPERATION, ERR,"syncrepl_message_to_entry : "
805                         " rctrls absent\n", 0, 0, 0 );
806 #else
807                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry :"
808                         " rctrls absent\n", 0, 0, 0 );
809 #endif
810         }
811
812         if ( *syncstate == LDAP_SYNC_PRESENT ) {
813                 e = NULL;
814                 goto done;
815         } else if ( *syncstate == LDAP_SYNC_DELETE ) {
816                 goto done;
817         }
818
819         if ( *modlist == NULL ) {
820 #ifdef NEW_LOGGING
821                 LDAP_LOG( OPERATION, ERR,
822                                 "syncrepl_message_to_entry: no attributes\n", 0, 0, 0 );
823 #else
824                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: no attributes\n",
825                                 0, 0, 0 );
826 #endif
827         }
828
829         ml = *modlist;
830         while ( ml != NULL ) {
831                 AttributeDescription *ad = NULL;
832         rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, &text );
833
834                 if( rc != LDAP_SUCCESS ) {
835                         e = NULL;
836                         goto done;
837                 }
838
839                 ad = ml->sml_desc;
840                 ml->sml_desc = NULL;
841                 ml = ml->sml_next;
842         }
843
844         rc = slap_mods_check( *modlist, 1, &text, txtbuf, textlen, NULL );
845
846         if ( rc != LDAP_SUCCESS ) {
847 #ifdef NEW_LOGGING
848                 LDAP_LOG( OPERATION, ERR,
849                                 "syncrepl_message_to_entry: mods check (%s)\n", text, 0, 0 );
850 #else
851                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods check (%s)\n",
852                                 text, 0, 0 );
853 #endif
854                 return NULL;
855         }
856         
857         rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
858         if( rc != LDAP_SUCCESS ) {
859 #ifdef NEW_LOGGING
860                 LDAP_LOG( OPERATION, ERR,
861                                 "syncrepl_message_to_entry: mods2entry (%s)\n", text, 0, 0 );
862 #else
863                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods2entry (%s)\n",
864                                 text, 0, 0 );
865 #endif
866         }
867
868 done:
869
870         ber_free ( ber, 0 );
871
872         return e;
873 }
874
875 int
876 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
877 {
878         const struct berval *uuid1 = v_uuid1;
879         const struct berval *uuid2 = v_uuid2;
880         int rc = uuid1->bv_len - uuid2->bv_len;
881         if ( rc ) return rc;
882         return ( strcmp( uuid1->bv_val, uuid2->bv_val ) );
883 }
884
885 int
886 syncrepl_entry(
887         syncinfo_t* si,
888         LDAP *ld,
889         Operation *op,
890         Entry* e,
891         Modifications* modlist,
892         int syncstate,
893         struct berval* syncUUID,
894         struct berval* syncCookie,
895         int refresh
896 )
897 {
898         Backend *be = op->o_bd;
899         slap_callback   cb;
900         struct berval   csn_bv = {0, NULL};
901         struct berval   *syncuuid_bv = NULL;
902         char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
903
904         SlapReply       rs = {REP_RESULT};
905         int rc = LDAP_SUCCESS;
906
907         struct berval base_bv = {0, NULL};
908
909         char *filterstr;
910         Filter *filter;
911
912         Attribute *a;
913
914         if ( refresh &&
915                         ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD )) {
916                 syncuuid_bv = ber_dupbv( NULL, syncUUID );
917                 avl_insert( &si->presentlist, (caddr_t) syncuuid_bv,
918                                                 syncuuid_cmp, avl_dup_error );
919         }
920
921         if ( syncstate == LDAP_SYNC_PRESENT ) {
922                 if ( e )
923                         return 1;
924                 else
925                         return 0;
926         }
927
928         filterstr = (char *) sl_malloc( strlen("entryUUID=") + syncUUID->bv_len + 1,
929                                                                         op->o_tmpmemctx ); 
930         strcpy( filterstr, "entryUUID=" );
931         strcat( filterstr, syncUUID->bv_val );
932
933         si->e = e;
934         si->syncUUID = syncUUID;
935         si->syncUUID_ndn = NULL;
936
937         filter = str2filter( filterstr );
938         ber_str2bv( filterstr, strlen(filterstr), 1, &op->ors_filterstr );
939         ch_free( filterstr );
940         op->ors_filter = filter;
941         op->ors_scope = LDAP_SCOPE_SUBTREE;
942
943         /* get syncrepl cookie of shadow replica from subentry */
944         ber_str2bv( si->base, strlen(si->base), 1, &base_bv ); 
945         dnPrettyNormal( 0, &base_bv, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx );
946         ch_free( base_bv.bv_val );
947
948         /* set callback function */
949         op->o_callback = &cb;
950         cb.sc_response = dn_callback;
951         cb.sc_private = si;
952
953         si->syncUUID_ndn = NULL;
954
955         rc = be->be_search( op, &rs );
956
957         ch_free( op->o_req_dn.bv_val );
958         ch_free( op->o_req_ndn.bv_val );
959         filter_free( op->ors_filter );
960         ch_free( op->ors_filterstr.bv_val );
961
962         cb.sc_response = null_callback;
963         cb.sc_private = si;
964
965         if ( rc == LDAP_SUCCESS && si->syncUUID_ndn && si->sync_mode != LDAP_SYNC_LOG_MODE ) {
966                 op->o_req_dn = *si->syncUUID_ndn;
967                 op->o_req_ndn = *si->syncUUID_ndn;
968                 op->o_tag = LDAP_REQ_DELETE;
969                 rc = be->be_delete( op, &rs );
970         }
971
972         if ( si->syncUUID_ndn ) {
973                 ber_bvfree( si->syncUUID_ndn );
974         }
975
976         switch ( syncstate ) {
977         case LDAP_SYNC_ADD :
978         case LDAP_SYNC_MODIFY :
979
980                 if ( rc == LDAP_SUCCESS ||
981                          rc == LDAP_REFERRAL ||
982                          rc == LDAP_NO_SUCH_OBJECT ) {
983
984                         attr_delete( &e->e_attrs, slap_schema.si_ad_entryUUID );
985                         attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID, syncUUID, op->o_tmpmemctx );
986
987                         op->o_tag = LDAP_REQ_ADD;
988                         op->ora_e = e;
989                         op->o_req_dn = e->e_name;
990                         op->o_req_ndn = e->e_nname;
991                         rc = be->be_add( op, &rs );
992
993                         if ( rc != LDAP_SUCCESS ) {
994                                 if ( rc == LDAP_ALREADY_EXISTS ) {      
995                                         op->o_tag = LDAP_REQ_MODIFY;
996                                         op->orm_modlist = modlist;
997                                         op->o_req_dn = e->e_name;
998                                         op->o_req_ndn = e->e_nname;
999                                         rc = be->be_modify( op, &rs );
1000                                         si->e = NULL;
1001                                         if ( rc != LDAP_SUCCESS ) {
1002 #ifdef NEW_LOGGING
1003                                                 LDAP_LOG( OPERATION, ERR,
1004                                                         "syncrepl_entry : be_modify failed (%d)\n",
1005                                                         rc, 0, 0 );
1006 #else
1007                                                 Debug( LDAP_DEBUG_ANY,
1008                                                         "syncrepl_entry : be_modify failed (%d)\n",
1009                                                         rc, 0, 0 );
1010 #endif
1011                                                 return 1;
1012                                         }
1013                                         return 0;
1014                                 } else if ( rc == LDAP_REFERRAL ||
1015                                                         rc == LDAP_NO_SUCH_OBJECT ) {
1016                                         syncrepl_add_glue( si, ld, op, e,
1017                                                 modlist, syncstate,
1018                                                 syncUUID, syncCookie);
1019                                         si->e = NULL;
1020                                         return 0;
1021                                 } else {
1022 #ifdef NEW_LOGGING
1023                                         LDAP_LOG( OPERATION, ERR,
1024                                                 "syncrepl_entry : be_add failed (%d)\n",
1025                                                 rc, 0, 0 );
1026 #else
1027                                         Debug( LDAP_DEBUG_ANY,
1028                                                 "syncrepl_entry : be_add failed (%d)\n",
1029                                                 rc, 0, 0 );
1030 #endif
1031                                         si->e = NULL;
1032                                         return 1;
1033                                 }
1034                         } else {
1035                                 si->e = NULL;
1036                                 be_entry_release_w( op, e );
1037                                 return 0;
1038                         }
1039                 } else {
1040 #ifdef NEW_LOGGING
1041                         LDAP_LOG( OPERATION, ERR,
1042                                 "syncrepl_entry : be_search failed (%d)\n", rc, 0, 0 );
1043 #else
1044                         Debug( LDAP_DEBUG_ANY,
1045                                 "syncrepl_entry : be_search failed (%d)\n", rc, 0, 0 );
1046 #endif
1047                         si->e = NULL;
1048                         return 1;
1049                 }
1050
1051         case LDAP_SYNC_DELETE :
1052                 if ( si->sync_mode == LDAP_SYNC_LOG_MODE ) {
1053                         op->o_req_dn = *si->syncUUID_ndn;
1054                         op->o_req_ndn = *si->syncUUID_ndn;
1055                         op->o_tag = LDAP_REQ_DELETE;
1056                         rc = be->be_delete( op, &rs );
1057                 }
1058                 /* Already deleted otherwise */
1059                 return 1;
1060
1061         default :
1062 #ifdef NEW_LOGGING
1063                 LDAP_LOG( OPERATION, ERR,
1064                         "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1065 #else
1066                 Debug( LDAP_DEBUG_ANY,
1067                         "syncrepl_entry : unknown syncstate\n", 0, 0, 0 );
1068 #endif
1069                 return 1;
1070         }
1071 }
1072
1073 static void
1074 syncrepl_del_nonpresent(
1075         LDAP *ld,
1076         Operation *op
1077 )
1078 {
1079         Backend* be = op->o_bd;
1080         syncinfo_t *si = op->o_si;
1081         slap_callback   cb;
1082         struct berval   base_bv = {0, NULL};
1083         Filter *filter;
1084         SlapReply       rs = {REP_RESULT};
1085         struct berval   filterstr_bv = {0, NULL};
1086         struct nonpresent_entry *np_list, *np_prev;
1087
1088         ber_str2bv( si->base, strlen(si->base), 1, &base_bv ); 
1089         dnPrettyNormal(0, &base_bv, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx );
1090         ch_free( base_bv.bv_val );
1091
1092         filter = str2filter( si->filterstr );
1093
1094         cb.sc_response = nonpresent_callback;
1095         cb.sc_private = si;
1096
1097         op->o_callback = &cb;
1098         op->o_tag = LDAP_REQ_SEARCH;
1099         op->ors_scope = si->scope;
1100         op->ors_deref = LDAP_DEREF_NEVER;
1101         op->ors_slimit = 0;
1102         op->ors_tlimit = 0;
1103         op->ors_attrsonly = 0;
1104         op->ors_attrs = NULL;
1105         op->ors_filter = filter;
1106         ber_str2bv( si->filterstr, strlen( si->filterstr ), 1, &op->ors_filterstr );
1107
1108         be->be_search( op, &rs );
1109
1110         if ( !LDAP_LIST_EMPTY( &si->nonpresentlist ) ) {
1111                 np_list = LDAP_LIST_FIRST( &si->nonpresentlist );
1112                 while ( np_list != NULL ) {
1113                         LDAP_LIST_REMOVE( np_list, np_link );
1114                         np_prev = np_list;
1115                         np_list = LDAP_LIST_NEXT( np_list, np_link );
1116                         op->o_tag = LDAP_REQ_DELETE;
1117                         op->o_callback = &cb;
1118                         cb.sc_response = null_callback;
1119                         cb.sc_private = si;
1120                         op->o_req_dn = *np_prev->dn;
1121                         op->o_req_ndn = *np_prev->ndn;
1122                         op->o_bd->be_delete( op, &rs );
1123                         ber_bvfree( np_prev->dn );
1124                         ber_bvfree( np_prev->ndn );
1125                         op->o_req_dn.bv_val = NULL;
1126                         op->o_req_ndn.bv_val = NULL;
1127                         ch_free( np_prev );
1128                 }
1129         }
1130
1131         if ( op->o_req_dn.bv_val )
1132                 ch_free( op->o_req_dn.bv_val );
1133         if ( op->o_req_ndn.bv_val )
1134                 ch_free( op->o_req_ndn.bv_val );
1135         filter_free( op->ors_filter );
1136         ch_free( op->ors_filterstr.bv_val );
1137
1138         return;
1139 }
1140
1141
1142 void
1143 syncrepl_add_glue(
1144         syncinfo_t *si,
1145         LDAP *ld,
1146         Operation* op,
1147         Entry *e,
1148         Modifications* modlist,
1149         int syncstate,
1150         struct berval* syncUUID,
1151         struct berval* syncCookie
1152 )
1153 {
1154         Backend *be = op->o_bd;
1155         struct berval   uuid_bv = {0, NULL};
1156         slap_callback cb;
1157         Attribute       *a;
1158         int     rc;
1159         char    uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
1160         int levels = 0;
1161         int i, j, k;
1162         struct berval dn = {0, NULL};
1163         struct berval pdn = {0, NULL};
1164         struct berval ndn = {0, NULL};
1165         struct berval rdn = {0, NULL};
1166         Entry   *glue;
1167         SlapReply       rs = {REP_RESULT};
1168         Connection *conn = op->o_conn;
1169         char* ptr;
1170
1171         op->o_tag = LDAP_REQ_ADD;
1172         op->o_callback = &cb;
1173         cb.sc_response = null_callback;
1174         cb.sc_private = si;
1175
1176         ber_dupbv( &dn, &e->e_nname );
1177         ber_dupbv( &pdn, &e->e_nname );
1178
1179         ptr = dn.bv_val;
1180         while ( !be_issuffix ( be, &pdn )) {
1181                 dnParent( &dn, &pdn );
1182                 dn.bv_val = pdn.bv_val;
1183                 dn.bv_len = pdn.bv_len;
1184                 levels++;
1185         }
1186         ch_free( ptr );
1187
1188         for ( i = 0; i <= levels; i++ ) {
1189                 glue = (Entry*) ch_calloc( 1, sizeof(Entry) );
1190                 ber_dupbv( &dn, &e->e_nname );
1191                 j = levels - i;
1192
1193                 ptr = dn.bv_val;
1194                 for ( k = 0; k < j; k++ ) {
1195                         dnParent( &dn, &pdn );
1196                         dn.bv_val = pdn.bv_val;
1197                         dn.bv_len = pdn.bv_len;
1198                 }
1199
1200                 dnPrettyNormal( 0, &dn, &pdn, &ndn, op->o_tmpmemctx );
1201                 ber_dupbv( &glue->e_name, &pdn );
1202                 ber_dupbv( &glue->e_nname, &ndn );
1203                 ch_free( ptr );
1204                 ch_free( pdn.bv_val );
1205                 ch_free( ndn.bv_val );
1206
1207                 a = ch_calloc( 1, sizeof( Attribute ));
1208                 a->a_desc = slap_schema.si_ad_objectClass;
1209
1210                 a->a_vals = ch_calloc( 3, sizeof( struct berval ));
1211                 ber_str2bv( "top", strlen("top"), 1, &a->a_vals[0] );
1212                 ber_str2bv( "glue", strlen("glue"), 1, &a->a_vals[1] );
1213                 a->a_vals[2].bv_len = 0;
1214                 a->a_vals[2].bv_val = NULL;
1215
1216                 a->a_nvals = ch_calloc( 3, sizeof( struct berval ));
1217                 ber_str2bv( "top", strlen("top"), 1, &a->a_nvals[0] );
1218                 ber_str2bv( "glue", strlen("glue"), 1, &a->a_nvals[1] );
1219                 a->a_nvals[2].bv_len = 0;
1220                 a->a_nvals[2].bv_val = NULL;
1221
1222                 a->a_next = glue->e_attrs;
1223                 glue->e_attrs = a;
1224
1225                 a = ch_calloc( 1, sizeof( Attribute ));
1226                 a->a_desc = slap_schema.si_ad_structuralObjectClass;
1227
1228                 a->a_vals = ch_calloc( 2, sizeof( struct berval ));
1229                 ber_str2bv( "glue", strlen("glue"), 1, &a->a_vals[0] );
1230                 a->a_vals[1].bv_len = 0;
1231                 a->a_vals[1].bv_val = NULL;
1232
1233                 a->a_nvals = ch_calloc( 2, sizeof( struct berval ));
1234                 ber_str2bv( "glue", strlen("glue"), 1, &a->a_nvals[0] );
1235                 a->a_nvals[1].bv_len = 0;
1236                 a->a_nvals[1].bv_val = NULL;
1237
1238                 a->a_next = glue->e_attrs;
1239                 glue->e_attrs = a;
1240
1241                 if ( !strcmp( e->e_nname.bv_val, glue->e_nname.bv_val )) {
1242                         op->o_req_dn = e->e_name;
1243                         op->o_req_ndn = e->e_nname;
1244                         op->ora_e = e;
1245                         rc = be->be_add ( op, &rs );
1246                         if ( rc == LDAP_SUCCESS )
1247                                 be_entry_release_w( op, e );
1248                         else 
1249                                 entry_free( e );
1250                         entry_free( glue );
1251                 } else {
1252                         op->o_req_dn = glue->e_name;
1253                         op->o_req_ndn = glue->e_nname;
1254                         op->ora_e = glue;
1255                         rc = be->be_add ( op, &rs );
1256                         if ( rc == LDAP_SUCCESS ) {
1257                                 be_entry_release_w( op, glue );
1258                         } else {
1259                         /* incl. ALREADY EXIST */
1260                                 entry_free( glue );
1261                         }
1262                 }
1263         }
1264
1265         return;
1266 }
1267
1268 void
1269 syncrepl_updateCookie(
1270         syncinfo_t *si,
1271         LDAP *ld,
1272         Operation *op,
1273         struct berval *pdn,
1274         struct berval *syncCookie
1275 )
1276 {
1277         Backend *be = op->o_bd;
1278         Modifications *ml;
1279         Modifications *mlnext;
1280         Modifications *mod;
1281         Modifications *modlist;
1282         Modifications **modtail = &modlist;
1283
1284         struct berval* ocbva = NULL;
1285         struct berval* cnbva = NULL;
1286         struct berval* ssbva = NULL;
1287         struct berval* scbva = NULL;
1288
1289         char substr[64];
1290         char rdnstr[67];
1291         const char      *text;
1292         char txtbuf[SLAP_TEXT_BUFLEN];
1293         size_t textlen = sizeof txtbuf;
1294
1295         Entry* e;
1296         int rc;
1297
1298         struct berval sub_bv = { 0, NULL };
1299         struct berval psubrdn = { 0, NULL };
1300         
1301         slap_callback cb;
1302         SlapReply       rs = {REP_RESULT};
1303
1304         ocbva = ( struct berval * ) ch_calloc( 4, sizeof( struct berval ));
1305         cnbva = ( struct berval * ) ch_calloc( 2, sizeof( struct berval ));
1306         ssbva = ( struct berval * ) ch_calloc( 2, sizeof( struct berval ));
1307         scbva = ( struct berval * ) ch_calloc( 2, sizeof( struct berval ));
1308
1309         /* update in memory cookie */
1310         if ( si->syncCookie != NULL ) {
1311                 ber_bvfree( si->syncCookie );
1312         }
1313         si->syncCookie = ber_dupbv( NULL, syncCookie );
1314         ber_str2bv( "top", strlen("top"), 1, &ocbva[0] );
1315         ber_str2bv( "subentry", strlen("subentry"), 1, &ocbva[1] );
1316         ber_str2bv( "syncConsumerSubentry",
1317                         strlen("syncConsumerSubentry"), 1, &ocbva[2] );
1318         mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1319         mod->sml_op = LDAP_MOD_REPLACE;
1320         ber_str2bv( "objectClass", strlen("objectClass"), 1, &mod->sml_type );
1321         mod->sml_bvalues = ocbva;
1322         *modtail = mod;
1323         modtail = &mod->sml_next;
1324
1325         sprintf( substr, "syncrepl%d", si->id );
1326         sprintf( rdnstr, "cn=%s", substr );
1327         ber_str2bv( substr, strlen( substr ), 1, &cnbva[0] );
1328         ber_str2bv( rdnstr, strlen( rdnstr ), 1, &psubrdn );
1329         mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1330         mod->sml_op = LDAP_MOD_REPLACE;
1331         ber_str2bv( "cn", strlen("cn"), 1, &mod->sml_type );
1332         mod->sml_bvalues = cnbva;
1333         *modtail = mod;
1334         modtail = &mod->sml_next;
1335
1336         ber_dupbv( &scbva[0], si->syncCookie );
1337         mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1338         mod->sml_op = LDAP_MOD_REPLACE;
1339         ber_str2bv( "syncreplCookie", strlen("syncreplCookie"),
1340                                                 1, &mod->sml_type );
1341         mod->sml_bvalues = scbva;
1342         *modtail = mod;
1343         modtail = &mod->sml_next;
1344
1345         ber_str2bv( "{}", strlen("{}"), 1, &ssbva[0] );
1346         mod = (Modifications *) ch_calloc( 1, sizeof( Modifications ));
1347         mod->sml_op = LDAP_MOD_REPLACE;
1348         ber_str2bv( "subtreeSpecification",
1349                         strlen("subtreeSpecification"), 1, &mod->sml_type );
1350         mod->sml_bvalues = ssbva;
1351         *modtail = mod;
1352         modtail = &mod->sml_next;
1353
1354         rc = slap_mods_check( modlist, 1, &text, txtbuf, textlen, NULL );
1355
1356         if ( rc != LDAP_SUCCESS ) {
1357 #ifdef NEW_LOGGING
1358                 LDAP_LOG( OPERATION, ERR,
1359                                 "syncrepl_updateCookie: mods check (%s)\n", text, 0, 0 );
1360 #else
1361                 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods check (%s)\n",
1362                          text, 0, 0 );
1363 #endif
1364         }
1365
1366         op->o_tag = LDAP_REQ_ADD;
1367         rc = slap_mods_opattrs( op, modlist, modtail,
1368                                                          &text,txtbuf, textlen );
1369
1370         for ( ml = modlist; ml != NULL; ml = mlnext ) {
1371                 mlnext = ml->sml_next;
1372                 ml->sml_op = LDAP_MOD_REPLACE;
1373         }
1374
1375         if( rc != LDAP_SUCCESS ) {
1376 #ifdef NEW_LOGGING
1377                 LDAP_LOG( OPERATION, ERR,
1378                                 "syncrepl_updateCookie: mods opattrs (%s)\n", text, 0, 0 );
1379 #else
1380                 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods opattrs (%s)\n",
1381                          text, 0, 0 );
1382 #endif
1383         }
1384
1385         e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1386
1387         build_new_dn( &sub_bv, pdn, &psubrdn );
1388         dnPrettyNormal( NULL, &sub_bv, &e->e_name, &e->e_nname, NULL );
1389         ch_free( sub_bv.bv_val );
1390         ch_free( psubrdn.bv_val );
1391
1392         e->e_attrs = NULL;
1393
1394         rc = slap_mods2entry( modlist, &e, 1, 1, &text, txtbuf, textlen );
1395
1396         if( rc != LDAP_SUCCESS ) {
1397 #ifdef NEW_LOGGING
1398                 LDAP_LOG( OPERATION, ERR,
1399                                 "syncrepl_updateCookie: mods2entry (%s)\n", text, 0, 0 );
1400 #else
1401                 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods2entry (%s)\n",
1402                          text, 0, 0 );
1403 #endif
1404         }
1405
1406         cb.sc_response = null_callback;
1407         cb.sc_private = si;
1408
1409         op->o_callback = &cb;
1410         op->o_req_dn = e->e_name;
1411         op->o_req_ndn = e->e_nname;
1412
1413         /* update persistent cookie */
1414 update_cookie_retry:
1415         op->o_tag = LDAP_REQ_MODIFY;
1416         op->orm_modlist = modlist;
1417         rc = be->be_modify( op, &rs );
1418
1419         if ( rc != LDAP_SUCCESS ) {
1420                 if ( rc == LDAP_REFERRAL ||
1421                          rc == LDAP_NO_SUCH_OBJECT ) {
1422                         op->o_tag = LDAP_REQ_ADD;
1423                         op->ora_e = e;
1424                         rc = be->be_add( op, &rs );
1425                         if ( rc != LDAP_SUCCESS ) {
1426                                 if ( rc == LDAP_ALREADY_EXISTS ) {
1427                                         goto update_cookie_retry;
1428                                 } else if ( rc == LDAP_REFERRAL ||
1429                                                         rc == LDAP_NO_SUCH_OBJECT ) {
1430 #ifdef NEW_LOGGING
1431                                         LDAP_LOG( OPERATION, ERR,
1432                                                 "cookie will be non-persistent\n",
1433                                                 0, 0, 0 );
1434 #else
1435                                         Debug( LDAP_DEBUG_ANY,
1436                                                 "cookie will be non-persistent\n",
1437                                                 0, 0, 0 );
1438 #endif
1439                                 } else {
1440 #ifdef NEW_LOGGING
1441                                         LDAP_LOG( OPERATION, ERR,
1442                                                 "be_add failed (%d)\n",
1443                                                 rc, 0, 0 );
1444 #else
1445                                         Debug( LDAP_DEBUG_ANY,
1446                                                 "be_add failed (%d)\n",
1447                                                 rc, 0, 0 );
1448 #endif
1449                                 }
1450                         } else {
1451                                 be_entry_release_w( op, e );
1452                                 goto done;
1453                         }
1454                 } else {
1455 #ifdef NEW_LOGGING
1456                         LDAP_LOG( OPERATION, ERR,
1457                                 "be_modify failed (%d)\n", rc, 0, 0 );
1458 #else
1459                         Debug( LDAP_DEBUG_ANY,
1460                                 "be_modify failed (%d)\n", rc, 0, 0 );
1461 #endif
1462                 }
1463         }
1464
1465         if ( e != NULL )
1466                 entry_free( e );
1467
1468 done :
1469
1470         for ( ml = modlist; ml != NULL; ml = mlnext ) {
1471                 mlnext = ml->sml_next;
1472                 free( ml );
1473         }
1474
1475         return;
1476 }
1477
1478 void
1479 avl_ber_bvfree( void *bv )
1480 {
1481         if( bv == NULL ) {
1482                 return;
1483         }
1484         if ( ((struct berval *)bv)->bv_val != NULL ) {
1485                 ber_memfree ( ((struct berval *)bv)->bv_val );
1486         }
1487         ber_memfree ( (char *) bv );
1488 }
1489
1490 static int
1491 cookie_callback(
1492         Operation* op,
1493         SlapReply* rs
1494 )
1495 {
1496         syncinfo_t *si = op->o_callback->sc_private;
1497         Attribute *a;
1498
1499         if ( rs->sr_type != REP_SEARCH ) return LDAP_SUCCESS;
1500
1501         a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_syncreplCookie );
1502
1503         if ( a == NULL ) {
1504                 si->syncCookie = NULL;
1505         } else {
1506                 si->syncCookie = ber_dupbv( NULL, &a->a_vals[0] );
1507         }
1508         return LDAP_SUCCESS;
1509 }
1510
1511 static int
1512 dn_callback(
1513         Operation*      op,
1514         SlapReply*      rs
1515 )
1516 {
1517         syncinfo_t *si = op->o_callback->sc_private;
1518
1519         if ( rs->sr_type == REP_SEARCH ) {
1520                 if ( si->syncUUID_ndn != NULL ) {
1521 #ifdef NEW_LOGGING
1522                         LDAP_LOG( OPERATION, ERR,
1523                                 "dn_callback : multiple entries match dn\n", 0, 0, 0 );
1524 #else
1525                         Debug( LDAP_DEBUG_ANY,
1526                                 "dn_callback : multiple entries match dn\n", 0, 0, 0 );
1527 #endif
1528                 } else {
1529                         if ( rs->sr_entry == NULL ) {
1530                                 si->syncUUID_ndn = NULL;
1531                         } else {
1532                                 si->syncUUID_ndn = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1533                         }
1534                 }
1535         }
1536
1537         return LDAP_SUCCESS;
1538 }
1539
1540 static int
1541 nonpresent_callback(
1542         Operation*      op,
1543         SlapReply*      rs
1544 )
1545 {
1546         syncinfo_t *si = op->o_callback->sc_private;
1547         Attribute *a;
1548         int count = 0;
1549         struct berval* present_uuid = NULL;
1550         slap_callback cb;
1551         SlapReply       rs_cb = {REP_RESULT};
1552         struct nonpresent_entry *np_entry;
1553
1554         if ( rs->sr_type == REP_RESULT ) {
1555                 count = avl_free( si->presentlist, avl_ber_bvfree );
1556                 si->presentlist = NULL;
1557                 return LDAP_SUCCESS;
1558         } else if ( rs->sr_type == REP_SEARCH ) {
1559                 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
1560
1561                 if ( a == NULL )
1562                         return 0;
1563
1564                 present_uuid = avl_find( si->presentlist, &a->a_vals[0], syncuuid_cmp );
1565
1566                 if ( present_uuid == NULL ) {
1567                         np_entry = (struct nonpresent_entry *)
1568                                                 ch_calloc( 1, sizeof( struct nonpresent_entry ));
1569                         np_entry->dn = ber_dupbv( NULL, &rs->sr_entry->e_name );
1570                         np_entry->ndn = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1571                         LDAP_LIST_INSERT_HEAD( &si->nonpresentlist, np_entry, np_link );
1572                 } else {
1573                         avl_delete( &si->presentlist,
1574                                         &a->a_vals[0], syncuuid_cmp );
1575                 }
1576                 return LDAP_SUCCESS;
1577         } else {
1578                 return LDAP_SUCCESS;
1579         }
1580
1581 }
1582
1583 static int
1584 null_callback(
1585         Operation*      op,
1586         SlapReply*      rs
1587 )
1588 {
1589         syncinfo_t *si = op->o_callback->sc_private;
1590
1591         if ( rs->sr_err != LDAP_SUCCESS &&
1592                  rs->sr_err != LDAP_REFERRAL &&
1593                  rs->sr_err != LDAP_ALREADY_EXISTS &&
1594                  rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
1595 #ifdef NEW_LOGGING
1596                 LDAP_LOG( OPERATION, ERR,
1597                         "null_callback : error code 0x%x\n",
1598                         rs->sr_err, 0, 0 );
1599 #else
1600                 Debug( LDAP_DEBUG_ANY,
1601                         "null_callback : error code 0x%x\n",
1602                         rs->sr_err, 0, 0 );
1603 #endif
1604         }
1605         return LDAP_SUCCESS;
1606 }
1607
1608
1609 char **
1610 str2clist( char ***out, char *in, const char *brkstr )
1611 {
1612         char    *str;
1613         char    *s;
1614         char    *lasts;
1615         int     i, j;
1616         const char *text;
1617         char    **new;
1618
1619         /* find last element in list */
1620         for (i = 0; *out && *out[i]; i++);
1621         
1622         /* protect the input string from strtok */
1623         str = ch_strdup( in );
1624
1625         /* Count words in string */
1626         j=1;
1627         for ( s = str; *s; s++ ) {
1628                 if ( strchr( brkstr, *s ) != NULL ) {
1629                         j++;
1630                 }
1631         }
1632
1633         *out = ch_realloc( *out, ( i + j + 1 ) * sizeof( char * ) );
1634         new = *out + i;
1635         for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
1636                 s != NULL;
1637                 s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
1638         {
1639                 *new = ch_strdup( s );
1640                 new++;
1641         }
1642
1643         *new = NULL;
1644         free( str );
1645         return( *out );
1646 }