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