]> git.sur5r.net Git - openldap/blob - servers/slapd/syncrepl.c
Fix LBER_OPT_MEMCTX behavior
[openldap] / servers / slapd / syncrepl.c
1 /* $OpenLDAP$ */
2 /*
3  * Replication Engine which uses the LDAP Sync protocol
4  */
5 /* Copyright (c) 2003 by International Business Machines, Inc.
6  *
7  * International Business Machines, Inc. (hereinafter called IBM) grants
8  * permission under its copyrights to use, copy, modify, and distribute this
9  * Software with or without fee, provided that the above copyright notice and
10  * all paragraphs of this notice appear in all copies, and that the name of IBM
11  * not be used in connection with the marketing of any product incorporating
12  * the Software or modifications thereof, without specific, written prior
13  * permission.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
17  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
18  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
19  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
20  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26
27 #include <ac/string.h>
28 #include <ac/socket.h>
29 #include <db.h>
30
31 #include "ldap_pvt.h"
32 #include "lutil.h"
33 #include "slap.h"
34 #include "lutil_ldap.h"
35
36 #ifdef LDAP_SYNCREPL
37
38 #include "ldap_rq.h"
39
40 static Entry*
41 syncrepl_message_to_entry ( LDAP *, Operation *, LDAPMessage *,
42                 Modifications **, int*, struct berval *, struct berval * );
43
44 static int
45 syncrepl_entry( LDAP *, Operation*, Entry*, Modifications*,
46                 int, struct berval*, struct berval*, int );
47
48 static int
49 syncrepl_del_nonpresent( LDAP *, Operation * );
50
51 static void
52 syncrepl_add_glue( LDAP *, Operation*, Entry*, Modifications*, int,
53                    struct berval*, struct berval* );
54
55 static void
56 syncrepl_updateCookie( LDAP *, Operation *, struct berval *, struct berval * );
57
58 static int
59 slap_mods_check_syncrepl( Operation *, Modifications **,
60                           const char **, char *, size_t, void *ctx );
61
62 static int
63 slap_mods_opattrs_syncrepl( Operation *, Modifications *, Modifications **,
64                                 const char **, char *, size_t );
65
66 static int
67 slap_mods2entry_syncrepl( Modifications *, Entry **, int,
68                           const char **, char *, size_t );
69
70 /* callback functions */
71 static int cookie_callback( struct slap_op *, struct slap_rep * );
72 static int dn_callback( struct slap_op *, struct slap_rep * );
73 static int nonpresent_callback( struct slap_op *, struct slap_rep * );
74 static int null_callback( struct slap_op *, struct slap_rep * );
75
76 static AttributeDescription **add_descs;
77 static AttributeDescription **add_descs_lastmod;
78 static AttributeDescription **del_descs;
79 static AttributeDescription **del_descs_lastmod;
80
81 struct runqueue_s syncrepl_rq;
82
83 void
84 init_syncrepl()
85 {
86         add_descs = ch_malloc( 2 * sizeof( AttributeDescription * ));
87         add_descs[0] = slap_schema.si_ad_objectClass;
88         add_descs[1] = NULL;
89
90         add_descs_lastmod = ch_malloc( 7 * sizeof( AttributeDescription * ));
91         add_descs_lastmod[0] = slap_schema.si_ad_objectClass;
92         add_descs_lastmod[1] = slap_schema.si_ad_creatorsName;
93         add_descs_lastmod[2] = slap_schema.si_ad_modifiersName;
94         add_descs_lastmod[3] = slap_schema.si_ad_createTimestamp;
95         add_descs_lastmod[4] = slap_schema.si_ad_modifyTimestamp;
96         add_descs_lastmod[5] = slap_schema.si_ad_entryCSN;
97         add_descs_lastmod[6] = NULL;
98
99         del_descs = ch_malloc( 9 * sizeof( AttributeDescription * ));
100         del_descs[0] = slap_schema.si_ad_structuralObjectClass;
101         del_descs[1] = slap_schema.si_ad_subschemaSubentry;
102         del_descs[2] = slap_schema.si_ad_hasSubordinates;
103         del_descs[3] = slap_schema.si_ad_creatorsName;
104         del_descs[4] = slap_schema.si_ad_modifiersName;
105         del_descs[5] = slap_schema.si_ad_createTimestamp;
106         del_descs[6] = slap_schema.si_ad_modifyTimestamp;
107         del_descs[7] = slap_schema.si_ad_entryCSN;
108         del_descs[8] = NULL;
109
110         del_descs_lastmod = ch_malloc( 4 * sizeof( AttributeDescription * ));
111         del_descs_lastmod[0] = slap_schema.si_ad_structuralObjectClass;
112         del_descs_lastmod[1] = slap_schema.si_ad_subschemaSubentry;
113         del_descs_lastmod[2] = slap_schema.si_ad_hasSubordinates;
114         del_descs_lastmod[3] = NULL;
115 }
116
117 void *
118 do_syncrepl(
119         void    *ctx,
120         void    *arg )
121 {
122         struct re_s* rtask = arg;
123         Backend *be = rtask->arg;
124         syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
125
126         SlapReply       rs = {REP_RESULT};
127
128         LDAPControl     c[2];
129         LDAPControl     **sctrls = NULL;
130         LDAPControl     **rctrls = NULL;
131         LDAPControl     *rctrlp = NULL;
132         BerElement      *sync_ber = NULL;
133         struct berval   *sync_bvalp = NULL;
134
135         BerElement      *ctrl_ber = NULL;
136         BerElement      *res_ber = NULL;
137
138         LDAP    *ld = NULL;
139         LDAPMessage     *res = NULL;
140         LDAPMessage     *msg = NULL;
141
142         ber_int_t       msgid;
143
144         int             nresponses, nreferences, nextended, npartial;
145         int             nresponses_psearch;
146
147         int             cancel_msgid = -1;
148         char            *retoid = NULL;
149         struct berval   *retdata = NULL;
150
151         int             sync_info_arrived = 0;
152         Entry           *entry = NULL;
153
154         int             syncstate;
155         struct berval   syncUUID = { 0, NULL };
156         struct berval   syncCookie = { 0, NULL };
157
158         int     rc;
159         int     err;
160         ber_len_t       len;
161         int     syncinfo_arrived = 0;
162         int     cancel_response = 0;
163
164         char **tmp = NULL;
165         AttributeDescription** descs = NULL;
166
167         Connection conn;
168         Operation op = {0};
169         slap_callback   cb;
170
171         void *memctx = NULL;
172         ber_len_t memsiz;
173         
174         int i, j, k, n;
175         int rc_efree;
176
177         struct berval base_bv = { 0, NULL };
178         struct berval pbase = { 0, NULL };
179         struct berval nbase = { 0, NULL };
180         struct berval sub_bv = { 0, NULL };
181         struct berval psubrdn = { 0, NULL };
182         struct berval nsubrdn = { 0, NULL };
183         struct berval psub = { 0, NULL };
184         struct berval nsub = { 0, NULL };
185         char substr[64];
186         Modifications   *modlist = NULL;
187         Modifications   *ml, *mlnext;
188         char *def_filter_str = NULL;
189
190 #ifdef NEW_LOGGING
191         LDAP_LOG ( OPERATION, DETAIL1, "do_syncrepl\n", 0, 0, 0 );
192 #else
193         Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl\n", 0, 0, 0 );
194 #endif
195
196         if ( si == NULL )
197                 return NULL;
198
199         if ( abs(si->type) != LDAP_SYNC_REFRESH_ONLY &&
200              abs(si->type) != LDAP_SYNC_REFRESH_AND_PERSIST ) {
201                 return NULL;
202         }
203
204         /* Init connection to master */
205
206         if ( ldap_is_ldap_url( si->masteruri )) {
207                 rc = ldap_initialize( &ld, si->masteruri );
208                 if ( rc != LDAP_SUCCESS ) {
209 #ifdef NEW_LOGGING
210                         LDAP_LOG( OPERATION, ERR, "do_syncrepl: "
211                                 "ldap_initialize failed (%s)\n",
212                                 si->masteruri, 0, 0 );
213 #else
214                         Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
215                                 "ldap_initialize failed (%s)\n",
216                                 si->masteruri, 0, 0 );
217 #endif
218                 }
219         } else {
220                 ld = ldap_init( si->mastername, si->masterport );
221                 if ( ld == NULL ) {
222 #ifdef NEW_LOGGING
223                         LDAP_LOG( OPERATION, ERR, "do_syncrepl: "
224                                 "ldap_init failed (%s:%d)\n",
225                                 si->mastername, si->masterport, 0 );
226 #else
227                         Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
228                                 "ldap_init failed (%s:%d)\n",
229                                 si->mastername, si->masterport, 0 );
230 #endif
231                 }
232         }
233
234         op.o_protocol = LDAP_VERSION3;
235         ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &op.o_protocol );
236
237         /* Bind to master */
238
239         if ( si->tls ) {
240                 rc = ldap_start_tls_s( ld, NULL, NULL );
241                 if( rc != LDAP_SUCCESS ) {
242 #ifdef NEW_LOGGING
243                         LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
244                                 "%s: ldap_start_tls failed (%d)\n",
245                                 si->tls == TLS_CRITICAL ? "Error" : "Warning",
246                                 rc, 0 );
247 #else
248                         Debug( LDAP_DEBUG_ANY,
249                                 "%s: ldap_start_tls failed (%d)\n",
250                                 si->tls == TLS_CRITICAL ? "Error" : "Warning",
251                                 rc, 0 );
252 #endif
253                         if( si->tls == TLS_CRITICAL )
254                                 return NULL;
255                 }
256         }
257
258         if ( si->bindmethod == LDAP_AUTH_SASL ) {
259 #ifdef HAVE_CYRUS_SASL
260                 void *defaults;
261
262                 if ( si->secprops != NULL ) {
263                         int err = ldap_set_option( ld,
264                                         LDAP_OPT_X_SASL_SECPROPS, si->secprops);
265
266                         if( err != LDAP_OPT_SUCCESS ) {
267 #ifdef NEW_LOGGING
268                                 LDAP_LOG ( OPERATION, ERR, "do_bind: Error: "
269                                         "ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
270                                         si->mastername, si->secprops, 0 );
271 #else
272                                 Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
273                                         "(%s,SECPROPS,\"%s\") failed!\n",
274                                         si->mastername, si->secprops, NULL );
275 #endif
276                                 return NULL;
277                         }
278                 }
279
280                 defaults = lutil_sasl_defaults( ld,
281                                 si->saslmech,
282                                 si->realm,
283                                 si->authcId,
284                                 si->passwd,
285                                 si->authzId );
286
287                 rc = ldap_sasl_interactive_bind_s( ld,
288                                 si->binddn,
289                                 si->saslmech,
290                                 NULL, NULL,
291                                 LDAP_SASL_AUTOMATIC,
292                                 lutil_sasl_interact,
293                                 defaults );
294
295                 if ( rc != LDAP_SUCCESS ) {
296 #ifdef NEW_LOGGING
297                         LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
298                                 "ldap_sasl_interactive_bind_s failed (%d)\n",
299                                 rc, 0, 0 );
300 #else
301                         Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
302                                 "ldap_sasl_interactive_bind_s failed (%d)\n",
303                                 rc, 0, 0 );
304 #endif
305                         return NULL;
306                 }
307 #else /* HAVE_CYRUS_SASL */
308                 fprintf( stderr, "not compiled with SASL support\n" );
309                 return NULL;
310 #endif
311         } else {
312                 rc = ldap_bind_s( ld, si->binddn, si->passwd, si->bindmethod );
313                 if ( rc != LDAP_SUCCESS ) {
314 #ifdef NEW_LOGGING
315                         LDAP_LOG ( OPERATION, ERR, "do_syncrepl: "
316                                 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
317 #else
318                         Debug( LDAP_DEBUG_ANY, "do_syncrepl: "
319                                 "ldap_bind_s failed (%d)\n", rc, 0, 0 );
320 #endif
321                         return NULL;
322                 }
323         }
324
325         si->ctx = ctx;
326
327         op.o_tmpmemctx = NULL; /* FIXME : to use per-thread mem context */
328         op.o_tmpmfuncs = &ch_mfuncs;
329         op.o_tag = LDAP_REQ_SEARCH;
330         op.o_dn = si->updatedn;
331         op.o_ndn = si->updatedn;
332         op.o_callback = &cb;
333         op.o_time = slap_get_time();
334         op.o_managedsait = 1;
335         op.o_threadctx = si->ctx;
336         op.o_bd = be;
337         op.o_conn = &conn;
338         op.o_connid = op.o_conn->c_connid;
339         op.ors_scope = LDAP_SCOPE_BASE;
340         op.ors_deref = LDAP_DEREF_NEVER;
341         op.ors_slimit = -1;
342         op.ors_tlimit = -1;
343         op.ors_attrsonly = 0;
344         op.ors_attrs = NULL;
345         op.ors_filter = str2filter( def_filter_str = "(objectClass=*)" );
346         ber_str2bv( def_filter_str, strlen( def_filter_str ), 1,
347                                 &op.ors_filterstr );
348
349         si->conn = &conn;
350         conn.c_send_ldap_result = slap_send_ldap_result;
351         conn.c_send_search_entry = slap_send_search_entry;
352         conn.c_send_search_reference = slap_send_search_reference;
353
354         /* get syncrepl cookie of shadow replica from subentry */
355         ber_str2bv( si->base, strlen(si->base), 1, &base_bv ); 
356         dnPrettyNormal( 0, &base_bv, &pbase, &nbase, op.o_tmpmemctx );
357
358         sprintf( substr, "cn=syncrepl%d", si->id );
359         ber_str2bv( substr, strlen(substr), 1, &sub_bv );
360         dnPrettyNormal( 0, &sub_bv, &psubrdn, &nsubrdn, op.o_tmpmemctx );
361
362         build_new_dn( &op.o_req_dn, &pbase, &psubrdn );
363         build_new_dn( &op.o_req_ndn, &nbase, &nsubrdn );
364
365         ch_free( base_bv.bv_val );
366         ch_free( pbase.bv_val );
367         ch_free( nbase.bv_val );
368         ch_free( sub_bv.bv_val );
369         ch_free( psubrdn.bv_val );
370         ch_free( nsubrdn.bv_val );
371
372         /* set callback function */
373         cb.sc_response = cookie_callback;
374         cb.sc_private = si;
375
376         /* search subentry to retrieve cookie */
377         si->syncCookie = NULL;
378         be->be_search( &op, &rs );
379
380         ch_free( op.o_req_dn.bv_val );
381         ch_free( op.o_req_ndn.bv_val );
382         filter_free( op.ors_filter );
383         ch_free( op.ors_filterstr.bv_val );
384
385         psub = be->be_nsuffix[0];
386
387         /* setup LDAP SYNC control */
388         sync_ber = ber_alloc_t( LBER_USE_DER );
389         ber_set_option( sync_ber, LBER_OPT_BER_MEMCTX, &op.o_tmpmemctx );
390
391         if ( si->syncCookie ) {
392                 ber_printf( sync_ber, "{eO}", abs(si->type), si->syncCookie );
393         } else {
394                 ber_printf( sync_ber, "{e}", abs(si->type) );
395         }
396
397         if ( ber_flatten( sync_ber, &sync_bvalp ) == LBER_ERROR ) {
398                 ber_free( sync_ber, 1 );
399                 return NULL;
400         }
401         ber_free( sync_ber, 1 );
402
403         sctrls = (LDAPControl**) sl_calloc( 3, sizeof(LDAPControl*), op.o_tmpmemctx );
404
405         c[0].ldctl_oid = LDAP_CONTROL_SYNC;
406         c[0].ldctl_value = (*sync_bvalp);
407         c[0].ldctl_iscritical = si->type < 0;
408         sctrls[0] = &c[0];
409
410         if ( si->authzId ) {
411                 c[1].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
412                 c[1].ldctl_value.bv_val = si->authzId;
413                 c[1].ldctl_value.bv_len = strlen( si->authzId );
414                 c[1].ldctl_iscritical = 1;
415                 sctrls[1] = &c[1];
416         } else {
417                 sctrls[1] = NULL;
418         }
419
420         sctrls[2] = NULL;
421
422         err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, sctrls );
423
424         ber_bvfree( sync_bvalp );
425         ch_free( sctrls );
426
427         if ( err != LDAP_OPT_SUCCESS )
428                 fprintf( stderr, "Could not set controls : %d\n", err );
429
430         /* Delete Attributes */
431         if ( si->lastmod == LASTMOD_REQ ) {
432                 descs = del_descs_lastmod;
433         } else {
434                 descs = del_descs;
435         }
436
437         for ( i = 0; descs[i] != NULL; i++ ) {
438                 for ( j = 0; si->attrs[j] != NULL; j++ ) {
439                         if ( !strcmp( si->attrs[j], descs[i]->ad_cname.bv_val )) {
440                                 ch_free( si->attrs[j] );
441                                 for ( k = j; si->attrs[k] != NULL; k++ ) {
442                                         si->attrs[k] = si->attrs[k+1];
443                                 }
444                         }
445                 }
446         }
447
448         /* Add Attributes */
449
450         for ( n = 0; si->attrs[ n ] != NULL; n++ ) ;
451         
452         if ( si->lastmod == LASTMOD_REQ ) {
453                 descs = add_descs_lastmod;
454         } else {
455                 descs = add_descs;
456         }
457
458         for ( i = 0; descs[i] != NULL; i++ ) {
459                 tmp = ( char ** ) ch_realloc( si->attrs,
460                                 ( n + 2 ) * sizeof( char * ));
461                 if ( tmp == NULL ) {
462 #ifdef NEW_LOGGING
463                         LDAP_LOG( OPERATION, ERR, "out of memory\n", 0,0,0 );
464 #else
465                         Debug( LDAP_DEBUG_ANY, "out of memory\n", 0,0,0 );
466 #endif
467                 }
468                 si->attrs = tmp;
469                 si->attrs[ n++ ] = ch_strdup ( descs[i]->ad_cname.bv_val );
470                 si->attrs[ n ] = NULL;
471         }
472
473         /* Send LDAP SYNC search */
474
475         rc = ldap_search_ext( ld, si->base, si->scope, si->filterstr,
476                                 si->attrs, si->attrsonly, NULL, NULL,
477                                 NULL, -1, &msgid );
478
479         if( rc != LDAP_SUCCESS ) {
480                 fprintf( stderr, "syncrepl: ldap_search_ext: %s (%d)\n",
481                                         ldap_err2string( rc ), rc );
482                 return NULL;
483         }
484
485         while (( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res )) > 0 ) {
486
487                 for ( msg = ldap_first_message( ld, res );
488                       msg != NULL;
489                       msg = ldap_next_message( ld, msg ) )
490                 {
491                         switch( ldap_msgtype( msg ) ) {
492                         case LDAP_RES_SEARCH_ENTRY:
493                                 entry = syncrepl_message_to_entry( ld, &op, msg,
494                                         &modlist, &syncstate, &syncUUID, &syncCookie );
495                                 rc_efree = syncrepl_entry( ld, &op, entry, modlist,
496                                                 syncstate, &syncUUID, &syncCookie, !syncinfo_arrived );
497                                 if ( syncCookie.bv_len ) {
498                                         syncrepl_updateCookie( ld, &op, &psub, &syncCookie );
499                                 }
500                                 if ( rc_efree )
501                                         entry_free( entry );
502                                 for ( ml = modlist; ml != NULL; ml = mlnext ) {
503                                         mlnext = ml->sml_next;
504                                         ber_memfree( ml );
505                                 }
506                                 break;
507
508                         case LDAP_RES_SEARCH_REFERENCE:
509 #ifdef NEW_LOGGING
510                                 LDAP_LOG( OPERATION, ERR,
511                                         "do_syncrepl : reference received\n", 0, 0, 0 );
512 #else
513                                 Debug( LDAP_DEBUG_ANY,
514                                         "do_syncrepl : reference received\n", 0, 0, 0 );
515 #endif
516                                 break;
517
518                         case LDAP_RES_SEARCH_RESULT:
519                                 ldap_parse_result( ld, msg, &err, NULL, NULL, NULL, &rctrls, 0 );
520                                 if ( rctrls ) {
521                                         rctrlp = *rctrls;
522                                         ctrl_ber = ber_alloc_t( LBER_USE_DER );
523                                         ber_set_option( ctrl_ber, LBER_OPT_BER_MEMCTX, &op.o_tmpmemctx );
524                                         ber_write( ctrl_ber, rctrlp->ldctl_value.bv_val, rctrlp->ldctl_value.bv_len, 0 );
525                                         ber_reset( ctrl_ber, 1 );
526
527                                         ber_scanf( ctrl_ber, "{" );
528                                         if ( ber_peek_tag( ctrl_ber, &len )
529                                                 == LDAP_SYNC_TAG_COOKIE ) {
530                                                 ber_scanf( ctrl_ber, "o", &syncCookie );
531                                         }
532                                 }
533                                 if (si->type == LDAP_SYNC_REFRESH_AND_PERSIST) {
534                                         if ( cancel_response ) {
535                                                 if ( syncCookie.bv_len ) {
536                                                         ber_bvfree( si->syncCookie );
537                                                         si->syncCookie = ber_dupbv( NULL, &syncCookie );
538                                                 }
539                                                 if ( ctrl_ber )
540                                                         ber_free( ctrl_ber, 1 );
541                                                 goto done;
542                                         }
543                                         else {
544                                                 if ( ctrl_ber )
545                                                         ber_free( ctrl_ber, 1 );
546                                                 break;
547                                         }
548                                 } else {
549                                         if ( syncCookie.bv_len ) {
550                                                 syncrepl_updateCookie( ld, &op, &psub, &syncCookie );
551                                         }
552                                         syncrepl_del_nonpresent( ld, &op );
553                                         if ( ctrl_ber )
554                                                 ber_free( ctrl_ber, 1 );
555                                         goto done;
556                                 }
557                                 break;
558
559                         case LDAP_RES_INTERMEDIATE_RESP:
560                                 ldap_parse_intermediate_resp_result( ld, msg,
561                                                 &retoid, &retdata, 0 );
562                                 if ( !strcmp( retoid, LDAP_SYNC_INFO ) ) {
563                                         sync_info_arrived = 1;
564                                         res_ber = ber_init( retdata );
565                                         ber_scanf( res_ber, "{e", &syncstate );
566
567                                         if ( syncstate == LDAP_SYNC_REFRESH_DONE ) {
568                                                 syncrepl_del_nonpresent( ld, &op );
569                                         } else if ( syncstate != LDAP_SYNC_NEW_COOKIE ) {
570 #ifdef NEW_LOGGING
571                                                 LDAP_LOG( OPERATION, ERR,
572                                                         "do_syncrepl : unknown sync info\n", 0, 0, 0 );
573 #else
574                                                 Debug( LDAP_DEBUG_ANY,
575                                                         "do_syncrepl : unknown sync info\n", 0, 0, 0 );
576 #endif
577                                         }
578
579                                         if ( ber_peek_tag( res_ber, &len )
580                                                                 == LDAP_SYNC_TAG_COOKIE ) {
581                                                 ber_scanf( res_ber, "o}", &syncCookie );
582                                                 if ( syncCookie.bv_len ) {
583                                                         ber_bvfree( si->syncCookie );
584                                                         si->syncCookie = ber_dupbv( NULL, &syncCookie );
585                                                 }
586                                         } else {
587                                                 if ( syncstate == LDAP_SYNC_NEW_COOKIE ) {
588 #ifdef NEW_LOGGING
589                                                         LDAP_LOG( OPERATION, ERR,
590                                                                 "do_syncrepl : cookie required\n", 0, 0, 0 );
591 #else
592                                                         Debug( LDAP_DEBUG_ANY,
593                                                                 "do_syncrepl : cookie required\n", 0, 0, 0 );
594 #endif
595                                                 }
596                                         }
597
598                                         ldap_memfree( retoid );
599                                         ber_bvfree( retdata );
600                                         ber_free( res_ber, 1 );
601                                         break;
602                                 } else {
603 #ifdef NEW_LOGGING
604                                         LDAP_LOG( OPERATION, ERR,"do_syncrepl :"
605                                                 " unknown intermediate "
606                                                 "response\n", 0, 0, 0 );
607 #else
608                                         Debug( LDAP_DEBUG_ANY, "do_syncrepl : "
609                                                 "unknown intermediate "
610                                                 "response\n", 0, 0, 0 );
611 #endif
612                                         ldap_memfree( retoid );
613                                         ber_bvfree( retdata );
614                                         break;
615                                 }
616                                 break;
617                         default:
618 #ifdef NEW_LOGGING
619                                 LDAP_LOG( OPERATION, ERR, "do_syncrepl : "
620                                         "unknown message\n", 0, 0, 0 );
621 #else
622                                 Debug( LDAP_DEBUG_ANY, "do_syncrepl : "
623                                         "unknown message\n", 0, 0, 0 );
624 #endif
625                                 break;
626
627                         }
628                 }
629                 ldap_msgfree( res );
630         }
631
632         if ( rc == -1 ) {
633 #ifdef NEW_LOGGING
634                 LDAP_LOG( OPERATION, ERR,
635                         "do_syncrepl : unknown result\n", 0, 0, 0 );
636 #else
637                 Debug( LDAP_DEBUG_ANY,
638                         "do_syncrepl : unknown result\n", 0, 0, 0 );
639 #endif
640         }
641
642 done:
643         if ( syncCookie.bv_val )
644                 ch_free( syncCookie.bv_val );
645         if ( syncUUID.bv_val )
646                 ch_free( syncUUID.bv_val );
647
648         if ( res )
649                 ldap_msgfree( res );
650         ldap_unbind( ld );
651
652         ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
653         ldap_pvt_runqueue_stoptask( &syncrepl_rq, rtask );
654         if ( si->type == LDAP_SYNC_REFRESH_ONLY ) {
655                 ldap_pvt_runqueue_resched( &syncrepl_rq, rtask );
656         } else {
657                 ldap_pvt_runqueue_remove( &syncrepl_rq, rtask );
658         }
659         ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
660
661         return NULL;
662 }
663
664 static Entry*
665 syncrepl_message_to_entry(
666         LDAP            *ld,
667         Operation       *op,
668         LDAPMessage     *msg,
669         Modifications   **modlist,
670         int             *syncstate,
671         struct berval   *syncUUID,
672         struct berval   *syncCookie
673 )
674 {
675         Entry           *e;
676         BerElement      *ber = NULL;
677         BerElement      *tmpber;
678         struct berval   bv = {0, NULL};
679         Modifications   tmp;
680         Modifications   *mod;
681         Modifications   **modtail = modlist;
682         Backend         *be = op->o_bd;
683
684         const char      *text;
685         char txtbuf[SLAP_TEXT_BUFLEN];
686         size_t textlen = sizeof txtbuf;
687
688         struct berval   **bvals = NULL;
689         char            *dn;
690         struct berval   bdn = {0, NULL};
691         Attribute       *attr;
692         struct berval   empty_bv = { 0, NULL };
693         int             rc;
694         char            *a;
695
696         syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
697
698         ber_len_t       len;
699         LDAPControl*    rctrlp;
700         LDAPControl**   rctrls = NULL;
701         BerElement*     ctrl_ber;
702
703         ber_tag_t       tag;
704
705         *modlist = NULL;
706
707         if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
708 #ifdef NEW_LOGGING
709                 LDAP_LOG( OPERATION, ERR,
710                         "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
711 #else
712                 Debug( LDAP_DEBUG_ANY,
713                         "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 );
714 #endif
715                 return NULL;
716         }
717
718         op->o_tag = LDAP_REQ_ADD;
719
720         rc = ldap_get_dn_ber( ld, msg, &ber, &bdn );
721
722         if ( rc != LDAP_SUCCESS ) {
723 #ifdef NEW_LOGGING
724                 LDAP_LOG( OPERATION, ERR,
725                         "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
726 #else
727                 Debug( LDAP_DEBUG_ANY,
728                         "syncrepl_message_to_entry : dn get failed (%d)", rc, 0, 0 );
729 #endif
730                 return NULL;
731         }
732
733         e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
734         dnPrettyNormal( NULL, &bdn, &e->e_name, &e->e_nname, op->o_tmpmemctx );
735
736         e->e_attrs = NULL;
737
738         while ( ber_remaining( ber ) ) {
739                 tag = ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values );
740
741                 if ( tag == LBER_ERROR ) break;
742                 if ( tmp.sml_type.bv_val == NULL ) break;
743
744                 mod  = (Modifications *) ch_malloc( sizeof( Modifications ));
745
746                 mod->sml_op = LDAP_MOD_REPLACE;
747                 mod->sml_next = NULL;
748                 mod->sml_desc = NULL;
749                 mod->sml_type = tmp.sml_type;
750                 mod->sml_bvalues = tmp.sml_bvalues;
751                 mod->sml_nvalues = tmp.sml_bvalues;
752
753                 *modtail = mod;
754                 modtail = &mod->sml_next;
755         }
756
757         if ( ber_scanf( ber, "}") == LBER_ERROR ) {
758 #ifdef NEW_LOGGING
759                 LDAP_LOG( OPERATION, ERR,
760                                 "syncrepl_message_to_entry: ber_scanf failed\n", 0, 0, 0 );
761 #else
762                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: ber_scanf failed\n",
763                                 0, 0, 0 );
764 #endif
765                 return NULL;
766         }
767
768         ber_free( ber, 0 );
769         tmpber = ldap_get_message_ber( msg );
770         ber = ber_dup( tmpber );
771
772         ber_scanf( ber, "{xx" );
773
774         rc = ldap_int_get_controls( ber, &rctrls );
775
776         if ( rc != LDAP_SUCCESS ) {
777 #ifdef NEW_LOGGING
778                 LDAP_LOG( OPERATION, ERR,
779                         "syncrepl_message_to_entry : control get failed (%d)", rc, 0, 0 );
780 #else
781                 Debug( LDAP_DEBUG_ANY,
782                         "syncrepl_message_to_entry : control get failed (%d)", rc, 0, 0 );
783 #endif
784                 return NULL;
785         }
786
787         if ( rctrls ) {
788                 rctrlp = *rctrls;
789                 ctrl_ber = ber_alloc_t( LBER_USE_DER );
790                 ber_set_option( ctrl_ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
791                 ber_write( ctrl_ber, rctrlp->ldctl_value.bv_val, rctrlp->ldctl_value.bv_len, 0 );
792                 ber_reset( ctrl_ber, 1 );
793                 ber_scanf( ctrl_ber, "{eo", syncstate, syncUUID );
794                 if ( ber_peek_tag( ctrl_ber, &len ) == LDAP_SYNC_TAG_COOKIE ) {
795                         ber_scanf( ctrl_ber, "o}", syncCookie );
796                 }
797                 ber_free( ctrl_ber, 1 );
798         } else {
799 #ifdef NEW_LOGGING
800                 LDAP_LOG( OPERATION, ERR,"syncrepl_message_to_entry : "
801                         " rctrls absent\n", 0, 0, 0 );
802 #else
803                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry :"
804                         " rctrls absent\n", 0, 0, 0 );
805 #endif
806         }
807
808         if ( *syncstate == LDAP_SYNC_PRESENT ) {
809                 e = NULL;
810                 goto done;
811         } else if ( *syncstate == LDAP_SYNC_DELETE ) {
812                 goto done;
813         }
814
815         if ( *modlist == NULL ) {
816 #ifdef NEW_LOGGING
817                 LDAP_LOG( OPERATION, ERR,
818                                 "syncrepl_message_to_entry: no attributes\n", 0, 0, 0 );
819 #else
820                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: no attributes\n",
821                                 0, 0, 0 );
822 #endif
823         }
824
825         rc = slap_mods_check_syncrepl( op, modlist, &text, txtbuf, textlen, NULL );
826
827         if ( rc != LDAP_SUCCESS ) {
828 #ifdef NEW_LOGGING
829                 LDAP_LOG( OPERATION, ERR,
830                                 "syncrepl_message_to_entry: mods check (%s)\n", text, 0, 0 );
831 #else
832                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods check (%s)\n",
833                                 text, 0, 0 );
834 #endif
835                 return NULL;
836         }
837         
838         rc = slap_mods_opattrs_syncrepl( op, *modlist, modtail,
839                                          &text,txtbuf, textlen );
840         
841         if( rc != LDAP_SUCCESS ) {
842 #ifdef NEW_LOGGING
843                 LDAP_LOG( OPERATION, ERR,
844                                 "syncrepl_message_to_entry: mods opattrs (%s)\n", text, 0, 0 );
845 #else
846                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods opattrs (%s)\n",
847                                 text, 0, 0 );
848 #endif
849                 return NULL;
850         }
851
852         rc = slap_mods2entry_syncrepl( *modlist, &e, 1, &text, txtbuf, textlen );
853         if( rc != LDAP_SUCCESS ) {
854 #ifdef NEW_LOGGING
855                 LDAP_LOG( OPERATION, ERR,
856                                 "syncrepl_message_to_entry: mods2entry (%s)\n", text, 0, 0 );
857 #else
858                 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: mods2entry (%s)\n",
859                                 text, 0, 0 );
860 #endif
861         }
862
863 done:
864
865         ber_free ( ber, 0 );
866
867         return e;
868 }
869
870 int
871 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
872 {
873         const struct berval *uuid1 = v_uuid1;
874         const struct berval *uuid2 = v_uuid2;
875         int rc = uuid1->bv_len - uuid2->bv_len;
876         if ( rc ) return rc;
877         return ( strcmp( uuid1->bv_val, uuid2->bv_val ) );
878 }
879
880 static int
881 syncrepl_entry(
882         LDAP *ld,
883         Operation *op,
884         Entry* e,
885         Modifications* modlist,
886         int syncstate,
887         struct berval* syncUUID,
888         struct berval* syncCookie,
889         int refresh
890 )
891 {
892         Backend *be = op->o_bd;
893         syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
894         slap_callback   cb;
895         struct berval   csn_bv = {0, NULL};
896         struct berval   *syncuuid_bv = NULL;
897         char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
898
899         SlapReply       rs = {REP_RESULT};
900         int rc = LDAP_SUCCESS;
901
902         struct berval base_bv = {0, NULL};
903
904         char *filterstr;
905         Filter *filter;
906
907         Attribute *a;
908
909         if ( refresh &&
910                         ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD )) {
911                 syncuuid_bv = ber_dupbv( NULL, syncUUID );
912                 avl_insert( &si->presentlist, (caddr_t) syncuuid_bv,
913                                                 syncuuid_cmp, avl_dup_error );
914         }
915
916         if ( syncstate == LDAP_SYNC_PRESENT ) {
917                 if ( e )
918                         return 1;
919                 else
920                         return 0;
921         }
922
923         filterstr = (char *) sl_malloc( strlen("entryUUID=") + syncUUID->bv_len + 1,
924                                                                         op->o_tmpmemctx ); 
925         strcpy( filterstr, "entryUUID=" );
926         strcat( filterstr, syncUUID->bv_val );
927
928         si->e = e;
929         si->syncUUID = syncUUID;
930         si->syncUUID_ndn = NULL;
931
932         filter = str2filter( filterstr );
933         ber_str2bv( filterstr, strlen(filterstr), 1, &op->ors_filterstr );
934         ch_free( filterstr );
935         op->ors_filter = filter;
936         op->ors_scope = LDAP_SCOPE_SUBTREE;
937
938         /* get syncrepl cookie of shadow replica from subentry */
939         ber_str2bv( si->base, strlen(si->base), 1, &base_bv ); 
940         dnPrettyNormal( 0, &base_bv, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx );
941         ch_free( base_bv.bv_val );
942
943         /* set callback function */
944         op->o_callback = &cb;
945         cb.sc_response = dn_callback;
946         cb.sc_private = si;
947
948         be->be_search( op, &rs );
949
950         ch_free( op->o_req_dn.bv_val );
951         ch_free( op->o_req_ndn.bv_val );
952         filter_free( op->ors_filter );
953         ch_free( op->ors_filterstr.bv_val );
954
955         cb.sc_response = null_callback;
956
957         rc = LDAP_SUCCESS;
958
959         if ( si->syncUUID_ndn ) {
960                 op->o_req_dn = *si->syncUUID_ndn;
961                 op->o_req_ndn = *si->syncUUID_ndn;
962                 op->o_tag = LDAP_REQ_DELETE;
963                 rc = be->be_delete( op, &rs );
964         }
965
966         switch ( syncstate ) {
967         case LDAP_SYNC_ADD :
968         case LDAP_SYNC_MODIFY :
969
970                 if ( rc == LDAP_SUCCESS ||
971                          rc == LDAP_REFERRAL ||
972                          rc == LDAP_NO_SUCH_OBJECT ||
973                          rc == DB_NOTFOUND ) {
974
975                         if ( !attr_find( e->e_attrs, slap_schema.si_ad_entryUUID )) {
976                                 attr_merge_one( e, slap_schema.si_ad_entryUUID, syncUUID, syncUUID );
977                         }
978
979                         op->o_tag = LDAP_REQ_ADD;
980                         op->ora_e = e;
981                         op->o_req_dn = e->e_name;
982                         op->o_req_ndn = e->e_nname;
983                         rc = be->be_add( op, &rs );
984
985                         if ( rc != LDAP_SUCCESS ) {
986                                 if ( rc == LDAP_ALREADY_EXISTS ) {      
987                                         op->o_tag = LDAP_REQ_MODIFY;
988                                         op->orm_modlist = modlist;
989                                         op->o_req_dn = e->e_name;
990                                         op->o_req_ndn = e->e_nname;
991                                         rc = be->be_modify( op, &rs );
992                                 } else if ( rc == LDAP_REFERRAL ||
993                                                         rc == LDAP_NO_SUCH_OBJECT ||
994                                                         rc == DB_NOTFOUND ) {
995                                         syncrepl_add_glue(ld, op, e,
996                                                 modlist, syncstate,
997                                                 syncUUID, syncCookie);
998                                 } else {
999 #ifdef NEW_LOGGING
1000                                         LDAP_LOG( OPERATION, ERR,
1001                                                 "be_modify failed (%d)\n",
1002                                                 rc, 0, 0 );
1003 #else
1004                                         Debug( LDAP_DEBUG_ANY,
1005                                                 "be_modify failed (%d)\n",
1006                                                 rc, 0, 0 );
1007 #endif
1008                                 }
1009                         } else {
1010                                 return 0;
1011                         }
1012                 } else {
1013 #ifdef NEW_LOGGING
1014                         LDAP_LOG( OPERATION, ERR,
1015                                 "be_modify/be_delete failed (%d)\n", rc, 0, 0 );
1016 #else
1017                         Debug( LDAP_DEBUG_ANY,
1018                                 "be_modify/be_delete failed (%d)\n", rc, 0, 0 );
1019 #endif
1020                 }
1021
1022                 si->e = NULL;
1023                 return 1;
1024
1025         case LDAP_SYNC_DELETE :
1026                 /* Already deleted */
1027                 return 1;
1028
1029         default :
1030 #ifdef NEW_LOGGING
1031                 LDAP_LOG( OPERATION, ERR,
1032                         "unknown syncstate\n", 0, 0, 0 );
1033 #else
1034                 Debug( LDAP_DEBUG_ANY,
1035                         "unknown syncstate\n", 0, 0, 0 );
1036 #endif
1037                 return 1;
1038         }
1039 }
1040
1041 static int
1042 syncrepl_del_nonpresent(
1043         LDAP *ld,
1044         Operation *op
1045 )
1046 {
1047         Backend* be = op->o_bd;
1048         syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
1049         slap_callback   cb;
1050         struct berval   base_bv = {0, NULL};
1051         Filter *filter;
1052         SlapReply       rs = {REP_RESULT};
1053         struct berval   filterstr_bv = {0, NULL};
1054         struct nonpresent_entry *np_list, *np_prev;
1055
1056         ber_str2bv( si->base, strlen(si->base), 1, &base_bv ); 
1057         dnPrettyNormal(0, &base_bv, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx );
1058         ch_free( base_bv.bv_val );
1059
1060         filter = str2filter( si->filterstr );
1061
1062         cb.sc_response = nonpresent_callback;
1063         cb.sc_private = si;
1064
1065         op->o_callback = &cb;
1066         op->o_tag = LDAP_REQ_SEARCH;
1067         op->ors_scope = si->scope;
1068         op->ors_deref = LDAP_DEREF_NEVER;
1069         op->ors_slimit = -1;
1070         op->ors_tlimit = -1;
1071         op->ors_attrsonly = 0;
1072         op->ors_attrs = NULL;
1073         op->ors_filter = filter;
1074         ber_str2bv( si->filterstr, strlen( si->filterstr ), 1, &op->ors_filterstr );
1075
1076         be->be_search( op, &rs );
1077
1078         if ( !LDAP_LIST_EMPTY( &si->nonpresentlist ) ) {
1079                 np_list = LDAP_LIST_FIRST( &si->nonpresentlist );
1080                 while ( np_list != NULL ) {
1081                         LDAP_LIST_REMOVE( np_list, np_link );
1082                         np_prev = np_list;
1083                         np_list = LDAP_LIST_NEXT( np_list, np_link );
1084                         op->o_tag = LDAP_REQ_DELETE;
1085                         op->o_callback = &cb;
1086                         cb.sc_response = null_callback;
1087                         cb.sc_private = si;
1088                         op->o_req_dn = *np_prev->dn;
1089                         op->o_req_ndn = *np_prev->ndn;
1090                         op->o_bd->be_delete( op, &rs );
1091                         ber_bvfree( np_prev->dn );
1092                         ber_bvfree( np_prev->ndn );
1093                         op->o_req_dn.bv_val = NULL;
1094                         op->o_req_ndn.bv_val = NULL;
1095                         ch_free( np_prev );
1096                 }
1097         }
1098
1099         if ( op->o_req_dn.bv_val )
1100                 ch_free( op->o_req_dn.bv_val );
1101         if ( op->o_req_ndn.bv_val )
1102                 ch_free( op->o_req_ndn.bv_val );
1103         filter_free( op->ors_filter );
1104         ch_free( op->ors_filterstr.bv_val );
1105 }
1106
1107
1108 static void
1109 syncrepl_add_glue(
1110         LDAP *ld,
1111         Operation* op,
1112         Entry *e,
1113         Modifications* modlist,
1114         int syncstate,
1115         struct berval* syncUUID,
1116         struct berval* syncCookie
1117 )
1118 {
1119         Backend *be = op->o_bd;
1120         syncinfo_t *si = op->o_callback->sc_private;
1121         struct berval   uuid_bv = {0, NULL};
1122         slap_callback cb;
1123         Attribute       *a;
1124         int     rc;
1125         char    uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
1126         int levels = 0;
1127         int i, j, k;
1128         struct berval dn = {0, NULL};
1129         struct berval pdn = {0, NULL};
1130         struct berval ndn = {0, NULL};
1131         struct berval rdn = {0, NULL};
1132         Entry   *glue;
1133         SlapReply       rs = {REP_RESULT};
1134         Connection *conn = op->o_conn;
1135
1136         op->o_tag = LDAP_REQ_ADD;
1137         op->o_callback = &cb;
1138         cb.sc_response = null_callback;
1139         cb.sc_private = si;
1140
1141         ber_dupbv( &dn, &e->e_nname );
1142         ber_dupbv( &pdn, &e->e_nname );
1143
1144         while ( !be_issuffix ( be, &pdn )) {
1145                 dnParent( &dn, &pdn );
1146                 ch_free( dn.bv_val );
1147                 ber_dupbv( &dn, &pdn );
1148                 levels++;
1149         }
1150
1151         for ( i = 0; i <= levels; i++ ) {
1152                 glue = (Entry*) ch_calloc( 1, sizeof(Entry) );
1153                 ch_free( dn.bv_val );
1154                 ch_free( pdn.bv_val );
1155                 ber_dupbv( &dn, &e->e_nname );
1156                 ber_dupbv( &pdn, &e->e_nname );
1157                 j = levels - i;
1158                 for ( k = 0; k < j; k++ ) {
1159                         dnParent( &dn, &pdn );
1160                         ch_free( dn.bv_val );
1161                         ber_dupbv( &dn, &pdn );
1162                 }
1163
1164                 dnPrettyNormal( 0, &dn, &pdn, &ndn, op->o_tmpmemctx );
1165                 ber_dupbv( &glue->e_name, &pdn );
1166                 ber_dupbv( &glue->e_nname, &ndn );
1167                 ch_free( dn.bv_val );
1168                 ch_free( pdn.bv_val );
1169                 ch_free( ndn.bv_val );
1170
1171                 a = ch_calloc( 1, sizeof( Attribute ));
1172                 a->a_desc = slap_schema.si_ad_objectClass;
1173                 a->a_vals = ch_calloc( 3, sizeof( struct berval ));
1174                 ber_str2bv( "top", strlen("top"), 1, &a->a_vals[0] );
1175                 ber_str2bv( "glue", strlen("glue"), 1, &a->a_vals[1] );
1176                 a->a_vals[2].bv_len = 0;
1177                 a->a_vals[2].bv_val = NULL;
1178                 a->a_next = glue->e_attrs;
1179                 glue->e_attrs = a;
1180
1181                 a = ch_calloc( 1, sizeof( Attribute ));
1182                 a->a_desc = slap_schema.si_ad_structuralObjectClass;
1183                 a->a_vals = ch_calloc( 2, sizeof( struct berval ));
1184                 ber_str2bv( "glue", strlen("glue"), 1, &a->a_vals[0] );
1185                 a->a_vals[1].bv_len = 0;
1186                 a->a_vals[1].bv_val = NULL;
1187                 a->a_next = glue->e_attrs;
1188                 glue->e_attrs = a;
1189
1190                 if ( !strcmp( e->e_nname.bv_val, glue->e_nname.bv_val )) {
1191                         op->o_req_dn = e->e_name;
1192                         op->o_req_ndn = e->e_nname;
1193                         op->ora_e = e;
1194                         rc = be->be_add ( op, &rs );
1195                         if ( rc == LDAP_SUCCESS )
1196                                 be_entry_release_w( op, e );
1197                         else 
1198                                 entry_free( e );
1199                         entry_free( glue );
1200                 } else {
1201                         op->o_req_dn = glue->e_name;
1202                         op->o_req_ndn = glue->e_nname;
1203                         op->ora_e = glue;
1204                         rc = be->be_add ( op, &rs );
1205                         if ( rc == LDAP_SUCCESS ) {
1206                                 be_entry_release_w( op, glue );
1207                         } else {
1208                         /* incl. ALREADY EXIST */
1209                                 entry_free( glue );
1210                         }
1211                 }
1212         }
1213
1214         return;
1215 }
1216
1217 static void
1218 syncrepl_updateCookie(
1219         LDAP *ld,
1220         Operation *op,
1221         struct berval *pdn,
1222         struct berval *syncCookie
1223 )
1224 {
1225         Backend *be = op->o_bd;
1226         syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
1227         Modifications *ml;
1228         Modifications *mlnext;
1229         Modifications *mod;
1230         Modifications *modlist;
1231         Modifications **modtail = &modlist;
1232
1233         struct berval* ocbva = NULL;
1234         struct berval* cnbva = NULL;
1235         struct berval* ssbva = NULL;
1236         struct berval* scbva = NULL;
1237
1238         char substr[64];
1239         char rdnstr[67];
1240         const char      *text;
1241         char txtbuf[SLAP_TEXT_BUFLEN];
1242         size_t textlen = sizeof txtbuf;
1243
1244         Entry* e;
1245         int rc;
1246
1247         struct berval sub_bv = { 0, NULL };
1248         struct berval psubrdn = { 0, NULL };
1249         
1250         slap_callback cb;
1251         SlapReply       rs = {REP_RESULT};
1252
1253         ocbva = ( struct berval * ) ch_calloc( 4, sizeof( struct berval ));
1254         cnbva = ( struct berval * ) ch_calloc( 2, sizeof( struct berval ));
1255         ssbva = ( struct berval * ) ch_calloc( 2, sizeof( struct berval ));
1256         scbva = ( struct berval * ) ch_calloc( 2, sizeof( struct berval ));
1257
1258         /* update in memory cookie */
1259         if ( si->syncCookie != NULL ) {
1260                 ber_bvfree( si->syncCookie );
1261         }
1262         si->syncCookie = ber_dupbv( NULL, syncCookie );
1263         ber_str2bv( "top", strlen("top"), 1, &ocbva[0] );
1264         ber_str2bv( "subentry", strlen("subentry"), 1, &ocbva[1] );
1265         ber_str2bv( "syncConsumerSubentry",
1266                         strlen("syncConsumerSubentry"), 1, &ocbva[2] );
1267         ocbva[3].bv_len = 0;
1268         ocbva[3].bv_val = NULL;
1269
1270         mod = (Modifications *) ch_malloc( sizeof( Modifications ));
1271         mod->sml_op = LDAP_MOD_REPLACE;
1272         mod->sml_next = NULL;
1273         mod->sml_desc = NULL;
1274         ber_str2bv( "objectClass", strlen("objectClass"), 1, &mod->sml_type );
1275         mod->sml_bvalues = ocbva;
1276         mod->sml_nvalues = ocbva;
1277         *modtail = mod;
1278         modtail = &mod->sml_next;
1279
1280         sprintf( substr, "syncrepl%d", si->id );
1281         sprintf( rdnstr, "cn=%s", substr );
1282         ber_str2bv( substr, strlen( substr ), 1, &cnbva[0] );
1283         ber_str2bv( rdnstr, strlen( rdnstr ), 1, &psubrdn );
1284         cnbva[1].bv_len = 0;
1285         cnbva[1].bv_val = NULL;
1286         mod = (Modifications *) ch_malloc( sizeof( Modifications ));
1287         mod->sml_op = LDAP_MOD_REPLACE;
1288         mod->sml_next = NULL;
1289         mod->sml_desc = NULL;
1290         ber_str2bv( "cn", strlen("cn"), 1, &mod->sml_type );
1291         mod->sml_bvalues = cnbva;
1292         mod->sml_nvalues = cnbva;
1293         *modtail = mod;
1294         modtail = &mod->sml_next;
1295
1296         ber_dupbv( &scbva[0], si->syncCookie );
1297         scbva[1].bv_len = 0;
1298         scbva[1].bv_val = NULL;
1299         mod = (Modifications *) ch_malloc( sizeof( Modifications ));
1300         mod->sml_op = LDAP_MOD_REPLACE;
1301         mod->sml_next = NULL;
1302         mod->sml_desc = NULL;
1303         ber_str2bv( "syncreplCookie", strlen("syncreplCookie"),
1304                                                 1, &mod->sml_type );
1305         mod->sml_bvalues = scbva;
1306         mod->sml_nvalues = scbva;
1307         *modtail = mod;
1308         modtail = &mod->sml_next;
1309
1310         ber_str2bv( "{}", strlen("{}"), 1, &ssbva[0] );
1311         ssbva[1].bv_len = 0;
1312         ssbva[1].bv_val = NULL;
1313         mod = (Modifications *) ch_malloc( sizeof( Modifications ));
1314         mod->sml_op = LDAP_MOD_REPLACE;
1315         mod->sml_next = NULL;
1316         mod->sml_desc = NULL;
1317         ber_str2bv( "subtreeSpecification",
1318                         strlen("subtreeSpecification"), 1, &mod->sml_type );
1319         mod->sml_bvalues = ssbva;
1320         mod->sml_nvalues = ssbva;
1321         *modtail = mod;
1322         modtail = &mod->sml_next;
1323
1324         rc = slap_mods_check_syncrepl( op, &modlist, &text, txtbuf, textlen, NULL );
1325
1326         if ( rc != LDAP_SUCCESS ) {
1327 #ifdef NEW_LOGGING
1328                 LDAP_LOG( OPERATION, ERR,
1329                                 "syncrepl_updateCookie: mods check (%s)\n", text, 0, 0 );
1330 #else
1331                 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods check (%s)\n",
1332                          text, 0, 0 );
1333 #endif
1334         }
1335
1336         op->o_tag = LDAP_REQ_ADD;
1337         rc = slap_mods_opattrs_syncrepl( op, modlist, modtail, &text,txtbuf, textlen );
1338
1339         if( rc != LDAP_SUCCESS ) {
1340 #ifdef NEW_LOGGING
1341                 LDAP_LOG( OPERATION, ERR,
1342                                 "syncrepl_updateCookie: mods opattrs (%s)\n", text, 0, 0 );
1343 #else
1344                 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods opattrs (%s)\n",
1345                          text, 0, 0 );
1346 #endif
1347         }
1348
1349         e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1350
1351         build_new_dn( &sub_bv, pdn, &psubrdn );
1352         dnPrettyNormal( NULL, &sub_bv, &e->e_name, &e->e_nname, op->o_tmpmemctx );
1353         ch_free( sub_bv.bv_val );
1354         ch_free( psubrdn.bv_val );
1355
1356         e->e_attrs = NULL;
1357
1358         rc = slap_mods2entry_syncrepl( modlist, &e, 1, &text, txtbuf, textlen );
1359
1360         if( rc != LDAP_SUCCESS ) {
1361 #ifdef NEW_LOGGING
1362                 LDAP_LOG( OPERATION, ERR,
1363                                 "syncrepl_updateCookie: mods2entry (%s)\n", text, 0, 0 );
1364 #else
1365                 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods2entry (%s)\n",
1366                          text, 0, 0 );
1367 #endif
1368         }
1369
1370         cb.sc_response = null_callback;
1371         cb.sc_private = si;
1372
1373         op->o_callback = &cb;
1374         op->o_req_dn = e->e_name;
1375         op->o_req_ndn = e->e_nname;
1376
1377         /* update persistent cookie */
1378 update_cookie_retry:
1379         op->o_tag = LDAP_REQ_MODIFY;
1380         op->orm_modlist = modlist;
1381         rc = be->be_modify( op, &rs );
1382         if ( rc != LDAP_SUCCESS ) {
1383                 if ( rc == LDAP_REFERRAL ||
1384                          rc == LDAP_NO_SUCH_OBJECT ||
1385                          rc == DB_NOTFOUND ) {
1386                         op->o_tag = LDAP_REQ_ADD;
1387                         op->ora_e = e;
1388                         rc = be->be_add( op, &rs );
1389                         if ( rc != LDAP_SUCCESS ) {
1390                                 if ( rc == LDAP_ALREADY_EXISTS ) {
1391                                         goto update_cookie_retry;
1392                                 } else if ( rc == LDAP_REFERRAL ||
1393                                                         rc == LDAP_NO_SUCH_OBJECT ||
1394                                                         rc == DB_NOTFOUND ) {
1395 #ifdef NEW_LOGGING
1396                                         LDAP_LOG( OPERATION, ERR,
1397                                                 "cookie will be non-persistent\n",
1398                                                 0, 0, 0 );
1399 #else
1400                                         Debug( LDAP_DEBUG_ANY,
1401                                                 "cookie will be non-persistent\n",
1402                                                 0, 0, 0 );
1403 #endif
1404                                 } else {
1405 #ifdef NEW_LOGGING
1406                                         LDAP_LOG( OPERATION, ERR,
1407                                                 "be_add failed (%d)\n",
1408                                                 rc, 0, 0 );
1409 #else
1410                                         Debug( LDAP_DEBUG_ANY,
1411                                                 "be_add failed (%d)\n",
1412                                                 rc, 0, 0 );
1413 #endif
1414                                 }
1415                         } else {
1416                                 goto done;
1417                         }
1418                 } else {
1419 #ifdef NEW_LOGGING
1420                         LDAP_LOG( OPERATION, ERR,
1421                                 "be_modify failed (%d)\n", rc, 0, 0 );
1422 #else
1423                         Debug( LDAP_DEBUG_ANY,
1424                                 "be_modify failed (%d)\n", rc, 0, 0 );
1425 #endif
1426                 }
1427         }
1428
1429         if ( e != NULL )
1430                 entry_free( e );
1431
1432 done :
1433
1434         for ( ml = modlist; ml != NULL; ml = mlnext ) {
1435                 mlnext = ml->sml_next;
1436                 free( ml );
1437         }
1438
1439         return;
1440 }
1441
1442
1443 static
1444 int slap_mods_check_syncrepl(
1445         Operation *op,
1446         Modifications **mlp,
1447         const char **text,
1448         char *textbuf,
1449         size_t textlen,
1450         void *ctx )
1451 {
1452         int rc;
1453         Backend *be = op->o_bd;
1454         syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
1455         AttributeDescription** descs;
1456         int i;
1457         Modifications *prevml = NULL;
1458         Modifications *nextml = NULL;
1459         Modifications *ml = *mlp;
1460
1461         while ( ml != NULL ) {
1462                 AttributeDescription *ad = NULL;
1463
1464                 /* convert to attribute description */
1465                 rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, text );
1466
1467                 if( rc != LDAP_SUCCESS ) {
1468                         snprintf( textbuf, textlen, "%s: %s",
1469                                                 ml->sml_type.bv_val, *text );
1470                         *text = textbuf;
1471                         return rc;
1472                 }
1473
1474                 ad = ml->sml_desc;
1475
1476                 if ( si->lastmod == LASTMOD_REQ ) {
1477                         descs = del_descs_lastmod;
1478                 } else {
1479                         descs = del_descs;
1480                 }
1481
1482                 for ( i = 0; descs[i] != NULL; i++ ) {
1483                         if ( ad == descs[i] ) {
1484                                 if ( prevml == NULL ) {
1485                                         mlp = &ml->sml_next;
1486                                         prevml = NULL;
1487                                 } else {
1488                                         prevml->sml_next = ml->sml_next;
1489                                 }
1490                                 slap_mod_free( &ml->sml_mod, 0 );
1491                                 nextml = ml->sml_next;
1492                                 free( ml );
1493                                 ml = nextml;
1494                                 continue;
1495                         }
1496                 }
1497
1498                 if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
1499                                 && !slap_ad_is_binary( ad )) {
1500                         /* attribute requires binary transfer */
1501                         snprintf( textbuf, textlen,
1502                                         "%s: requires ;binary transfer",
1503                                         ml->sml_type.bv_val );
1504                         *text = textbuf;
1505                         return LDAP_UNDEFINED_TYPE;
1506                 }
1507
1508                 if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
1509                                         && slap_ad_is_binary( ad )) {
1510                         /* attribute requires binary transfer */
1511                         snprintf( textbuf, textlen,
1512                                         "%s: disallows ;binary transfer",
1513                                         ml->sml_type.bv_val );
1514                         *text = textbuf;
1515                         return LDAP_UNDEFINED_TYPE;
1516                 }
1517
1518                 if( slap_ad_is_tag_range( ad )) {
1519                         /* attribute requires binary transfer */
1520                         snprintf( textbuf, textlen,
1521                                         "%s: inappropriate use of tag range option",
1522                                         ml->sml_type.bv_val );
1523                         *text = textbuf;
1524                         return LDAP_UNDEFINED_TYPE;
1525                 }
1526
1527                 if ( is_at_obsolete( ad->ad_type ) &&
1528                                 ( ml->sml_op == LDAP_MOD_ADD || ml->sml_values != NULL ) ) {
1529                         /*
1530                          * attribute is obsolete,
1531                          * only allow replace/delete with no values
1532                          */
1533                         snprintf( textbuf, textlen,
1534                                         "%s: attribute is obsolete",
1535                                         ml->sml_type.bv_val );
1536                         *text = textbuf;
1537                         return LDAP_CONSTRAINT_VIOLATION;
1538                 }
1539
1540                 /*
1541                  * check values
1542                  */
1543                 if( ml->sml_values != NULL ) {
1544                         ber_len_t nvals;
1545                         slap_syntax_validate_func *validate =
1546                         ad->ad_type->sat_syntax->ssyn_validate;
1547                         slap_syntax_transform_func *pretty =
1548                         ad->ad_type->sat_syntax->ssyn_pretty;
1549
1550                         if( !pretty && !validate ) {
1551                                 *text = "no validator for syntax";
1552                                 snprintf( textbuf, textlen,
1553                                                 "%s: no validator for syntax %s",
1554                                                 ml->sml_type.bv_val,
1555                                                 ad->ad_type->sat_syntax->ssyn_oid );
1556                                 *text = textbuf;
1557                                 return LDAP_INVALID_SYNTAX;
1558                         }
1559
1560                         /*
1561                          * check that each value is valid per syntax
1562                          * and pretty if appropriate
1563                          */
1564                         for( nvals = 0; ml->sml_values[nvals].bv_val; nvals++ ) {
1565                                 struct berval pval = {0, NULL};
1566                                 if( pretty ) {
1567                                         rc = pretty( ad->ad_type->sat_syntax,
1568                                                         &ml->sml_values[nvals], &pval, ctx );
1569                                 } else {
1570                                         rc = validate( ad->ad_type->sat_syntax,
1571                                                         &ml->sml_values[nvals] );
1572                                 }
1573
1574                                 if( rc != 0 ) {
1575                                         snprintf( textbuf, textlen,
1576                                                         "%s: value #%ld invalid per syntax",
1577                                                         ml->sml_type.bv_val, (long) nvals );
1578                                         *text = textbuf;
1579                                         return LDAP_INVALID_SYNTAX;
1580                                 }
1581
1582                                 if( pretty ) {
1583                                         ber_memfree( ml->sml_values[nvals].bv_val );
1584                                         ml->sml_values[nvals] = pval;
1585                                 }
1586                         }
1587
1588                         /*
1589                          * a rough single value check... an additional check is needed
1590                          * to catch add of single value to existing single valued attribute
1591                          */
1592                         if ((ml->sml_op == LDAP_MOD_ADD || ml->sml_op == LDAP_MOD_REPLACE)
1593                                         && nvals > 1 && is_at_single_value( ad->ad_type )) {
1594                                 snprintf( textbuf, textlen,
1595                                                 "%s: multiple values provided",
1596                                                 ml->sml_type.bv_val );
1597                                 *text = textbuf;
1598                                 return LDAP_CONSTRAINT_VIOLATION;
1599                         }
1600
1601                         if( nvals && ad->ad_type->sat_equality &&
1602                                         ad->ad_type->sat_equality->smr_normalize ) {
1603                                 ml->sml_nvalues = ch_malloc( (nvals+1)*sizeof(struct berval) );
1604                                 for( nvals = 0; ml->sml_values[nvals].bv_val; nvals++ ) {
1605                                         rc = ad->ad_type->sat_equality->smr_normalize( 0,
1606                                                         ad->ad_type->sat_syntax, ad->ad_type->sat_equality,
1607                                                         &ml->sml_values[nvals], &ml->sml_nvalues[nvals], ctx );
1608                                         if( rc ) {
1609 #ifdef NEW_LOGGING
1610                                                 LDAP_LOG( OPERATION, DETAIL1,
1611                                                                 "str2entry:  NULL (ssyn_normalize %d)\n", rc, 0, 0 );
1612 #else
1613                                                 Debug( LDAP_DEBUG_ANY,
1614                                                                 "<= str2entry NULL (ssyn_normalize %d)\n", rc, 0, 0 );
1615 #endif
1616                                                 snprintf( textbuf, textlen,
1617                                                                 "%s: value #%ld normalization failed",
1618                                                                 ml->sml_type.bv_val, (long) nvals );
1619                                                 *text = textbuf;
1620                                                 return rc;
1621                                         }
1622                                 }
1623                                 ml->sml_nvalues[nvals].bv_val = NULL;
1624                                 ml->sml_nvalues[nvals].bv_len = 0;
1625                         }
1626                 }
1627                 prevml = ml;
1628                 ml = ml->sml_next;
1629         }
1630
1631         return LDAP_SUCCESS;
1632 }
1633
1634 static
1635 int slap_mods_opattrs_syncrepl(
1636         Operation *op,
1637         Modifications *mods,
1638         Modifications **modtail,
1639         const char **text,
1640         char *textbuf, size_t textlen )
1641 {
1642         struct berval name = {0, NULL};
1643         struct berval timestamp = {0, NULL};
1644         struct berval csn = {0, NULL};
1645         struct berval nname = {0, NULL};
1646         char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
1647         char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
1648         Modifications *mod;
1649         Backend *be = op->o_bd;
1650         syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
1651
1652         int mop = LDAP_MOD_REPLACE;
1653
1654         assert( modtail != NULL );
1655         assert( *modtail == NULL );
1656
1657         if( si->lastmod == LASTMOD_GEN ) {
1658                 struct tm *ltm;
1659                 time_t now = slap_get_time();
1660
1661                 ldap_pvt_thread_mutex_lock( &gmtime_mutex );
1662                 ltm = gmtime( &now );
1663                 lutil_gentime( timebuf, sizeof(timebuf), ltm );
1664
1665                 csn.bv_len = lutil_csnstr( csnbuf, sizeof( csnbuf ), 0, 0 );
1666                 ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
1667                 csn.bv_val = csnbuf;
1668
1669                 timestamp.bv_val = timebuf;
1670                 timestamp.bv_len = strlen(timebuf);
1671
1672                 if( op->o_dn.bv_len == 0 ) {
1673                         name.bv_val = SLAPD_ANONYMOUS;
1674                         name.bv_len = sizeof(SLAPD_ANONYMOUS)-1;
1675                         nname = name;
1676                 } else {
1677                         name = op->o_dn;
1678                         nname = op->o_ndn;
1679                 }
1680         }
1681
1682         if( op->o_tag == LDAP_REQ_ADD ) {
1683                 struct berval tmpval = {0, NULL};
1684
1685                 if( global_schemacheck ) {
1686                         int rc = mods_structural_class( mods, &tmpval,
1687                                                                         text, textbuf, textlen );
1688                         if( rc != LDAP_SUCCESS ) {
1689                                 return rc;
1690                         }
1691
1692                         mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
1693                         mod->sml_op = mop;
1694                         mod->sml_type.bv_val = NULL;
1695                         mod->sml_desc = slap_schema.si_ad_structuralObjectClass;
1696                         mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1697                         ber_dupbv( &mod->sml_values[0], &tmpval );
1698                         mod->sml_values[1].bv_len = 0;
1699                         mod->sml_values[1].bv_val = NULL;
1700                         assert( mod->sml_values[0].bv_val );
1701                         mod->sml_nvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1702                         ber_dupbv( &mod->sml_nvalues[0], &tmpval );
1703                         mod->sml_nvalues[1].bv_len = 0;
1704                         mod->sml_nvalues[1].bv_val = NULL;
1705                         assert( mod->sml_nvalues[0].bv_val );
1706                         *modtail = mod;
1707                         modtail = &mod->sml_next;
1708                 }
1709
1710                 if( si->lastmod == LASTMOD_GEN ) {
1711                         mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
1712                         mod->sml_op = mop;
1713                         mod->sml_type.bv_val = NULL;
1714                         mod->sml_desc = slap_schema.si_ad_creatorsName;
1715                         mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1716                         ber_dupbv( &mod->sml_values[0], &name );
1717                         mod->sml_values[1].bv_len = 0;
1718                         mod->sml_values[1].bv_val = NULL;
1719                         assert( mod->sml_values[0].bv_val );
1720                         mod->sml_nvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1721                         ber_dupbv( &mod->sml_nvalues[0], &nname );
1722                         mod->sml_nvalues[1].bv_len = 0;
1723                         mod->sml_nvalues[1].bv_val = NULL;
1724                         assert( mod->sml_nvalues[0].bv_val );
1725                         *modtail = mod;
1726                         modtail = &mod->sml_next;
1727
1728                         mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
1729                         mod->sml_op = mop;
1730                         mod->sml_type.bv_val = NULL;
1731                         mod->sml_desc = slap_schema.si_ad_createTimestamp;
1732                         mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1733                         ber_dupbv( &mod->sml_values[0], &timestamp );
1734                         mod->sml_values[1].bv_len = 0;
1735                         mod->sml_values[1].bv_val = NULL;
1736                         assert( mod->sml_values[0].bv_val );
1737                         mod->sml_nvalues = NULL;
1738                         *modtail = mod;
1739                         modtail = &mod->sml_next;
1740                 }
1741         }
1742
1743         if( si->lastmod == LASTMOD_GEN ) {
1744                 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
1745                 mod->sml_op = mop;
1746                 mod->sml_type.bv_val = NULL;
1747                 mod->sml_desc = slap_schema.si_ad_entryCSN;
1748                 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1749                 ber_dupbv( &mod->sml_values[0], &csn );
1750                 mod->sml_values[1].bv_len = 0;
1751                 mod->sml_values[1].bv_val = NULL;
1752                 assert( mod->sml_values[0].bv_val );
1753                 mod->sml_nvalues = NULL;
1754                 *modtail = mod;
1755                 modtail = &mod->sml_next;
1756
1757                 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
1758                 mod->sml_op = mop;
1759                 mod->sml_type.bv_val = NULL;
1760                 mod->sml_desc = slap_schema.si_ad_modifiersName;
1761                 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1762                 ber_dupbv( &mod->sml_values[0], &name );
1763                 mod->sml_values[1].bv_len = 0;
1764                 mod->sml_values[1].bv_val = NULL;
1765                 assert( mod->sml_values[0].bv_val );
1766                 mod->sml_nvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1767                 ber_dupbv( &mod->sml_nvalues[0], &nname );
1768                 mod->sml_nvalues[1].bv_len = 0;
1769                 mod->sml_nvalues[1].bv_val = NULL;
1770                 assert( mod->sml_nvalues[0].bv_val );
1771                 *modtail = mod;
1772                 modtail = &mod->sml_next;
1773
1774                 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
1775                 mod->sml_op = mop;
1776                 mod->sml_type.bv_val = NULL;
1777                 mod->sml_desc = slap_schema.si_ad_modifyTimestamp;
1778                 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1779                 ber_dupbv( &mod->sml_values[0], &timestamp );
1780                 mod->sml_values[1].bv_len = 0;
1781                 mod->sml_values[1].bv_val = NULL;
1782                 assert( mod->sml_values[0].bv_val );
1783                 mod->sml_nvalues = NULL;
1784                 *modtail = mod;
1785                 modtail = &mod->sml_next;
1786         }
1787
1788         *modtail = NULL;
1789         return LDAP_SUCCESS;
1790 }
1791
1792
1793 static
1794 int slap_mods2entry_syncrepl(
1795         Modifications *mods,
1796         Entry **e,
1797         int repl_user,
1798         const char **text,
1799         char *textbuf, size_t textlen )
1800 {
1801         Attribute **tail = &(*e)->e_attrs;
1802         assert( *tail == NULL );
1803
1804         *text = textbuf;
1805
1806         for( ; mods != NULL; mods = mods->sml_next ) {
1807                 Attribute *attr;
1808
1809                 assert( mods->sml_desc != NULL );
1810
1811                 attr = attr_find( (*e)->e_attrs, mods->sml_desc );
1812
1813                 if( attr != NULL ) {
1814 #define SLURPD_FRIENDLY
1815 #ifdef SLURPD_FRIENDLY
1816                         ber_len_t i,j;
1817
1818                         if( !repl_user ) {
1819                                 snprintf( textbuf, textlen,
1820                                         "attribute '%s' provided more than once",
1821                                         mods->sml_desc->ad_cname.bv_val );
1822                                 return LDAP_TYPE_OR_VALUE_EXISTS;
1823                         }
1824
1825                         for( i=0; attr->a_vals[i].bv_val; i++ ) {
1826                                 /* count them */
1827                         }
1828                         for( j=0; mods->sml_values[j].bv_val; j++ ) {
1829                                 /* count them */
1830                         }
1831                         j++;    /* NULL */
1832                         
1833                         attr->a_vals = ch_realloc( attr->a_vals,
1834                                 sizeof( struct berval ) * (i+j) );
1835
1836                         /* should check for duplicates */
1837
1838                         AC_MEMCPY( &attr->a_vals[i], mods->sml_values,
1839                                 sizeof( struct berval ) * j );
1840
1841                         if( attr->a_nvals ) {
1842                                 attr->a_nvals = ch_realloc( attr->a_nvals,
1843                                         sizeof( struct berval ) * (i+j) );
1844
1845                                 AC_MEMCPY( &attr->a_nvals[i], mods->sml_nvalues,
1846                                         sizeof( struct berval ) * j );
1847
1848                                 /* trim the mods array */
1849                                 ch_free( mods->sml_nvalues );
1850                                 mods->sml_nvalues = NULL;
1851                         }
1852
1853                         continue;
1854 #else
1855                         snprintf( textbuf, textlen,
1856                                 "attribute '%s' provided more than once",
1857                                 mods->sml_desc->ad_cname.bv_val );
1858                         return LDAP_TYPE_OR_VALUE_EXISTS;
1859 #endif
1860                 }
1861
1862                 if( mods->sml_values[1].bv_val != NULL ) {
1863                         /* check for duplicates */
1864                         int             i, j;
1865                         MatchingRule *mr = mods->sml_desc->ad_type->sat_equality;
1866
1867                         /* check if the values we're adding already exist */
1868                         if( mr == NULL || !mr->smr_match ) {
1869                                 for ( i = 0; mods->sml_bvalues[i].bv_val != NULL; i++ ) {
1870                                         /* test asserted values against themselves */
1871                                         for( j = 0; j < i; j++ ) {
1872                                                 if ( bvmatch( &mods->sml_bvalues[i],
1873                                                         &mods->sml_bvalues[j] ) ) {
1874                                                         /* value exists already */
1875                                                         snprintf( textbuf, textlen,
1876                                                                 "%s: value #%d provided more than once",
1877                                                                 mods->sml_desc->ad_cname.bv_val, j );
1878                                                         return LDAP_TYPE_OR_VALUE_EXISTS;
1879                                                 }
1880                                         }
1881                                 }
1882
1883                         } else {
1884                                 int             rc;
1885                                 const char      *text = NULL;
1886                                 char            textbuf[ SLAP_TEXT_BUFLEN ]  = { '\0' };
1887                                 
1888                                 rc = modify_check_duplicates( mods->sml_desc, mr,
1889                                                 NULL, mods->sml_bvalues, 0,
1890                                                 &text, textbuf, sizeof( textbuf ) );
1891
1892                                 if ( rc != LDAP_SUCCESS ) {
1893                                         return rc;
1894                                 }
1895                         }
1896                 }
1897
1898                 attr = ch_calloc( 1, sizeof(Attribute) );
1899
1900                 /* move ad to attr structure */
1901                 attr->a_desc = mods->sml_desc;
1902
1903                 /* move values to attr structure */
1904                 /*      should check for duplicates */
1905                 attr->a_vals = mods->sml_values;
1906
1907                 attr->a_nvals = mods->sml_nvalues;
1908
1909                 *tail = attr;
1910                 tail = &attr->a_next;
1911         }
1912
1913         return LDAP_SUCCESS;
1914 }
1915
1916 void
1917 avl_ber_bvfree( void *bv )
1918 {
1919         if( bv == NULL ) {
1920                 return;
1921         }
1922         if ( ((struct berval *)bv)->bv_val != NULL ) {
1923                 ber_memfree ( ((struct berval *)bv)->bv_val );
1924         }
1925         ber_memfree ( (char *) bv );
1926 }
1927
1928 static int
1929 cookie_callback(
1930         Operation* op,
1931         SlapReply* rs
1932 )
1933 {
1934         syncinfo_t *si = op->o_callback->sc_private;
1935         Attribute *a;
1936
1937         if ( rs->sr_type != REP_SEARCH ) return LDAP_SUCCESS;
1938
1939         a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_syncreplCookie );
1940
1941         if ( a == NULL ) {
1942                 si->syncCookie = NULL;
1943         } else {
1944                 si->syncCookie = ber_dupbv( NULL, &a->a_vals[0] );
1945         }
1946         return LDAP_SUCCESS;
1947 }
1948
1949 static int
1950 dn_callback(
1951         Operation*      op,
1952         SlapReply*      rs
1953 )
1954 {
1955         syncinfo_t *si = op->o_callback->sc_private;
1956         
1957         if ( rs->sr_type == REP_SEARCH ) {
1958                 si->syncUUID_ndn = &rs->sr_entry->e_nname;
1959         }
1960
1961         return LDAP_SUCCESS;
1962 }
1963
1964 static int
1965 nonpresent_callback(
1966         Operation*      op,
1967         SlapReply*      rs
1968 )
1969 {
1970         syncinfo_t *si = op->o_callback->sc_private;
1971         Attribute *a;
1972         int count = 0;
1973         struct berval* present_uuid = NULL;
1974         slap_callback cb;
1975         SlapReply       rs_cb = {REP_RESULT};
1976         struct nonpresent_entry *np_entry;
1977
1978         if ( rs->sr_type == REP_RESULT ) {
1979                 count = avl_free( si->presentlist, avl_ber_bvfree );
1980                 return LDAP_SUCCESS;
1981         } else if ( rs->sr_type == REP_SEARCH ) {
1982                 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
1983
1984                 if ( a == NULL )
1985                         return 0;
1986
1987                 present_uuid = avl_find( si->presentlist, &a->a_vals[0], syncuuid_cmp );
1988
1989                 if ( present_uuid == NULL ) {
1990                         np_entry = (struct nonpresent_entry *)
1991                                                 ch_calloc( 1, sizeof( struct nonpresent_entry ));
1992                         np_entry->dn = ber_dupbv( NULL, &rs->sr_entry->e_name );
1993                         np_entry->ndn = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1994                         LDAP_LIST_INSERT_HEAD( &si->nonpresentlist, np_entry, np_link );
1995                 } else {
1996                         avl_delete( &si->presentlist,
1997                                         &a->a_vals[0], syncuuid_cmp );
1998                 }
1999                 return LDAP_SUCCESS;
2000         } else {
2001                 return LDAP_SUCCESS;
2002         }
2003
2004 }
2005
2006 static int
2007 null_callback(
2008         Operation*      op,
2009         SlapReply*      rs
2010 )
2011 {
2012         if ( rs->sr_err != LDAP_SUCCESS &&
2013                  rs->sr_err != LDAP_REFERRAL &&
2014                  rs->sr_err != LDAP_ALREADY_EXISTS &&
2015                  rs->sr_err != LDAP_NO_SUCH_OBJECT &&
2016                  rs->sr_err != DB_NOTFOUND ) {
2017 #ifdef NEW_LOGGING
2018                 LDAP_LOG( OPERATION, ERR,
2019                         "null_callback : error code 0x%x\n",
2020                         rs->sr_err, 0, 0 );
2021 #else
2022                 Debug( LDAP_DEBUG_ANY,
2023                         "null_callback : error code 0x%x\n",
2024                         rs->sr_err, 0, 0 );
2025 #endif
2026         }
2027         return LDAP_SUCCESS;
2028 }
2029
2030
2031 char **
2032 str2clist( char **out, char *in, const char *brkstr )
2033 {
2034         char    *str;
2035         char    *s;
2036         char    *lasts;
2037         int     i, j;
2038         const char *text;
2039         char    **new;
2040
2041         /* find last element in list */
2042         for (i = 0; out && out[i]; i++);
2043         
2044         /* protect the input string from strtok */
2045         str = ch_strdup( in );
2046
2047         /* Count words in string */
2048         j=1;
2049         for ( s = str; *s; s++ ) {
2050                 if ( strchr( brkstr, *s ) != NULL ) {
2051                         j++;
2052                 }
2053         }
2054
2055         out = ch_realloc( out, ( i + j + 1 ) * sizeof( char * ) );
2056         new = out + i;
2057         for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
2058                 s != NULL;
2059                 s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
2060         {
2061                 *new = ch_strdup( s );
2062                 new++;
2063         }
2064
2065         *new = NULL;
2066         free( str );
2067         return( out );
2068 }
2069
2070 #endif