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