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