]> git.sur5r.net Git - openldap/blob - servers/slapd/syncrepl.c
6f4eb6d04a3effa5b27b18b877d4a89f03224163
[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:
560                                 rc = ldap_parse_intermediate( ld, msg,
561                                         &retoid, &retdata, NULL, 0 );
562                                 if ( !rc && !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 response (%d)\n",
610                                                 rc, 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
974                         if ( !attr_find( e->e_attrs, slap_schema.si_ad_entryUUID )) {
975                                 attr_merge_one( e, slap_schema.si_ad_entryUUID, syncUUID, syncUUID );
976                         }
977
978                         op->o_tag = LDAP_REQ_ADD;
979                         op->ora_e = e;
980                         op->o_req_dn = e->e_name;
981                         op->o_req_ndn = e->e_nname;
982                         rc = be->be_add( op, &rs );
983
984                         if ( rc != LDAP_SUCCESS ) {
985                                 if ( rc == LDAP_ALREADY_EXISTS ) {      
986                                         op->o_tag = LDAP_REQ_MODIFY;
987                                         op->orm_modlist = modlist;
988                                         op->o_req_dn = e->e_name;
989                                         op->o_req_ndn = e->e_nname;
990                                         rc = be->be_modify( op, &rs );
991                                 } else if ( rc == LDAP_REFERRAL ||
992                                                         rc == LDAP_NO_SUCH_OBJECT ) {
993                                         syncrepl_add_glue(ld, op, e,
994                                                 modlist, syncstate,
995                                                 syncUUID, syncCookie);
996                                 } else {
997 #ifdef NEW_LOGGING
998                                         LDAP_LOG( OPERATION, ERR,
999                                                 "be_modify failed (%d)\n",
1000                                                 rc, 0, 0 );
1001 #else
1002                                         Debug( LDAP_DEBUG_ANY,
1003                                                 "be_modify failed (%d)\n",
1004                                                 rc, 0, 0 );
1005 #endif
1006                                 }
1007                         } else {
1008                                 return 0;
1009                         }
1010                 } else {
1011 #ifdef NEW_LOGGING
1012                         LDAP_LOG( OPERATION, ERR,
1013                                 "be_modify/be_delete failed (%d)\n", rc, 0, 0 );
1014 #else
1015                         Debug( LDAP_DEBUG_ANY,
1016                                 "be_modify/be_delete failed (%d)\n", rc, 0, 0 );
1017 #endif
1018                 }
1019
1020                 si->e = NULL;
1021                 return 1;
1022
1023         case LDAP_SYNC_DELETE :
1024                 /* Already deleted */
1025                 return 1;
1026
1027         default :
1028 #ifdef NEW_LOGGING
1029                 LDAP_LOG( OPERATION, ERR,
1030                         "unknown syncstate\n", 0, 0, 0 );
1031 #else
1032                 Debug( LDAP_DEBUG_ANY,
1033                         "unknown syncstate\n", 0, 0, 0 );
1034 #endif
1035                 return 1;
1036         }
1037 }
1038
1039 static int
1040 syncrepl_del_nonpresent(
1041         LDAP *ld,
1042         Operation *op
1043 )
1044 {
1045         Backend* be = op->o_bd;
1046         syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
1047         slap_callback   cb;
1048         struct berval   base_bv = {0, NULL};
1049         Filter *filter;
1050         SlapReply       rs = {REP_RESULT};
1051         struct berval   filterstr_bv = {0, NULL};
1052         struct nonpresent_entry *np_list, *np_prev;
1053
1054         ber_str2bv( si->base, strlen(si->base), 1, &base_bv ); 
1055         dnPrettyNormal(0, &base_bv, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx );
1056         ch_free( base_bv.bv_val );
1057
1058         filter = str2filter( si->filterstr );
1059
1060         cb.sc_response = nonpresent_callback;
1061         cb.sc_private = si;
1062
1063         op->o_callback = &cb;
1064         op->o_tag = LDAP_REQ_SEARCH;
1065         op->ors_scope = si->scope;
1066         op->ors_deref = LDAP_DEREF_NEVER;
1067         op->ors_slimit = -1;
1068         op->ors_tlimit = -1;
1069         op->ors_attrsonly = 0;
1070         op->ors_attrs = NULL;
1071         op->ors_filter = filter;
1072         ber_str2bv( si->filterstr, strlen( si->filterstr ), 1, &op->ors_filterstr );
1073
1074         be->be_search( op, &rs );
1075
1076         if ( !LDAP_LIST_EMPTY( &si->nonpresentlist ) ) {
1077                 np_list = LDAP_LIST_FIRST( &si->nonpresentlist );
1078                 while ( np_list != NULL ) {
1079                         LDAP_LIST_REMOVE( np_list, np_link );
1080                         np_prev = np_list;
1081                         np_list = LDAP_LIST_NEXT( np_list, np_link );
1082                         op->o_tag = LDAP_REQ_DELETE;
1083                         op->o_callback = &cb;
1084                         cb.sc_response = null_callback;
1085                         cb.sc_private = si;
1086                         op->o_req_dn = *np_prev->dn;
1087                         op->o_req_ndn = *np_prev->ndn;
1088                         op->o_bd->be_delete( op, &rs );
1089                         ber_bvfree( np_prev->dn );
1090                         ber_bvfree( np_prev->ndn );
1091                         op->o_req_dn.bv_val = NULL;
1092                         op->o_req_ndn.bv_val = NULL;
1093                         ch_free( np_prev );
1094                 }
1095         }
1096
1097         if ( op->o_req_dn.bv_val )
1098                 ch_free( op->o_req_dn.bv_val );
1099         if ( op->o_req_ndn.bv_val )
1100                 ch_free( op->o_req_ndn.bv_val );
1101         filter_free( op->ors_filter );
1102         ch_free( op->ors_filterstr.bv_val );
1103 }
1104
1105
1106 static void
1107 syncrepl_add_glue(
1108         LDAP *ld,
1109         Operation* op,
1110         Entry *e,
1111         Modifications* modlist,
1112         int syncstate,
1113         struct berval* syncUUID,
1114         struct berval* syncCookie
1115 )
1116 {
1117         Backend *be = op->o_bd;
1118         syncinfo_t *si = op->o_callback->sc_private;
1119         struct berval   uuid_bv = {0, NULL};
1120         slap_callback cb;
1121         Attribute       *a;
1122         int     rc;
1123         char    uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
1124         int levels = 0;
1125         int i, j, k;
1126         struct berval dn = {0, NULL};
1127         struct berval pdn = {0, NULL};
1128         struct berval ndn = {0, NULL};
1129         struct berval rdn = {0, NULL};
1130         Entry   *glue;
1131         SlapReply       rs = {REP_RESULT};
1132         Connection *conn = op->o_conn;
1133
1134         op->o_tag = LDAP_REQ_ADD;
1135         op->o_callback = &cb;
1136         cb.sc_response = null_callback;
1137         cb.sc_private = si;
1138
1139         ber_dupbv( &dn, &e->e_nname );
1140         ber_dupbv( &pdn, &e->e_nname );
1141
1142         while ( !be_issuffix ( be, &pdn )) {
1143                 dnParent( &dn, &pdn );
1144                 ch_free( dn.bv_val );
1145                 ber_dupbv( &dn, &pdn );
1146                 levels++;
1147         }
1148
1149         for ( i = 0; i <= levels; i++ ) {
1150                 glue = (Entry*) ch_calloc( 1, sizeof(Entry) );
1151                 ch_free( dn.bv_val );
1152                 ch_free( pdn.bv_val );
1153                 ber_dupbv( &dn, &e->e_nname );
1154                 ber_dupbv( &pdn, &e->e_nname );
1155                 j = levels - i;
1156                 for ( k = 0; k < j; k++ ) {
1157                         dnParent( &dn, &pdn );
1158                         ch_free( dn.bv_val );
1159                         ber_dupbv( &dn, &pdn );
1160                 }
1161
1162                 dnPrettyNormal( 0, &dn, &pdn, &ndn, op->o_tmpmemctx );
1163                 ber_dupbv( &glue->e_name, &pdn );
1164                 ber_dupbv( &glue->e_nname, &ndn );
1165                 ch_free( dn.bv_val );
1166                 ch_free( pdn.bv_val );
1167                 ch_free( ndn.bv_val );
1168
1169                 a = ch_calloc( 1, sizeof( Attribute ));
1170                 a->a_desc = slap_schema.si_ad_objectClass;
1171                 a->a_vals = ch_calloc( 3, sizeof( struct berval ));
1172                 ber_str2bv( "top", strlen("top"), 1, &a->a_vals[0] );
1173                 ber_str2bv( "glue", strlen("glue"), 1, &a->a_vals[1] );
1174                 a->a_vals[2].bv_len = 0;
1175                 a->a_vals[2].bv_val = NULL;
1176                 a->a_next = glue->e_attrs;
1177                 glue->e_attrs = a;
1178
1179                 a = ch_calloc( 1, sizeof( Attribute ));
1180                 a->a_desc = slap_schema.si_ad_structuralObjectClass;
1181                 a->a_vals = ch_calloc( 2, sizeof( struct berval ));
1182                 ber_str2bv( "glue", strlen("glue"), 1, &a->a_vals[0] );
1183                 a->a_vals[1].bv_len = 0;
1184                 a->a_vals[1].bv_val = NULL;
1185                 a->a_next = glue->e_attrs;
1186                 glue->e_attrs = a;
1187
1188                 if ( !strcmp( e->e_nname.bv_val, glue->e_nname.bv_val )) {
1189                         op->o_req_dn = e->e_name;
1190                         op->o_req_ndn = e->e_nname;
1191                         op->ora_e = e;
1192                         rc = be->be_add ( op, &rs );
1193                         if ( rc == LDAP_SUCCESS )
1194                                 be_entry_release_w( op, e );
1195                         else 
1196                                 entry_free( e );
1197                         entry_free( glue );
1198                 } else {
1199                         op->o_req_dn = glue->e_name;
1200                         op->o_req_ndn = glue->e_nname;
1201                         op->ora_e = glue;
1202                         rc = be->be_add ( op, &rs );
1203                         if ( rc == LDAP_SUCCESS ) {
1204                                 be_entry_release_w( op, glue );
1205                         } else {
1206                         /* incl. ALREADY EXIST */
1207                                 entry_free( glue );
1208                         }
1209                 }
1210         }
1211
1212         return;
1213 }
1214
1215 static void
1216 syncrepl_updateCookie(
1217         LDAP *ld,
1218         Operation *op,
1219         struct berval *pdn,
1220         struct berval *syncCookie
1221 )
1222 {
1223         Backend *be = op->o_bd;
1224         syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
1225         Modifications *ml;
1226         Modifications *mlnext;
1227         Modifications *mod;
1228         Modifications *modlist;
1229         Modifications **modtail = &modlist;
1230
1231         struct berval* ocbva = NULL;
1232         struct berval* cnbva = NULL;
1233         struct berval* ssbva = NULL;
1234         struct berval* scbva = NULL;
1235
1236         char substr[64];
1237         char rdnstr[67];
1238         const char      *text;
1239         char txtbuf[SLAP_TEXT_BUFLEN];
1240         size_t textlen = sizeof txtbuf;
1241
1242         Entry* e;
1243         int rc;
1244
1245         struct berval sub_bv = { 0, NULL };
1246         struct berval psubrdn = { 0, NULL };
1247         
1248         slap_callback cb;
1249         SlapReply       rs = {REP_RESULT};
1250
1251         ocbva = ( struct berval * ) ch_calloc( 4, sizeof( struct berval ));
1252         cnbva = ( struct berval * ) ch_calloc( 2, sizeof( struct berval ));
1253         ssbva = ( struct berval * ) ch_calloc( 2, sizeof( struct berval ));
1254         scbva = ( struct berval * ) ch_calloc( 2, sizeof( struct berval ));
1255
1256         /* update in memory cookie */
1257         if ( si->syncCookie != NULL ) {
1258                 ber_bvfree( si->syncCookie );
1259         }
1260         si->syncCookie = ber_dupbv( NULL, syncCookie );
1261         ber_str2bv( "top", strlen("top"), 1, &ocbva[0] );
1262         ber_str2bv( "subentry", strlen("subentry"), 1, &ocbva[1] );
1263         ber_str2bv( "syncConsumerSubentry",
1264                         strlen("syncConsumerSubentry"), 1, &ocbva[2] );
1265         ocbva[3].bv_len = 0;
1266         ocbva[3].bv_val = NULL;
1267
1268         mod = (Modifications *) ch_malloc( sizeof( Modifications ));
1269         mod->sml_op = LDAP_MOD_REPLACE;
1270         mod->sml_next = NULL;
1271         mod->sml_desc = NULL;
1272         ber_str2bv( "objectClass", strlen("objectClass"), 1, &mod->sml_type );
1273         mod->sml_bvalues = ocbva;
1274         mod->sml_nvalues = ocbva;
1275         *modtail = mod;
1276         modtail = &mod->sml_next;
1277
1278         sprintf( substr, "syncrepl%d", si->id );
1279         sprintf( rdnstr, "cn=%s", substr );
1280         ber_str2bv( substr, strlen( substr ), 1, &cnbva[0] );
1281         ber_str2bv( rdnstr, strlen( rdnstr ), 1, &psubrdn );
1282         cnbva[1].bv_len = 0;
1283         cnbva[1].bv_val = NULL;
1284         mod = (Modifications *) ch_malloc( sizeof( Modifications ));
1285         mod->sml_op = LDAP_MOD_REPLACE;
1286         mod->sml_next = NULL;
1287         mod->sml_desc = NULL;
1288         ber_str2bv( "cn", strlen("cn"), 1, &mod->sml_type );
1289         mod->sml_bvalues = cnbva;
1290         mod->sml_nvalues = cnbva;
1291         *modtail = mod;
1292         modtail = &mod->sml_next;
1293
1294         ber_dupbv( &scbva[0], si->syncCookie );
1295         scbva[1].bv_len = 0;
1296         scbva[1].bv_val = NULL;
1297         mod = (Modifications *) ch_malloc( sizeof( Modifications ));
1298         mod->sml_op = LDAP_MOD_REPLACE;
1299         mod->sml_next = NULL;
1300         mod->sml_desc = NULL;
1301         ber_str2bv( "syncreplCookie", strlen("syncreplCookie"),
1302                                                 1, &mod->sml_type );
1303         mod->sml_bvalues = scbva;
1304         mod->sml_nvalues = scbva;
1305         *modtail = mod;
1306         modtail = &mod->sml_next;
1307
1308         ber_str2bv( "{}", strlen("{}"), 1, &ssbva[0] );
1309         ssbva[1].bv_len = 0;
1310         ssbva[1].bv_val = NULL;
1311         mod = (Modifications *) ch_malloc( sizeof( Modifications ));
1312         mod->sml_op = LDAP_MOD_REPLACE;
1313         mod->sml_next = NULL;
1314         mod->sml_desc = NULL;
1315         ber_str2bv( "subtreeSpecification",
1316                         strlen("subtreeSpecification"), 1, &mod->sml_type );
1317         mod->sml_bvalues = ssbva;
1318         mod->sml_nvalues = ssbva;
1319         *modtail = mod;
1320         modtail = &mod->sml_next;
1321
1322         rc = slap_mods_check_syncrepl( op, &modlist, &text, txtbuf, textlen, NULL );
1323
1324         if ( rc != LDAP_SUCCESS ) {
1325 #ifdef NEW_LOGGING
1326                 LDAP_LOG( OPERATION, ERR,
1327                                 "syncrepl_updateCookie: mods check (%s)\n", text, 0, 0 );
1328 #else
1329                 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods check (%s)\n",
1330                          text, 0, 0 );
1331 #endif
1332         }
1333
1334         op->o_tag = LDAP_REQ_ADD;
1335         rc = slap_mods_opattrs_syncrepl( op, modlist, modtail, &text,txtbuf, textlen );
1336
1337         if( rc != LDAP_SUCCESS ) {
1338 #ifdef NEW_LOGGING
1339                 LDAP_LOG( OPERATION, ERR,
1340                                 "syncrepl_updateCookie: mods opattrs (%s)\n", text, 0, 0 );
1341 #else
1342                 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods opattrs (%s)\n",
1343                          text, 0, 0 );
1344 #endif
1345         }
1346
1347         e = ( Entry * ) ch_calloc( 1, sizeof( Entry ));
1348
1349         build_new_dn( &sub_bv, pdn, &psubrdn );
1350         dnPrettyNormal( NULL, &sub_bv, &e->e_name, &e->e_nname, op->o_tmpmemctx );
1351         ch_free( sub_bv.bv_val );
1352         ch_free( psubrdn.bv_val );
1353
1354         e->e_attrs = NULL;
1355
1356         rc = slap_mods2entry_syncrepl( modlist, &e, 1, &text, txtbuf, textlen );
1357
1358         if( rc != LDAP_SUCCESS ) {
1359 #ifdef NEW_LOGGING
1360                 LDAP_LOG( OPERATION, ERR,
1361                                 "syncrepl_updateCookie: mods2entry (%s)\n", text, 0, 0 );
1362 #else
1363                 Debug( LDAP_DEBUG_ANY, "syncrepl_updateCookie: mods2entry (%s)\n",
1364                          text, 0, 0 );
1365 #endif
1366         }
1367
1368         cb.sc_response = null_callback;
1369         cb.sc_private = si;
1370
1371         op->o_callback = &cb;
1372         op->o_req_dn = e->e_name;
1373         op->o_req_ndn = e->e_nname;
1374
1375         /* update persistent cookie */
1376 update_cookie_retry:
1377         op->o_tag = LDAP_REQ_MODIFY;
1378         op->orm_modlist = modlist;
1379         rc = be->be_modify( op, &rs );
1380         if ( rc != LDAP_SUCCESS ) {
1381                 if ( rc == LDAP_REFERRAL ||
1382                          rc == LDAP_NO_SUCH_OBJECT ) {
1383                         op->o_tag = LDAP_REQ_ADD;
1384                         op->ora_e = e;
1385                         rc = be->be_add( op, &rs );
1386                         if ( rc != LDAP_SUCCESS ) {
1387                                 if ( rc == LDAP_ALREADY_EXISTS ) {
1388                                         goto update_cookie_retry;
1389                                 } else if ( rc == LDAP_REFERRAL ||
1390                                                         rc == LDAP_NO_SUCH_OBJECT ) {
1391 #ifdef NEW_LOGGING
1392                                         LDAP_LOG( OPERATION, ERR,
1393                                                 "cookie will be non-persistent\n",
1394                                                 0, 0, 0 );
1395 #else
1396                                         Debug( LDAP_DEBUG_ANY,
1397                                                 "cookie will be non-persistent\n",
1398                                                 0, 0, 0 );
1399 #endif
1400                                 } else {
1401 #ifdef NEW_LOGGING
1402                                         LDAP_LOG( OPERATION, ERR,
1403                                                 "be_add failed (%d)\n",
1404                                                 rc, 0, 0 );
1405 #else
1406                                         Debug( LDAP_DEBUG_ANY,
1407                                                 "be_add failed (%d)\n",
1408                                                 rc, 0, 0 );
1409 #endif
1410                                 }
1411                         } else {
1412                                 goto done;
1413                         }
1414                 } else {
1415 #ifdef NEW_LOGGING
1416                         LDAP_LOG( OPERATION, ERR,
1417                                 "be_modify failed (%d)\n", rc, 0, 0 );
1418 #else
1419                         Debug( LDAP_DEBUG_ANY,
1420                                 "be_modify failed (%d)\n", rc, 0, 0 );
1421 #endif
1422                 }
1423         }
1424
1425         if ( e != NULL )
1426                 entry_free( e );
1427
1428 done :
1429
1430         for ( ml = modlist; ml != NULL; ml = mlnext ) {
1431                 mlnext = ml->sml_next;
1432                 free( ml );
1433         }
1434
1435         return;
1436 }
1437
1438
1439 static
1440 int slap_mods_check_syncrepl(
1441         Operation *op,
1442         Modifications **mlp,
1443         const char **text,
1444         char *textbuf,
1445         size_t textlen,
1446         void *ctx )
1447 {
1448         int rc;
1449         Backend *be = op->o_bd;
1450         syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
1451         AttributeDescription** descs;
1452         int i;
1453         Modifications *prevml = NULL;
1454         Modifications *nextml = NULL;
1455         Modifications *ml = *mlp;
1456
1457         while ( ml != NULL ) {
1458                 AttributeDescription *ad = NULL;
1459
1460                 /* convert to attribute description */
1461                 rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, text );
1462
1463                 if( rc != LDAP_SUCCESS ) {
1464                         snprintf( textbuf, textlen, "%s: %s",
1465                                                 ml->sml_type.bv_val, *text );
1466                         *text = textbuf;
1467                         return rc;
1468                 }
1469
1470                 ad = ml->sml_desc;
1471
1472                 if ( si->lastmod == LASTMOD_REQ ) {
1473                         descs = del_descs_lastmod;
1474                 } else {
1475                         descs = del_descs;
1476                 }
1477
1478                 for ( i = 0; descs[i] != NULL; i++ ) {
1479                         if ( ad == descs[i] ) {
1480                                 if ( prevml == NULL ) {
1481                                         mlp = &ml->sml_next;
1482                                         prevml = NULL;
1483                                 } else {
1484                                         prevml->sml_next = ml->sml_next;
1485                                 }
1486                                 slap_mod_free( &ml->sml_mod, 0 );
1487                                 nextml = ml->sml_next;
1488                                 free( ml );
1489                                 ml = nextml;
1490                                 continue;
1491                         }
1492                 }
1493
1494                 if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
1495                                 && !slap_ad_is_binary( ad )) {
1496                         /* attribute requires binary transfer */
1497                         snprintf( textbuf, textlen,
1498                                         "%s: requires ;binary transfer",
1499                                         ml->sml_type.bv_val );
1500                         *text = textbuf;
1501                         return LDAP_UNDEFINED_TYPE;
1502                 }
1503
1504                 if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
1505                                         && slap_ad_is_binary( ad )) {
1506                         /* attribute requires binary transfer */
1507                         snprintf( textbuf, textlen,
1508                                         "%s: disallows ;binary transfer",
1509                                         ml->sml_type.bv_val );
1510                         *text = textbuf;
1511                         return LDAP_UNDEFINED_TYPE;
1512                 }
1513
1514                 if( slap_ad_is_tag_range( ad )) {
1515                         /* attribute requires binary transfer */
1516                         snprintf( textbuf, textlen,
1517                                         "%s: inappropriate use of tag range option",
1518                                         ml->sml_type.bv_val );
1519                         *text = textbuf;
1520                         return LDAP_UNDEFINED_TYPE;
1521                 }
1522
1523                 if ( is_at_obsolete( ad->ad_type ) &&
1524                                 ( ml->sml_op == LDAP_MOD_ADD || ml->sml_values != NULL ) ) {
1525                         /*
1526                          * attribute is obsolete,
1527                          * only allow replace/delete with no values
1528                          */
1529                         snprintf( textbuf, textlen,
1530                                         "%s: attribute is obsolete",
1531                                         ml->sml_type.bv_val );
1532                         *text = textbuf;
1533                         return LDAP_CONSTRAINT_VIOLATION;
1534                 }
1535
1536                 /*
1537                  * check values
1538                  */
1539                 if( ml->sml_values != NULL ) {
1540                         ber_len_t nvals;
1541                         slap_syntax_validate_func *validate =
1542                         ad->ad_type->sat_syntax->ssyn_validate;
1543                         slap_syntax_transform_func *pretty =
1544                         ad->ad_type->sat_syntax->ssyn_pretty;
1545
1546                         if( !pretty && !validate ) {
1547                                 *text = "no validator for syntax";
1548                                 snprintf( textbuf, textlen,
1549                                                 "%s: no validator for syntax %s",
1550                                                 ml->sml_type.bv_val,
1551                                                 ad->ad_type->sat_syntax->ssyn_oid );
1552                                 *text = textbuf;
1553                                 return LDAP_INVALID_SYNTAX;
1554                         }
1555
1556                         /*
1557                          * check that each value is valid per syntax
1558                          * and pretty if appropriate
1559                          */
1560                         for( nvals = 0; ml->sml_values[nvals].bv_val; nvals++ ) {
1561                                 struct berval pval = {0, NULL};
1562                                 if( pretty ) {
1563                                         rc = pretty( ad->ad_type->sat_syntax,
1564                                                         &ml->sml_values[nvals], &pval, ctx );
1565                                 } else {
1566                                         rc = validate( ad->ad_type->sat_syntax,
1567                                                         &ml->sml_values[nvals] );
1568                                 }
1569
1570                                 if( rc != 0 ) {
1571                                         snprintf( textbuf, textlen,
1572                                                         "%s: value #%ld invalid per syntax",
1573                                                         ml->sml_type.bv_val, (long) nvals );
1574                                         *text = textbuf;
1575                                         return LDAP_INVALID_SYNTAX;
1576                                 }
1577
1578                                 if( pretty ) {
1579                                         ber_memfree( ml->sml_values[nvals].bv_val );
1580                                         ml->sml_values[nvals] = pval;
1581                                 }
1582                         }
1583
1584                         /*
1585                          * a rough single value check... an additional check is needed
1586                          * to catch add of single value to existing single valued attribute
1587                          */
1588                         if ((ml->sml_op == LDAP_MOD_ADD || ml->sml_op == LDAP_MOD_REPLACE)
1589                                         && nvals > 1 && is_at_single_value( ad->ad_type )) {
1590                                 snprintf( textbuf, textlen,
1591                                                 "%s: multiple values provided",
1592                                                 ml->sml_type.bv_val );
1593                                 *text = textbuf;
1594                                 return LDAP_CONSTRAINT_VIOLATION;
1595                         }
1596
1597                         if( nvals && ad->ad_type->sat_equality &&
1598                                         ad->ad_type->sat_equality->smr_normalize ) {
1599                                 ml->sml_nvalues = ch_malloc( (nvals+1)*sizeof(struct berval) );
1600                                 for( nvals = 0; ml->sml_values[nvals].bv_val; nvals++ ) {
1601                                         rc = ad->ad_type->sat_equality->smr_normalize( 0,
1602                                                         ad->ad_type->sat_syntax, ad->ad_type->sat_equality,
1603                                                         &ml->sml_values[nvals], &ml->sml_nvalues[nvals], ctx );
1604                                         if( rc ) {
1605 #ifdef NEW_LOGGING
1606                                                 LDAP_LOG( OPERATION, DETAIL1,
1607                                                                 "str2entry:  NULL (ssyn_normalize %d)\n", rc, 0, 0 );
1608 #else
1609                                                 Debug( LDAP_DEBUG_ANY,
1610                                                                 "<= str2entry NULL (ssyn_normalize %d)\n", rc, 0, 0 );
1611 #endif
1612                                                 snprintf( textbuf, textlen,
1613                                                                 "%s: value #%ld normalization failed",
1614                                                                 ml->sml_type.bv_val, (long) nvals );
1615                                                 *text = textbuf;
1616                                                 return rc;
1617                                         }
1618                                 }
1619                                 ml->sml_nvalues[nvals].bv_val = NULL;
1620                                 ml->sml_nvalues[nvals].bv_len = 0;
1621                         }
1622                 }
1623                 prevml = ml;
1624                 ml = ml->sml_next;
1625         }
1626
1627         return LDAP_SUCCESS;
1628 }
1629
1630 static
1631 int slap_mods_opattrs_syncrepl(
1632         Operation *op,
1633         Modifications *mods,
1634         Modifications **modtail,
1635         const char **text,
1636         char *textbuf, size_t textlen )
1637 {
1638         struct berval name = {0, NULL};
1639         struct berval timestamp = {0, NULL};
1640         struct berval csn = {0, NULL};
1641         struct berval nname = {0, NULL};
1642         char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
1643         char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
1644         Modifications *mod;
1645         Backend *be = op->o_bd;
1646         syncinfo_t *si = ( syncinfo_t * ) be->syncinfo;
1647
1648         int mop = LDAP_MOD_REPLACE;
1649
1650         assert( modtail != NULL );
1651         assert( *modtail == NULL );
1652
1653         if( si->lastmod == LASTMOD_GEN ) {
1654                 struct tm *ltm;
1655                 time_t now = slap_get_time();
1656
1657                 ldap_pvt_thread_mutex_lock( &gmtime_mutex );
1658                 ltm = gmtime( &now );
1659                 lutil_gentime( timebuf, sizeof(timebuf), ltm );
1660
1661                 csn.bv_len = lutil_csnstr( csnbuf, sizeof( csnbuf ), 0, 0 );
1662                 ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
1663                 csn.bv_val = csnbuf;
1664
1665                 timestamp.bv_val = timebuf;
1666                 timestamp.bv_len = strlen(timebuf);
1667
1668                 if( op->o_dn.bv_len == 0 ) {
1669                         name.bv_val = SLAPD_ANONYMOUS;
1670                         name.bv_len = sizeof(SLAPD_ANONYMOUS)-1;
1671                         nname = name;
1672                 } else {
1673                         name = op->o_dn;
1674                         nname = op->o_ndn;
1675                 }
1676         }
1677
1678         if( op->o_tag == LDAP_REQ_ADD ) {
1679                 struct berval tmpval = {0, NULL};
1680
1681                 if( global_schemacheck ) {
1682                         int rc = mods_structural_class( mods, &tmpval,
1683                                                                         text, textbuf, textlen );
1684                         if( rc != LDAP_SUCCESS ) {
1685                                 return rc;
1686                         }
1687
1688                         mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
1689                         mod->sml_op = mop;
1690                         mod->sml_type.bv_val = NULL;
1691                         mod->sml_desc = slap_schema.si_ad_structuralObjectClass;
1692                         mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1693                         ber_dupbv( &mod->sml_values[0], &tmpval );
1694                         mod->sml_values[1].bv_len = 0;
1695                         mod->sml_values[1].bv_val = NULL;
1696                         assert( mod->sml_values[0].bv_val );
1697                         mod->sml_nvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1698                         ber_dupbv( &mod->sml_nvalues[0], &tmpval );
1699                         mod->sml_nvalues[1].bv_len = 0;
1700                         mod->sml_nvalues[1].bv_val = NULL;
1701                         assert( mod->sml_nvalues[0].bv_val );
1702                         *modtail = mod;
1703                         modtail = &mod->sml_next;
1704                 }
1705
1706                 if( si->lastmod == LASTMOD_GEN ) {
1707                         mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
1708                         mod->sml_op = mop;
1709                         mod->sml_type.bv_val = NULL;
1710                         mod->sml_desc = slap_schema.si_ad_creatorsName;
1711                         mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1712                         ber_dupbv( &mod->sml_values[0], &name );
1713                         mod->sml_values[1].bv_len = 0;
1714                         mod->sml_values[1].bv_val = NULL;
1715                         assert( mod->sml_values[0].bv_val );
1716                         mod->sml_nvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1717                         ber_dupbv( &mod->sml_nvalues[0], &nname );
1718                         mod->sml_nvalues[1].bv_len = 0;
1719                         mod->sml_nvalues[1].bv_val = NULL;
1720                         assert( mod->sml_nvalues[0].bv_val );
1721                         *modtail = mod;
1722                         modtail = &mod->sml_next;
1723
1724                         mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
1725                         mod->sml_op = mop;
1726                         mod->sml_type.bv_val = NULL;
1727                         mod->sml_desc = slap_schema.si_ad_createTimestamp;
1728                         mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1729                         ber_dupbv( &mod->sml_values[0], &timestamp );
1730                         mod->sml_values[1].bv_len = 0;
1731                         mod->sml_values[1].bv_val = NULL;
1732                         assert( mod->sml_values[0].bv_val );
1733                         mod->sml_nvalues = NULL;
1734                         *modtail = mod;
1735                         modtail = &mod->sml_next;
1736                 }
1737         }
1738
1739         if( si->lastmod == LASTMOD_GEN ) {
1740                 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
1741                 mod->sml_op = mop;
1742                 mod->sml_type.bv_val = NULL;
1743                 mod->sml_desc = slap_schema.si_ad_entryCSN;
1744                 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1745                 ber_dupbv( &mod->sml_values[0], &csn );
1746                 mod->sml_values[1].bv_len = 0;
1747                 mod->sml_values[1].bv_val = NULL;
1748                 assert( mod->sml_values[0].bv_val );
1749                 mod->sml_nvalues = NULL;
1750                 *modtail = mod;
1751                 modtail = &mod->sml_next;
1752
1753                 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
1754                 mod->sml_op = mop;
1755                 mod->sml_type.bv_val = NULL;
1756                 mod->sml_desc = slap_schema.si_ad_modifiersName;
1757                 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1758                 ber_dupbv( &mod->sml_values[0], &name );
1759                 mod->sml_values[1].bv_len = 0;
1760                 mod->sml_values[1].bv_val = NULL;
1761                 assert( mod->sml_values[0].bv_val );
1762                 mod->sml_nvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1763                 ber_dupbv( &mod->sml_nvalues[0], &nname );
1764                 mod->sml_nvalues[1].bv_len = 0;
1765                 mod->sml_nvalues[1].bv_val = NULL;
1766                 assert( mod->sml_nvalues[0].bv_val );
1767                 *modtail = mod;
1768                 modtail = &mod->sml_next;
1769
1770                 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
1771                 mod->sml_op = mop;
1772                 mod->sml_type.bv_val = NULL;
1773                 mod->sml_desc = slap_schema.si_ad_modifyTimestamp;
1774                 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1775                 ber_dupbv( &mod->sml_values[0], &timestamp );
1776                 mod->sml_values[1].bv_len = 0;
1777                 mod->sml_values[1].bv_val = NULL;
1778                 assert( mod->sml_values[0].bv_val );
1779                 mod->sml_nvalues = NULL;
1780                 *modtail = mod;
1781                 modtail = &mod->sml_next;
1782         }
1783
1784         *modtail = NULL;
1785         return LDAP_SUCCESS;
1786 }
1787
1788
1789 static
1790 int slap_mods2entry_syncrepl(
1791         Modifications *mods,
1792         Entry **e,
1793         int repl_user,
1794         const char **text,
1795         char *textbuf, size_t textlen )
1796 {
1797         Attribute **tail = &(*e)->e_attrs;
1798         assert( *tail == NULL );
1799
1800         *text = textbuf;
1801
1802         for( ; mods != NULL; mods = mods->sml_next ) {
1803                 Attribute *attr;
1804
1805                 assert( mods->sml_desc != NULL );
1806
1807                 attr = attr_find( (*e)->e_attrs, mods->sml_desc );
1808
1809                 if( attr != NULL ) {
1810 #define SLURPD_FRIENDLY
1811 #ifdef SLURPD_FRIENDLY
1812                         ber_len_t i,j;
1813
1814                         if( !repl_user ) {
1815                                 snprintf( textbuf, textlen,
1816                                         "attribute '%s' provided more than once",
1817                                         mods->sml_desc->ad_cname.bv_val );
1818                                 return LDAP_TYPE_OR_VALUE_EXISTS;
1819                         }
1820
1821                         for( i=0; attr->a_vals[i].bv_val; i++ ) {
1822                                 /* count them */
1823                         }
1824                         for( j=0; mods->sml_values[j].bv_val; j++ ) {
1825                                 /* count them */
1826                         }
1827                         j++;    /* NULL */
1828                         
1829                         attr->a_vals = ch_realloc( attr->a_vals,
1830                                 sizeof( struct berval ) * (i+j) );
1831
1832                         /* should check for duplicates */
1833
1834                         AC_MEMCPY( &attr->a_vals[i], mods->sml_values,
1835                                 sizeof( struct berval ) * j );
1836
1837                         if( attr->a_nvals ) {
1838                                 attr->a_nvals = ch_realloc( attr->a_nvals,
1839                                         sizeof( struct berval ) * (i+j) );
1840
1841                                 AC_MEMCPY( &attr->a_nvals[i], mods->sml_nvalues,
1842                                         sizeof( struct berval ) * j );
1843
1844                                 /* trim the mods array */
1845                                 ch_free( mods->sml_nvalues );
1846                                 mods->sml_nvalues = NULL;
1847                         }
1848
1849                         continue;
1850 #else
1851                         snprintf( textbuf, textlen,
1852                                 "attribute '%s' provided more than once",
1853                                 mods->sml_desc->ad_cname.bv_val );
1854                         return LDAP_TYPE_OR_VALUE_EXISTS;
1855 #endif
1856                 }
1857
1858                 if( mods->sml_values[1].bv_val != NULL ) {
1859                         /* check for duplicates */
1860                         int             i, j;
1861                         MatchingRule *mr = mods->sml_desc->ad_type->sat_equality;
1862
1863                         /* check if the values we're adding already exist */
1864                         if( mr == NULL || !mr->smr_match ) {
1865                                 for ( i = 0; mods->sml_bvalues[i].bv_val != NULL; i++ ) {
1866                                         /* test asserted values against themselves */
1867                                         for( j = 0; j < i; j++ ) {
1868                                                 if ( bvmatch( &mods->sml_bvalues[i],
1869                                                         &mods->sml_bvalues[j] ) ) {
1870                                                         /* value exists already */
1871                                                         snprintf( textbuf, textlen,
1872                                                                 "%s: value #%d provided more than once",
1873                                                                 mods->sml_desc->ad_cname.bv_val, j );
1874                                                         return LDAP_TYPE_OR_VALUE_EXISTS;
1875                                                 }
1876                                         }
1877                                 }
1878
1879                         } else {
1880                                 int             rc;
1881                                 const char      *text = NULL;
1882                                 char            textbuf[ SLAP_TEXT_BUFLEN ]  = { '\0' };
1883                                 
1884                                 rc = modify_check_duplicates( mods->sml_desc, mr,
1885                                                 NULL, mods->sml_bvalues, 0,
1886                                                 &text, textbuf, sizeof( textbuf ) );
1887
1888                                 if ( rc != LDAP_SUCCESS ) {
1889                                         return rc;
1890                                 }
1891                         }
1892                 }
1893
1894                 attr = ch_calloc( 1, sizeof(Attribute) );
1895
1896                 /* move ad to attr structure */
1897                 attr->a_desc = mods->sml_desc;
1898
1899                 /* move values to attr structure */
1900                 /*      should check for duplicates */
1901                 attr->a_vals = mods->sml_values;
1902
1903                 attr->a_nvals = mods->sml_nvalues;
1904
1905                 *tail = attr;
1906                 tail = &attr->a_next;
1907         }
1908
1909         return LDAP_SUCCESS;
1910 }
1911
1912 void
1913 avl_ber_bvfree( void *bv )
1914 {
1915         if( bv == NULL ) {
1916                 return;
1917         }
1918         if ( ((struct berval *)bv)->bv_val != NULL ) {
1919                 ber_memfree ( ((struct berval *)bv)->bv_val );
1920         }
1921         ber_memfree ( (char *) bv );
1922 }
1923
1924 static int
1925 cookie_callback(
1926         Operation* op,
1927         SlapReply* rs
1928 )
1929 {
1930         syncinfo_t *si = op->o_callback->sc_private;
1931         Attribute *a;
1932
1933         if ( rs->sr_type != REP_SEARCH ) return LDAP_SUCCESS;
1934
1935         a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_syncreplCookie );
1936
1937         if ( a == NULL ) {
1938                 si->syncCookie = NULL;
1939         } else {
1940                 si->syncCookie = ber_dupbv( NULL, &a->a_vals[0] );
1941         }
1942         return LDAP_SUCCESS;
1943 }
1944
1945 static int
1946 dn_callback(
1947         Operation*      op,
1948         SlapReply*      rs
1949 )
1950 {
1951         syncinfo_t *si = op->o_callback->sc_private;
1952         
1953         if ( rs->sr_type == REP_SEARCH ) {
1954                 si->syncUUID_ndn = &rs->sr_entry->e_nname;
1955         }
1956
1957         return LDAP_SUCCESS;
1958 }
1959
1960 static int
1961 nonpresent_callback(
1962         Operation*      op,
1963         SlapReply*      rs
1964 )
1965 {
1966         syncinfo_t *si = op->o_callback->sc_private;
1967         Attribute *a;
1968         int count = 0;
1969         struct berval* present_uuid = NULL;
1970         slap_callback cb;
1971         SlapReply       rs_cb = {REP_RESULT};
1972         struct nonpresent_entry *np_entry;
1973
1974         if ( rs->sr_type == REP_RESULT ) {
1975                 count = avl_free( si->presentlist, avl_ber_bvfree );
1976                 return LDAP_SUCCESS;
1977         } else if ( rs->sr_type == REP_SEARCH ) {
1978                 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
1979
1980                 if ( a == NULL )
1981                         return 0;
1982
1983                 present_uuid = avl_find( si->presentlist, &a->a_vals[0], syncuuid_cmp );
1984
1985                 if ( present_uuid == NULL ) {
1986                         np_entry = (struct nonpresent_entry *)
1987                                                 ch_calloc( 1, sizeof( struct nonpresent_entry ));
1988                         np_entry->dn = ber_dupbv( NULL, &rs->sr_entry->e_name );
1989                         np_entry->ndn = ber_dupbv( NULL, &rs->sr_entry->e_nname );
1990                         LDAP_LIST_INSERT_HEAD( &si->nonpresentlist, np_entry, np_link );
1991                 } else {
1992                         avl_delete( &si->presentlist,
1993                                         &a->a_vals[0], syncuuid_cmp );
1994                 }
1995                 return LDAP_SUCCESS;
1996         } else {
1997                 return LDAP_SUCCESS;
1998         }
1999
2000 }
2001
2002 static int
2003 null_callback(
2004         Operation*      op,
2005         SlapReply*      rs
2006 )
2007 {
2008         if ( rs->sr_err != LDAP_SUCCESS &&
2009                  rs->sr_err != LDAP_REFERRAL &&
2010                  rs->sr_err != LDAP_ALREADY_EXISTS &&
2011                  rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
2012 #ifdef NEW_LOGGING
2013                 LDAP_LOG( OPERATION, ERR,
2014                         "null_callback : error code 0x%x\n",
2015                         rs->sr_err, 0, 0 );
2016 #else
2017                 Debug( LDAP_DEBUG_ANY,
2018                         "null_callback : error code 0x%x\n",
2019                         rs->sr_err, 0, 0 );
2020 #endif
2021         }
2022         return LDAP_SUCCESS;
2023 }
2024
2025
2026 char **
2027 str2clist( char **out, char *in, const char *brkstr )
2028 {
2029         char    *str;
2030         char    *s;
2031         char    *lasts;
2032         int     i, j;
2033         const char *text;
2034         char    **new;
2035
2036         /* find last element in list */
2037         for (i = 0; out && out[i]; i++);
2038         
2039         /* protect the input string from strtok */
2040         str = ch_strdup( in );
2041
2042         /* Count words in string */
2043         j=1;
2044         for ( s = str; *s; s++ ) {
2045                 if ( strchr( brkstr, *s ) != NULL ) {
2046                         j++;
2047                 }
2048         }
2049
2050         out = ch_realloc( out, ( i + j + 1 ) * sizeof( char * ) );
2051         new = out + i;
2052         for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
2053                 s != NULL;
2054                 s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
2055         {
2056                 *new = ch_strdup( s );
2057                 new++;
2058         }
2059
2060         *new = NULL;
2061         free( str );
2062         return( out );
2063 }
2064
2065 #endif