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