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