]> git.sur5r.net Git - openldap/blob - servers/slapd/tools/slapadd.c
misc syncrpel updates
[openldap] / servers / slapd / tools / slapadd.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 #include "portable.h"
7
8 #include <stdio.h>
9
10 #include <ac/stdlib.h>
11
12 #include <ac/ctype.h>
13 #include <ac/string.h>
14 #include <ac/socket.h>
15 #include <ac/unistd.h>
16
17 #include <lber.h>
18 #include <ldif.h>
19 #include <lutil.h>
20
21 #include "slapcommon.h"
22
23 static char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
24 static const struct berval slap_syncrepl_bvc = BER_BVC("syncreplxxx");
25 static const struct berval slap_syncrepl_cn_bvc = BER_BVC("cn=syncreplxxx");
26 static struct berval slap_syncrepl_bv = BER_BVNULL;
27 static struct berval slap_syncrepl_cn_bv = BER_BVNULL;
28
29 struct subentryinfo {
30         struct berval cn;
31         struct berval ndn;
32         struct berval rdn;
33         struct berval cookie;
34         LDAP_SLIST_ENTRY( subentryinfo ) sei_next;
35 };
36
37 int
38 main( int argc, char **argv )
39 {
40         char            *buf = NULL;
41         int         lineno;
42         int         lmax;
43         int                     rc = EXIT_SUCCESS;
44
45         const char *text;
46         char textbuf[SLAP_TEXT_BUFLEN] = { '\0' };
47         size_t textlen = sizeof textbuf;
48
49         struct berval csn;
50         struct berval maxcsn = { 0, NULL };
51         struct berval ldifcsn = { 0, NULL };
52         int match;
53         int     provider_subentry = 0;
54         struct subentryinfo *sei;
55         LDAP_SLIST_HEAD( consumer_subentry_slist, subentryinfo ) consumer_subentry;
56         Attribute *attr;
57         Entry *ctxcsn_e;
58         ID      ctxcsn_id;
59         struct berval   ctxcsn_ndn = { 0, NULL };
60         int ret;
61         struct berval bvtext;
62         int i;
63 #ifdef NEW_LOGGING
64         lutil_log_initialize(argc, argv );
65 #endif
66         slap_tool_init( "slapadd", SLAPADD, argc, argv );
67
68         LDAP_SLIST_INIT( &consumer_subentry );
69
70         if( !be->be_entry_open ||
71                 !be->be_entry_close ||
72                 !be->be_entry_put )
73         {
74                 fprintf( stderr, "%s: database doesn't support necessary operations.\n",
75                         progname );
76                 exit( EXIT_FAILURE );
77         }
78
79         lmax = 0;
80         lineno = 0;
81
82         if( be->be_entry_open( be, 1 ) != 0 ) {
83                 fprintf( stderr, "%s: could not open database.\n",
84                         progname );
85                 exit( EXIT_FAILURE );
86         }
87
88         while( ldif_read_record( ldiffp, &lineno, &buf, &lmax ) ) {
89                 Entry *e = str2entry( buf );
90
91                 /*
92                  * Initialize text buffer
93                  */
94                 bvtext.bv_len = textlen;
95                 bvtext.bv_val = textbuf;
96                 bvtext.bv_val[0] = '\0';
97
98                 if( e == NULL ) {
99                         fprintf( stderr, "%s: could not parse entry (line=%d)\n",
100                                 progname, lineno );
101                         rc = EXIT_FAILURE;
102                         if( continuemode ) continue;
103                         break;
104                 }
105
106                 /* make sure the DN is not empty */
107                 if( !e->e_nname.bv_len ) {
108                         fprintf( stderr, "%s: empty dn=\"%s\" (line=%d)\n",
109                                 progname, e->e_dn, lineno );
110                         rc = EXIT_FAILURE;
111                         entry_free( e );
112                         if( continuemode ) continue;
113                         break;
114                 }
115
116                 /* check backend */
117                 if( select_backend( &e->e_nname, is_entry_referral(e), nosubordinates )
118                         != be )
119                 {
120                         fprintf( stderr, "%s: line %d: "
121                                 "database (%s) not configured to hold \"%s\"\n",
122                                 progname, lineno,
123                                 be ? be->be_suffix[0].bv_val : "<none>",
124                                 e->e_dn );
125                         fprintf( stderr, "%s: line %d: "
126                                 "database (%s) not configured to hold \"%s\"\n",
127                                 progname, lineno,
128                                 be ? be->be_nsuffix[0].bv_val : "<none>",
129                                 e->e_ndn );
130                         rc = EXIT_FAILURE;
131                         entry_free( e );
132                         if( continuemode ) continue;
133                         break;
134                 }
135
136                 if( global_schemacheck ) {
137                         Attribute *sc = attr_find( e->e_attrs,
138                                 slap_schema.si_ad_structuralObjectClass );
139                         Attribute *oc = attr_find( e->e_attrs,
140                                 slap_schema.si_ad_objectClass );
141
142                         if( oc == NULL ) {
143                                 fprintf( stderr, "%s: dn=\"%s\" (line=%d): %s\n",
144                                         progname, e->e_dn, lineno,
145                                         "no objectClass attribute");
146                                 rc = EXIT_FAILURE;
147                                 entry_free( e );
148                                 if( continuemode ) continue;
149                                 break;
150                         }
151
152                         if( sc == NULL ) {
153                                 struct berval vals[2];
154
155                                 rc = structural_class( oc->a_vals, vals,
156                                         NULL, &text, textbuf, textlen );
157
158                                 if( rc != LDAP_SUCCESS ) {
159                                         fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n",
160                                                 progname, e->e_dn, lineno, rc, text );
161                                         rc = EXIT_FAILURE;
162                                         entry_free( e );
163                                         if( continuemode ) continue;
164                                         break;
165                                 }
166
167                                 vals[1].bv_len = 0;
168                                 vals[1].bv_val = NULL;
169
170                                 attr_merge( e, slap_schema.si_ad_structuralObjectClass,
171                                         vals, NULL /* FIXME */ );
172                         }
173
174                         /* check schema */
175                         rc = entry_schema_check( be, e, NULL, &text, textbuf, textlen );
176
177                         if( rc != LDAP_SUCCESS ) {
178                                 fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n",
179                                         progname, e->e_dn, lineno, rc, text );
180                                 rc = EXIT_FAILURE;
181                                 entry_free( e );
182                                 if( continuemode ) continue;
183                                 break;
184                         }
185                 }
186
187                 if ( SLAP_LASTMOD(be) ) {
188                         struct tm *ltm;
189                         time_t now = slap_get_time();
190                         char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
191                         struct berval vals[ 2 ];
192
193                         struct berval name, timestamp;
194
195                         struct berval nvals[ 2 ];
196                         struct berval nname;
197                         char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
198
199                         vals[1].bv_len = 0;
200                         vals[1].bv_val = NULL;
201
202                         nvals[1].bv_len = 0;
203                         nvals[1].bv_val = NULL;
204
205                         ltm = gmtime(&now);
206                         lutil_gentime( timebuf, sizeof(timebuf), ltm );
207
208                         csn.bv_len = lutil_csnstr( csnbuf, sizeof( csnbuf ), 0, 0 );
209                         csn.bv_val = csnbuf;
210
211                         timestamp.bv_val = timebuf;
212                         timestamp.bv_len = strlen(timebuf);
213
214                         if ( be->be_rootndn.bv_len == 0 ) {
215                                 name.bv_val = SLAPD_ANONYMOUS;
216                                 name.bv_len = sizeof(SLAPD_ANONYMOUS) - 1;
217                                 nname.bv_val = SLAPD_ANONYMOUS;
218                                 nname.bv_len = sizeof(SLAPD_ANONYMOUS) - 1;
219                         } else {
220                                 name = be->be_rootdn;
221                                 nname = be->be_rootndn;
222                         }
223
224                         if( attr_find( e->e_attrs, slap_schema.si_ad_entryUUID )
225                                 == NULL )
226                         {
227                                 vals[0].bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
228                                 vals[0].bv_val = uuidbuf;
229                                 attr_merge( e, slap_schema.si_ad_entryUUID, vals, NULL );
230                         }
231
232                         if( attr_find( e->e_attrs, slap_schema.si_ad_creatorsName )
233                                 == NULL )
234                         {
235                                 vals[0] = name;
236                                 nvals[0] = nname;
237                                 attr_merge( e, slap_schema.si_ad_creatorsName, vals, nvals );
238                         }
239
240                         if( attr_find( e->e_attrs, slap_schema.si_ad_modifiersName )
241                                 == NULL )
242                         {
243                                 vals[0] = name;
244                                 nvals[0] = nname;
245                                 attr_merge( e, slap_schema.si_ad_modifiersName, vals, nvals );
246                         }
247
248                         if( attr_find( e->e_attrs, slap_schema.si_ad_createTimestamp )
249                                 == NULL )
250                         {
251                                 vals[0] = timestamp;
252                                 attr_merge( e, slap_schema.si_ad_createTimestamp, vals, NULL );
253                         }
254
255                         if( attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp )
256                                 == NULL )
257                         {
258                                 vals[0] = timestamp;
259                                 attr_merge( e, slap_schema.si_ad_modifyTimestamp, vals, NULL );
260                         }
261
262                         if( attr_find( e->e_attrs, slap_schema.si_ad_entryCSN )
263                                 == NULL )
264                         {
265                                 vals[0] = csn;
266                                 attr_merge( e, slap_schema.si_ad_entryCSN, vals, NULL );
267                         }
268
269                         if ( !is_entry_syncProviderSubentry( e ) &&
270                                  !is_entry_syncConsumerSubentry( e ) &&
271                                  update_ctxcsn != SLAP_TOOL_CTXCSN_KEEP ) {
272                                 attr = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
273                                 if ( maxcsn.bv_len != 0 ) {
274                                         value_match( &match, slap_schema.si_ad_entryCSN,
275                                                 slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
276                                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
277                                                 &maxcsn, &attr->a_nvals[0], &text );
278                                 } else {
279                                         match = -1;
280                                 }
281                                 if ( match < 0 ) {
282                                         if ( maxcsn.bv_val )
283                                                 ch_free( maxcsn.bv_val );
284                                         ber_dupbv( &maxcsn, &attr->a_nvals[0] );
285                                 }
286                         }
287                 }
288
289                 if ( update_ctxcsn == SLAP_TOOL_CTXCSN_KEEP ) {
290                         if ( is_entry_syncProviderSubentry( e )) { 
291                                 if ( !LDAP_SLIST_EMPTY( &consumer_subentry )) {
292                                         fprintf( stderr, "%s: consumer and provider subentries "
293                                                                          "are both present\n", progname );
294                                         rc = EXIT_FAILURE;
295                                         entry_free( e );
296                                         sei = LDAP_SLIST_FIRST( &consumer_subentry );
297                                         while ( sei ) {
298                                                 ch_free( sei->cn.bv_val );
299                                                 ch_free( sei->ndn.bv_val );
300                                                 ch_free( sei->rdn.bv_val );
301                                                 ch_free( sei->cookie.bv_val );
302                                                 LDAP_SLIST_REMOVE_HEAD( &consumer_subentry, sei_next );
303                                                 ch_free( sei );
304                                                 sei = LDAP_SLIST_FIRST( &consumer_subentry );
305                                         }
306                                         break;
307                                 }
308                                 if ( provider_subentry ) {
309                                         fprintf( stderr, "%s: multiple provider subentries are "
310                                                         "present : add -w flag to refresh\n", progname );
311                                         rc = EXIT_FAILURE;
312                                         entry_free( e );
313                                         break;
314                                 }
315                                 attr = attr_find( e->e_attrs, slap_schema.si_ad_contextCSN );
316                                 if ( attr == NULL ) {
317                                         entry_free( e );
318                                         continue;
319                                 }
320                                 provider_subentry = 1;
321                                 ber_dupbv( &maxcsn, &attr->a_nvals[0] );
322                         } else if ( is_entry_syncConsumerSubentry( e )) {
323                                 if ( provider_subentry ) {
324                                         fprintf( stderr, "%s: consumer and provider subentries "
325                                                                          "are both present\n", progname );
326                                         rc = EXIT_FAILURE;
327                                         entry_free( e );
328                                         break;
329                                 }
330
331                                 attr = attr_find( e->e_attrs, slap_schema.si_ad_cn );
332
333                                 if ( attr == NULL ) {
334                                         entry_free( e );
335                                         continue;
336                                 }
337
338                                 if ( !LDAP_SLIST_EMPTY( &consumer_subentry )) {
339                                         LDAP_SLIST_FOREACH( sei, &consumer_subentry, sei_next ) {
340                                                 value_match( &match, slap_schema.si_ad_cn,
341                                                         slap_schema.si_ad_cn->ad_type->sat_equality,
342                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
343                                                         &sei->cn, &attr->a_nvals[0], &text );
344                                         }
345                                         if ( !match ) {
346                                                 fprintf( stderr, "%s: multiple consumer subentries "
347                                                                 "have the same id : add -w flag to refresh\n",
348                                                                 progname );
349                                                 rc = EXIT_FAILURE;
350                                                 entry_free( e );
351                                                 sei = LDAP_SLIST_FIRST( &consumer_subentry );
352                                                 while ( sei ) {
353                                                         ch_free( sei->cn.bv_val );
354                                                         ch_free( sei->ndn.bv_val );
355                                                         ch_free( sei->rdn.bv_val );
356                                                         ch_free( sei->cookie.bv_val );
357                                                         LDAP_SLIST_REMOVE_HEAD( &consumer_subentry, sei_next );
358                                                         ch_free( sei );
359                                                         sei = LDAP_SLIST_FIRST( &consumer_subentry );
360                                                 }
361                                                 break;
362                                         }
363                                 }
364                                 sei = ch_calloc( 1, sizeof( struct subentryinfo ));
365                                 ber_dupbv( &sei->cn, &attr->a_nvals[0] );
366                                 ber_dupbv( &sei->ndn, &e->e_nname );
367                                 dnExtractRdn( &sei->ndn, &sei->rdn, NULL );
368                                 attr = attr_find( e->e_attrs, slap_schema.si_ad_syncreplCookie );
369                                 if ( attr == NULL ) {
370                                         ch_free( sei->cn.bv_val );
371                                         ch_free( sei->ndn.bv_val );
372                                         ch_free( sei->rdn.bv_val );
373                                         ch_free( sei->cookie.bv_val );
374                                         ch_free( sei );
375                                         entry_free( e );
376                                         continue;
377                                 }
378                                 ber_dupbv( &sei->cookie, &attr->a_nvals[0] );
379                                 LDAP_SLIST_INSERT_HEAD( &consumer_subentry, sei, sei_next );
380                         }
381                 }
382
383                 if ( !is_entry_syncProviderSubentry( e ) &&
384                          !is_entry_syncConsumerSubentry( e )) {
385                         if (!dryrun) {
386                                 ID id = be->be_entry_put( be, e, &bvtext );
387                                 if( id == NOID ) {
388                                         fprintf( stderr, "%s: could not add entry dn=\"%s\" "
389                                                                          "(line=%d): %s\n", progname, e->e_dn,
390                                                                          lineno, bvtext.bv_val );
391                                         rc = EXIT_FAILURE;
392                                         entry_free( e );
393                                         if( continuemode ) continue;
394                                         break;
395                                 }
396         
397                                 if ( verbose ) {
398                                         fprintf( stderr, "added: \"%s\" (%08lx)\n",
399                                                 e->e_dn, (long) id );
400                                 }
401                         } else {
402                                 if ( verbose ) {
403                                         fprintf( stderr, "(dry) added: \"%s\"\n", e->e_dn );
404                                 }
405                         }
406                 }
407
408                 entry_free( e );
409         }
410
411         bvtext.bv_len = textlen;
412         bvtext.bv_val = textbuf;
413         bvtext.bv_val[0] = '\0';
414
415         if ( !LDAP_SLIST_EMPTY( &consumer_subentry )) {
416                 maxcsn.bv_len = 0;
417                 maxcsn.bv_val = NULL;
418                 LDAP_SLIST_FOREACH( sei, &consumer_subentry, sei_next ) {
419                         if ( maxcsn.bv_len != 0 ) {
420                                 value_match( &match, slap_schema.si_ad_syncreplCookie,
421                                         slap_schema.si_ad_syncreplCookie->ad_type->sat_ordering,
422                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
423                                         &maxcsn, &sei->cookie, &text );
424                         } else {
425                                 match = -1;
426                         }
427                         if ( match < 0 ) {
428                                 if ( maxcsn.bv_val )
429                                         ch_free( maxcsn.bv_val );
430                                 ber_dupbv( &maxcsn, &sei->cookie );
431                         }
432                 }
433         }
434
435         if ( SLAP_LASTMOD(be) && replica_promotion ) {
436                 if ( provider_subentry || update_ctxcsn == SLAP_TOOL_CTXCSN_BATCH ||
437                          !LDAP_SLIST_EMPTY( &consumer_subentry )) {
438                         build_new_dn( &ctxcsn_ndn, &be->be_nsuffix[0],
439                                                   (struct berval *)&slap_ldapsync_cn_bv, NULL );
440                         ctxcsn_id = be->be_dn2id_get( be, &ctxcsn_ndn );
441                 
442                         if ( ctxcsn_id == NOID ) {
443                                 ctxcsn_e = slap_create_context_csn_entry( be, &maxcsn );
444                                 if ( !dryrun ) {
445                                         ctxcsn_id = be->be_entry_put( be, ctxcsn_e, &bvtext );
446                                         if( ctxcsn_id == NOID ) {
447                                                 fprintf( stderr, "%s: could not add ctxcsn subentry\n",
448                                                                                  progname);
449                                                 rc = EXIT_FAILURE;
450                                         }
451                                         if ( verbose ) {
452                                                 fprintf( stderr, "added: \"%s\" (%08lx)\n",
453                                                                                  ctxcsn_e->e_dn, (long) ctxcsn_id );
454                                         }
455                                 } else {
456                                         if ( verbose ) {
457                                                 fprintf( stderr, "(dry) added: \"%s\"\n", ctxcsn_e->e_dn );
458                                         }
459                                 }
460                                 entry_free( ctxcsn_e );
461                         } else {
462                                 ret = be->be_id2entry_get( be, ctxcsn_id, &ctxcsn_e );
463                                 if ( ret == LDAP_SUCCESS ) {
464                                         attr = attr_find( ctxcsn_e->e_attrs,
465                                                                                 slap_schema.si_ad_contextCSN );
466                                         AC_MEMCPY( attr->a_vals[0].bv_val, maxcsn.bv_val, maxcsn.bv_len );
467                                         attr->a_vals[0].bv_val[maxcsn.bv_len] = '\0';
468                                         attr->a_vals[0].bv_len = maxcsn.bv_len;
469                                         if ( !dryrun ) {
470                                                 ctxcsn_id = be->be_entry_modify( be, ctxcsn_e, &bvtext );
471                                                 if( ctxcsn_id == NOID ) {
472                                                         fprintf( stderr, "%s: could not modify ctxcsn "
473                                                                                          "subentry\n", progname);
474                                                         rc = EXIT_FAILURE;
475                                                 }
476                                                 if ( verbose ) {
477                                                         fprintf( stderr, "modified: \"%s\" (%08lx)\n",
478                                                                                          ctxcsn_e->e_dn, (long) ctxcsn_id );
479                                                 }
480                                         } else {
481                                                 if ( verbose ) {
482                                                         fprintf( stderr, "(dry) modified: \"%s\"\n",
483                                                                                          ctxcsn_e->e_dn );
484                                                 }
485                                         }
486                                 } else {
487                                         fprintf( stderr, "%s: could not modify ctxcsn subentry\n",
488                                                                          progname);
489                                         rc = EXIT_FAILURE;
490                                 }
491                         }
492                 } 
493         } else if ( SLAP_LASTMOD(be) && replica_demotion &&
494                                 ( update_ctxcsn == SLAP_TOOL_CTXCSN_BATCH ||
495                                 provider_subentry )) {
496
497                 ber_dupbv( &slap_syncrepl_bv, (struct berval *) &slap_syncrepl_bvc );
498                 ber_dupbv( &slap_syncrepl_cn_bv,
499                                         (struct berval *) &slap_syncrepl_cn_bvc );
500
501                 if ( replica_id_list == NULL ) {
502                         replica_id_list = ch_calloc( 2, sizeof( int ));
503                         replica_id_list[0] = 0;
504                         replica_id_list[1] = -1;
505                 }
506
507                 for ( i = 0; replica_id_list[i] > -1 ; i++ ) {
508                         slap_syncrepl_bv.bv_len = snprintf( slap_syncrepl_bv.bv_val,
509                                                                         slap_syncrepl_bvc.bv_len,
510                                                                         "syncrepl%d", replica_id_list[i] );
511                         slap_syncrepl_cn_bv.bv_len = snprintf( slap_syncrepl_cn_bv.bv_val,
512                                                                                 slap_syncrepl_cn_bvc.bv_len,
513                                                                                 "cn=syncrepl%d", replica_id_list[i] );
514                         build_new_dn( &ctxcsn_ndn, &be->be_nsuffix[0],
515                                                   (struct berval *)&slap_syncrepl_cn_bv, NULL );
516                         ctxcsn_id = be->be_dn2id_get( be, &ctxcsn_ndn );
517
518                         if ( ctxcsn_id == NOID ) {
519                                 ctxcsn_e = slap_create_syncrepl_entry( be, &maxcsn,
520                                                                                                 &slap_syncrepl_cn_bv,
521                                                                                                 &slap_syncrepl_bv );
522                                 if ( !dryrun ) {
523                                         ctxcsn_id = be->be_entry_put( be, ctxcsn_e, &bvtext );
524                                         if( ctxcsn_id == NOID ) {
525                                                 fprintf( stderr, "%s: could not add ctxcsn subentry\n",
526                                                                                  progname);
527                                                 rc = EXIT_FAILURE;
528                                         }
529                                         if ( verbose ) {
530                                                 fprintf( stderr, "added: \"%s\" (%08lx)\n",
531                                                                                  ctxcsn_e->e_dn, (long) ctxcsn_id );
532                                         }
533                                 } else {
534                                         if ( verbose ) {
535                                                 fprintf( stderr, "(dry) added: \"%s\"\n",
536                                                                                         ctxcsn_e->e_dn );
537                                         }
538                                 }
539                                 entry_free( ctxcsn_e );
540                         } else {
541                                 ret = be->be_id2entry_get( be, ctxcsn_id, &ctxcsn_e );
542                                 if ( ret == LDAP_SUCCESS ) {
543                                         attr = attr_find( ctxcsn_e->e_attrs,
544                                                                           slap_schema.si_ad_syncreplCookie );
545                                         AC_MEMCPY( attr->a_vals[0].bv_val, maxcsn.bv_val, maxcsn.bv_len );
546                                         attr->a_vals[0].bv_val[maxcsn.bv_len] = '\0';
547                                         attr->a_vals[0].bv_len = maxcsn.bv_len;
548                                         if ( !dryrun ) {
549                                                 ctxcsn_id = be->be_entry_modify( be,
550                                                                                         ctxcsn_e, &bvtext );
551                                                 if( ctxcsn_id == NOID ) {
552                                                         fprintf( stderr, "%s: could not modify ctxcsn "
553                                                                                          "subentry\n", progname);
554                                                         rc = EXIT_FAILURE;
555                                                 }
556                                                 if ( verbose ) {
557                                                         fprintf( stderr, "modified: \"%s\" (%08lx)\n",
558                                                                                          ctxcsn_e->e_dn, (long) ctxcsn_id );
559                                                 }
560                                         } else {
561                                                 if ( verbose ) {
562                                                         fprintf( stderr, "(dry) modified: \"%s\"\n",
563                                                                                          ctxcsn_e->e_dn );
564                                                 }
565                                         }
566                                 } else {
567                                         fprintf( stderr, "%s: could not modify ctxcsn subentry\n",
568                                                                          progname);
569                                         rc = EXIT_FAILURE;
570                                 }
571                         }
572                 }
573                 
574                 if ( slap_syncrepl_bv.bv_val ) {
575                         ch_free( slap_syncrepl_bv.bv_val );
576                 }
577                 if ( slap_syncrepl_cn_bv.bv_val ) {
578                         ch_free( slap_syncrepl_cn_bv.bv_val );
579                 }
580         } else if ( SLAP_LASTMOD(be) && replica_demotion &&
581                                 !LDAP_SLIST_EMPTY( &consumer_subentry )) {
582
583                 LDAP_SLIST_FOREACH( sei, &consumer_subentry, sei_next ) {
584                         ctxcsn_id = be->be_dn2id_get( be, &sei->ndn );
585
586                         if ( ctxcsn_id == NOID ) {
587                                 ctxcsn_e = slap_create_syncrepl_entry( be, &sei->cookie,
588                                                                                                 &sei->rdn, &sei->cn );
589                                 if ( !dryrun ) {
590                                         ctxcsn_id = be->be_entry_put( be, ctxcsn_e, &bvtext );
591                                         if( ctxcsn_id == NOID ) {
592                                                 fprintf( stderr, "%s: could not add ctxcsn subentry\n",
593                                                                                  progname);
594                                                 rc = EXIT_FAILURE;
595                                         }
596                                         if ( verbose ) {
597                                                 fprintf( stderr, "added: \"%s\" (%08lx)\n",
598                                                                                  ctxcsn_e->e_dn, (long) ctxcsn_id );
599                                         }
600                                 } else {
601                                         if ( verbose ) {
602                                                 fprintf( stderr, "(dry) added: \"%s\"\n",
603                                                                                         ctxcsn_e->e_dn );
604                                         }
605                                 }
606                                 entry_free( ctxcsn_e );
607                         } else {
608                                 ret = be->be_id2entry_get( be, ctxcsn_id, &ctxcsn_e );
609                                 if ( ret == LDAP_SUCCESS ) {
610                                         attr = attr_find( ctxcsn_e->e_attrs,
611                                                                           slap_schema.si_ad_syncreplCookie );
612                                         AC_MEMCPY( attr->a_vals[0].bv_val, maxcsn.bv_val, maxcsn.bv_len );
613                                         attr->a_vals[0].bv_val[maxcsn.bv_len] = '\0';
614                                         attr->a_vals[0].bv_len = maxcsn.bv_len;
615                                         if ( !dryrun ) {
616                                                 ctxcsn_id = be->be_entry_modify( be,
617                                                                                         ctxcsn_e, &bvtext );
618                                                 if( ctxcsn_id == NOID ) {
619                                                         fprintf( stderr, "%s: could not modify ctxcsn "
620                                                                                          "subentry\n", progname);
621                                                         rc = EXIT_FAILURE;
622                                                 }
623                                                 if ( verbose ) {
624                                                         fprintf( stderr, "modified: \"%s\" (%08lx)\n",
625                                                                                          ctxcsn_e->e_dn, (long) ctxcsn_id );
626                                                 }
627                                         } else {
628                                                 if ( verbose ) {
629                                                         fprintf( stderr, "(dry) modified: \"%s\"\n",
630                                                                                          ctxcsn_e->e_dn );
631                                                 }
632                                         }
633                                 } else {
634                                         fprintf( stderr, "%s: could not modify ctxcsn subentry\n",
635                                                                          progname);
636                                         rc = EXIT_FAILURE;
637                                 }
638                         }
639                 }
640                 
641                 if ( slap_syncrepl_bv.bv_val ) {
642                         ch_free( slap_syncrepl_bv.bv_val );
643                 }
644                 if ( slap_syncrepl_cn_bv.bv_val ) {
645                         ch_free( slap_syncrepl_cn_bv.bv_val );
646                 }
647         }
648
649         sei = LDAP_SLIST_FIRST( &consumer_subentry );
650         while ( sei ) {
651                 ch_free( sei->cn.bv_val );
652                 ch_free( sei->ndn.bv_val );
653                 ch_free( sei->rdn.bv_val );
654                 ch_free( sei->cookie.bv_val );
655                 LDAP_SLIST_REMOVE_HEAD( &consumer_subentry, sei_next );
656                 ch_free( sei );
657                 sei = LDAP_SLIST_FIRST( &consumer_subentry );
658         }
659
660         ch_free( buf );
661
662         if( be->be_entry_close( be )) rc = EXIT_FAILURE;
663
664         if( be->be_sync ) {
665                 be->be_sync( be );
666         }
667
668         slap_tool_destroy();
669         return rc;
670 }