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