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