]> git.sur5r.net Git - openldap/blob - servers/slapd/slapadd.c
Add register_certificate_map_function() native plugin API for registering
[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 = BER_BVNULL;
70         struct berval ldifcsn = BER_BVNULL;
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 = BER_BVNULL;
79         int ret;
80         struct berval bvtext;
81         int i;
82         struct berval mc;
83         struct sync_cookie sc;
84         slap_tool_init( progname, SLAPADD, argc, argv );
85
86         LDAP_SLIST_INIT( &consumer_subentry );
87
88         if( !be->be_entry_open ||
89                 !be->be_entry_close ||
90                 !be->be_entry_put )
91         {
92                 fprintf( stderr, "%s: database doesn't support necessary operations.\n",
93                         progname );
94                 if ( dryrun ) {
95                         fprintf( stderr, "\t(dry) continuing...\n" );
96
97                 } else {
98                         exit( EXIT_FAILURE );
99                 }
100         }
101
102         lmax = 0;
103         lineno = 0;
104
105         if( !dryrun && be->be_entry_open( be, 1 ) != 0 ) {
106                 fprintf( stderr, "%s: could not open database.\n",
107                         progname );
108                 exit( EXIT_FAILURE );
109         }
110
111         while( ldif_read_record( ldiffp, &lineno, &buf, &lmax ) ) {
112                 Entry *e = str2entry( buf );
113
114                 /*
115                  * Initialize text buffer
116                  */
117                 bvtext.bv_len = textlen;
118                 bvtext.bv_val = textbuf;
119                 bvtext.bv_val[0] = '\0';
120
121                 if( e == NULL ) {
122                         fprintf( stderr, "%s: could not parse entry (line=%d)\n",
123                                 progname, lineno );
124                         rc = EXIT_FAILURE;
125                         if( continuemode ) continue;
126                         break;
127                 }
128
129                 /* make sure the DN is not empty */
130                 if( !e->e_nname.bv_len ) {
131                         fprintf( stderr, "%s: empty dn=\"%s\" (line=%d)\n",
132                                 progname, e->e_dn, lineno );
133                         rc = EXIT_FAILURE;
134                         entry_free( e );
135                         if( continuemode ) continue;
136                         break;
137                 }
138
139                 /* check backend */
140                 if( select_backend( &e->e_nname, is_entry_referral(e), nosubordinates )
141                         != be )
142                 {
143                         fprintf( stderr, "%s: line %d: "
144                                 "database (%s) not configured to hold \"%s\"\n",
145                                 progname, lineno,
146                                 be ? be->be_suffix[0].bv_val : "<none>",
147                                 e->e_dn );
148                         fprintf( stderr, "%s: line %d: "
149                                 "database (%s) not configured to hold \"%s\"\n",
150                                 progname, lineno,
151                                 be ? be->be_nsuffix[0].bv_val : "<none>",
152                                 e->e_ndn );
153                         rc = EXIT_FAILURE;
154                         entry_free( e );
155                         if( continuemode ) continue;
156                         break;
157                 }
158
159                 if( global_schemacheck ) {
160                         Attribute *sc = attr_find( e->e_attrs,
161                                 slap_schema.si_ad_structuralObjectClass );
162                         Attribute *oc = attr_find( e->e_attrs,
163                                 slap_schema.si_ad_objectClass );
164
165                         if( oc == NULL ) {
166                                 fprintf( stderr, "%s: dn=\"%s\" (line=%d): %s\n",
167                                         progname, e->e_dn, lineno,
168                                         "no objectClass attribute");
169                                 rc = EXIT_FAILURE;
170                                 entry_free( e );
171                                 if( continuemode ) continue;
172                                 break;
173                         }
174
175                         if( sc == NULL ) {
176                                 struct berval vals[2];
177
178                                 rc = structural_class( oc->a_vals, vals,
179                                         NULL, &text, textbuf, textlen );
180
181                                 if( rc != LDAP_SUCCESS ) {
182                                         fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n",
183                                                 progname, e->e_dn, lineno, rc, text );
184                                         rc = EXIT_FAILURE;
185                                         entry_free( e );
186                                         if( continuemode ) continue;
187                                         break;
188                                 }
189
190                                 vals[1].bv_len = 0;
191                                 vals[1].bv_val = NULL;
192
193                                 attr_merge( e, slap_schema.si_ad_structuralObjectClass,
194                                         vals, NULL /* FIXME */ );
195                         }
196
197                         /* check schema */
198                         rc = entry_schema_check( be, e, NULL, &text, textbuf, textlen );
199
200                         if( rc != LDAP_SUCCESS ) {
201                                 fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n",
202                                         progname, e->e_dn, lineno, rc, text );
203                                 rc = EXIT_FAILURE;
204                                 entry_free( e );
205                                 if( continuemode ) continue;
206                                 break;
207                         }
208                 }
209
210                 if ( SLAP_LASTMOD(be) ) {
211                         struct tm *ltm;
212                         time_t now = slap_get_time();
213                         char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
214                         struct berval vals[ 2 ];
215
216                         struct berval name, timestamp;
217
218                         struct berval nvals[ 2 ];
219                         struct berval nname;
220                         char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
221
222                         vals[1].bv_len = 0;
223                         vals[1].bv_val = NULL;
224
225                         nvals[1].bv_len = 0;
226                         nvals[1].bv_val = NULL;
227
228                         ltm = gmtime(&now);
229                         lutil_gentime( timebuf, sizeof(timebuf), ltm );
230
231                         csn.bv_len = lutil_csnstr( csnbuf, sizeof( csnbuf ), 0, 0 );
232                         csn.bv_val = csnbuf;
233
234                         timestamp.bv_val = timebuf;
235                         timestamp.bv_len = strlen(timebuf);
236
237                         if ( BER_BVISEMPTY( &be->be_rootndn ) ) {
238                                 BER_BVSTR( &name, SLAPD_ANONYMOUS );
239                                 nname = name;
240                         } else {
241                                 name = be->be_rootdn;
242                                 nname = be->be_rootndn;
243                         }
244
245                         if( attr_find( e->e_attrs, slap_schema.si_ad_entryUUID )
246                                 == NULL )
247                         {
248                                 vals[0].bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
249                                 vals[0].bv_val = uuidbuf;
250                                 attr_merge_normalize_one( e,
251                                                         slap_schema.si_ad_entryUUID, vals, NULL );
252                         }
253
254                         if( attr_find( e->e_attrs, slap_schema.si_ad_creatorsName )
255                                 == NULL )
256                         {
257                                 vals[0] = name;
258                                 nvals[0] = nname;
259                                 attr_merge( e, slap_schema.si_ad_creatorsName, vals, nvals );
260                         }
261
262                         if( attr_find( e->e_attrs, slap_schema.si_ad_modifiersName )
263                                 == NULL )
264                         {
265                                 vals[0] = name;
266                                 nvals[0] = nname;
267                                 attr_merge( e, slap_schema.si_ad_modifiersName, vals, nvals );
268                         }
269
270                         if( attr_find( e->e_attrs, slap_schema.si_ad_createTimestamp )
271                                 == NULL )
272                         {
273                                 vals[0] = timestamp;
274                                 attr_merge( e, slap_schema.si_ad_createTimestamp, vals, NULL );
275                         }
276
277                         if( attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp )
278                                 == NULL )
279                         {
280                                 vals[0] = timestamp;
281                                 attr_merge( e, slap_schema.si_ad_modifyTimestamp, vals, NULL );
282                         }
283
284                         if( attr_find( e->e_attrs, slap_schema.si_ad_entryCSN )
285                                 == NULL )
286                         {
287                                 vals[0] = csn;
288                                 attr_merge( e, slap_schema.si_ad_entryCSN, vals, NULL );
289                         }
290
291                         if ( !is_entry_syncProviderSubentry( e ) &&
292                                  !is_entry_syncConsumerSubentry( e ) &&
293                                  update_ctxcsn != SLAP_TOOL_CTXCSN_KEEP ) {
294                                 attr = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
295                                 if ( maxcsn.bv_len != 0 ) {
296                                         value_match( &match, slap_schema.si_ad_entryCSN,
297                                                 slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
298                                                 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
299                                                 &maxcsn, &attr->a_nvals[0], &text );
300                                 } else {
301                                         match = -1;
302                                 }
303                                 if ( match < 0 ) {
304                                         if ( maxcsn.bv_val )
305                                                 ch_free( maxcsn.bv_val );
306                                         ber_dupbv( &maxcsn, &attr->a_nvals[0] );
307                                 }
308                         }
309                 }
310
311                 if ( dryrun ) {
312                         if ( verbose ) {
313                                 fprintf( stderr, "(dry) added: \"%s\"\n", e->e_dn );
314                         }
315                         goto done;
316                 }
317
318                 if ( update_ctxcsn == SLAP_TOOL_CTXCSN_KEEP &&
319                         ( replica_promotion || replica_demotion )) {
320                         if ( is_entry_syncProviderSubentry( e )) { 
321                                 if ( !LDAP_SLIST_EMPTY( &consumer_subentry )) {
322                                         fprintf( stderr, "%s: consumer and provider subentries "
323                                                                          "are both present\n", progname );
324                                         rc = EXIT_FAILURE;
325                                         entry_free( e );
326                                         sei = LDAP_SLIST_FIRST( &consumer_subentry );
327                                         while ( sei ) {
328                                                 ch_free( sei->cn.bv_val );
329                                                 ch_free( sei->ndn.bv_val );
330                                                 ch_free( sei->rdn.bv_val );
331                                                 ch_free( sei->cookie.bv_val );
332                                                 LDAP_SLIST_REMOVE_HEAD( &consumer_subentry, sei_next );
333                                                 ch_free( sei );
334                                                 sei = LDAP_SLIST_FIRST( &consumer_subentry );
335                                         }
336                                         break;
337                                 }
338                                 if ( provider_subentry ) {
339                                         fprintf( stderr, "%s: multiple provider subentries are "
340                                                         "present : add -w flag to refresh\n", progname );
341                                         rc = EXIT_FAILURE;
342                                         entry_free( e );
343                                         break;
344                                 }
345                                 attr = attr_find( e->e_attrs, slap_schema.si_ad_contextCSN );
346                                 if ( attr == NULL ) {
347                                         entry_free( e );
348                                         continue;
349                                 }
350                                 provider_subentry = 1;
351                                 ber_dupbv( &maxcsn, &attr->a_nvals[0] );
352                         } else if ( is_entry_syncConsumerSubentry( e )) {
353                                 if ( provider_subentry ) {
354                                         fprintf( stderr, "%s: consumer and provider subentries "
355                                                                          "are both present\n", progname );
356                                         rc = EXIT_FAILURE;
357                                         entry_free( e );
358                                         break;
359                                 }
360
361                                 attr = attr_find( e->e_attrs, slap_schema.si_ad_cn );
362
363                                 if ( attr == NULL ) {
364                                         entry_free( e );
365                                         continue;
366                                 }
367
368                                 if ( !LDAP_SLIST_EMPTY( &consumer_subentry )) {
369                                         LDAP_SLIST_FOREACH( sei, &consumer_subentry, sei_next ) {
370                                                 value_match( &match, slap_schema.si_ad_cn,
371                                                         slap_schema.si_ad_cn->ad_type->sat_equality,
372                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
373                                                         &sei->cn, &attr->a_nvals[0], &text );
374                                         }
375                                         if ( !match ) {
376                                                 fprintf( stderr, "%s: multiple consumer subentries "
377                                                                 "have the same id : add -w flag to refresh\n",
378                                                                 progname );
379                                                 rc = EXIT_FAILURE;
380                                                 entry_free( e );
381                                                 sei = LDAP_SLIST_FIRST( &consumer_subentry );
382                                                 while ( sei ) {
383                                                         ch_free( sei->cn.bv_val );
384                                                         ch_free( sei->ndn.bv_val );
385                                                         ch_free( sei->rdn.bv_val );
386                                                         ch_free( sei->cookie.bv_val );
387                                                         LDAP_SLIST_REMOVE_HEAD( &consumer_subentry, sei_next );
388                                                         ch_free( sei );
389                                                         sei = LDAP_SLIST_FIRST( &consumer_subentry );
390                                                 }
391                                                 break;
392                                         }
393                                 }
394                                 sei = ch_calloc( 1, sizeof( struct subentryinfo ));
395                                 ber_dupbv( &sei->cn, &attr->a_nvals[0] );
396                                 ber_dupbv( &sei->ndn, &e->e_nname );
397                                 dnExtractRdn( &sei->ndn, &sei->rdn, NULL );
398                                 attr = attr_find( e->e_attrs, slap_schema.si_ad_syncreplCookie );
399                                 if ( attr == NULL ) {
400                                         ch_free( sei->cn.bv_val );
401                                         ch_free( sei->ndn.bv_val );
402                                         ch_free( sei->rdn.bv_val );
403                                         ch_free( sei->cookie.bv_val );
404                                         ch_free( sei );
405                                         entry_free( e );
406                                         continue;
407                                 }
408                                 ber_dupbv( &sei->cookie, &attr->a_nvals[0] );
409                                 LDAP_SLIST_INSERT_HEAD( &consumer_subentry, sei, sei_next );
410                         }
411                 }
412
413                 if (( !is_entry_syncProviderSubentry( e ) &&
414                                  !is_entry_syncConsumerSubentry( e )) ||
415                                  ( !replica_promotion && !replica_demotion ))
416                 {
417                         /* dryrun moved earlier */
418                         assert( !dryrun );
419
420                         if (!dryrun) {
421                                 ID id = be->be_entry_put( be, e, &bvtext );
422                                 if( id == NOID ) {
423                                         fprintf( stderr, "%s: could not add entry dn=\"%s\" "
424                                                                          "(line=%d): %s\n", progname, e->e_dn,
425                                                                          lineno, bvtext.bv_val );
426                                         rc = EXIT_FAILURE;
427                                         entry_free( e );
428                                         if( continuemode ) continue;
429                                         break;
430                                 }
431         
432                                 if ( verbose ) {
433                                         fprintf( stderr, "added: \"%s\" (%08lx)\n",
434                                                 e->e_dn, (long) id );
435                                 }
436                         } else {
437                                 if ( verbose ) {
438                                         fprintf( stderr, "(dry) added: \"%s\"\n", e->e_dn );
439                                 }
440                         }
441                 }
442
443 done:;
444                 entry_free( e );
445         }
446
447         bvtext.bv_len = textlen;
448         bvtext.bv_val = textbuf;
449         bvtext.bv_val[0] = '\0';
450
451         if ( !LDAP_SLIST_EMPTY( &consumer_subentry )) {
452                 maxcsn.bv_len = 0;
453                 maxcsn.bv_val = NULL;
454                 LDAP_SLIST_FOREACH( sei, &consumer_subentry, sei_next ) {
455                         sc.octet_str = &sei->cookie;
456                         slap_parse_sync_cookie( &sc );
457                         if ( maxcsn.bv_len != 0 ) {
458                                 value_match( &match, slap_schema.si_ad_syncreplCookie,
459                                         slap_schema.si_ad_syncreplCookie->ad_type->sat_ordering,
460                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
461                                         &maxcsn, &sc.ctxcsn[0], &text );
462                         } else {
463                                 match = -1;
464                         }
465                         if ( match < 0 ) {
466                                 if ( maxcsn.bv_val )
467                                         ch_free( maxcsn.bv_val );
468                                 ber_dupbv( &maxcsn, &sc.ctxcsn[0] );
469                         }
470                         sc.octet_str = NULL;
471                         slap_sync_cookie_free( &sc, 0 );
472                 }
473         }
474
475         slap_compose_sync_cookie( NULL, &mc, &maxcsn, -1, -1 );
476
477         if ( SLAP_LASTMOD(be) && replica_promotion ) {
478                 if ( provider_subentry || update_ctxcsn == SLAP_TOOL_CTXCSN_BATCH ||
479                          !LDAP_SLIST_EMPTY( &consumer_subentry )) {
480                         build_new_dn( &ctxcsn_ndn, &be->be_nsuffix[0],
481                                                   (struct berval *)&slap_ldapsync_cn_bv, NULL );
482                         ctxcsn_id = be->be_dn2id_get( be, &ctxcsn_ndn );
483                 
484                         if ( ctxcsn_id == NOID ) {
485                                 ctxcsn_e = slap_create_context_csn_entry( be, &maxcsn );
486                                 
487                                 /* dryrun moved earlier */
488                                 assert( !dryrun );
489
490                                 if ( !dryrun ) {
491                                         ctxcsn_id = be->be_entry_put( be, ctxcsn_e, &bvtext );
492                                         if( ctxcsn_id == NOID ) {
493                                                 fprintf( stderr, "%s: could not add ctxcsn subentry\n",
494                                                                                  progname);
495                                                 rc = EXIT_FAILURE;
496                                         }
497                                         if ( verbose ) {
498                                                 fprintf( stderr, "added: \"%s\" (%08lx)\n",
499                                                                                  ctxcsn_e->e_dn, (long) ctxcsn_id );
500                                         }
501                                 } else {
502                                         if ( verbose ) {
503                                                 fprintf( stderr, "(dry) added: \"%s\"\n", ctxcsn_e->e_dn );
504                                         }
505                                 }
506                                 entry_free( ctxcsn_e );
507                         } else {
508                                 ret = be->be_id2entry_get( be, ctxcsn_id, &ctxcsn_e );
509                                 if ( ret == LDAP_SUCCESS ) {
510                                         attr = attr_find( ctxcsn_e->e_attrs,
511                                                                                 slap_schema.si_ad_contextCSN );
512                                         AC_MEMCPY( attr->a_vals[0].bv_val, maxcsn.bv_val, maxcsn.bv_len );
513                                         attr->a_vals[0].bv_val[maxcsn.bv_len] = '\0';
514                                         attr->a_vals[0].bv_len = maxcsn.bv_len;
515                                 
516                                         /* dryrun moved earlier */
517                                         assert( !dryrun );
518
519                                         if ( !dryrun ) {
520                                                 ctxcsn_id = be->be_entry_modify( be, ctxcsn_e, &bvtext );
521                                                 if( ctxcsn_id == NOID ) {
522                                                         fprintf( stderr, "%s: could not modify ctxcsn "
523                                                                                          "subentry\n", progname);
524                                                         rc = EXIT_FAILURE;
525                                                 }
526                                                 if ( verbose ) {
527                                                         fprintf( stderr, "modified: \"%s\" (%08lx)\n",
528                                                                                          ctxcsn_e->e_dn, (long) ctxcsn_id );
529                                                 }
530                                         } else {
531                                                 if ( verbose ) {
532                                                         fprintf( stderr, "(dry) modified: \"%s\"\n",
533                                                                                          ctxcsn_e->e_dn );
534                                                 }
535                                         }
536                                 } else {
537                                         fprintf( stderr, "%s: could not modify ctxcsn subentry\n",
538                                                                          progname);
539                                         rc = EXIT_FAILURE;
540                                 }
541                         }
542                 } 
543         } else if ( SLAP_LASTMOD(be) && replica_demotion &&
544                                 ( update_ctxcsn == SLAP_TOOL_CTXCSN_BATCH ||
545                                 provider_subentry )) {
546
547                 ber_dupbv( &slap_syncrepl_bv, (struct berval *) &slap_syncrepl_bvc );
548                 ber_dupbv( &slap_syncrepl_cn_bv,
549                                         (struct berval *) &slap_syncrepl_cn_bvc );
550
551                 if ( replica_id_list == NULL ) {
552                         replica_id_list = ch_calloc( 2, sizeof( int ));
553                         replica_id_list[0] = 0;
554                         replica_id_list[1] = -1;
555                 }
556
557                 for ( i = 0; replica_id_list[i] > -1 ; i++ ) {
558                         slap_syncrepl_bv.bv_len = snprintf( slap_syncrepl_bv.bv_val,
559                                                                         slap_syncrepl_bvc.bv_len+1,
560                                                                         "syncrepl%d", replica_id_list[i] );
561                         slap_syncrepl_cn_bv.bv_len = snprintf( slap_syncrepl_cn_bv.bv_val,
562                                                                                 slap_syncrepl_cn_bvc.bv_len+1,
563                                                                                 "cn=syncrepl%d", replica_id_list[i] );
564                         build_new_dn( &ctxcsn_ndn, &be->be_nsuffix[0],
565                                                   (struct berval *)&slap_syncrepl_cn_bv, NULL );
566                         ctxcsn_id = be->be_dn2id_get( be, &ctxcsn_ndn );
567
568                         if ( ctxcsn_id == NOID ) {
569                                 ctxcsn_e = slap_create_syncrepl_entry( be, &mc,
570                                                 &slap_syncrepl_cn_bv,
571                                                 &slap_syncrepl_bv );
572
573                                 /* dryrun moved earlier */
574                                 assert( !dryrun );
575
576                                 if ( !dryrun ) {
577                                         ctxcsn_id = be->be_entry_put( be, ctxcsn_e, &bvtext );
578                                         if( ctxcsn_id == NOID ) {
579                                                 fprintf( stderr, "%s: could not add ctxcsn subentry\n",
580                                                                                  progname);
581                                                 rc = EXIT_FAILURE;
582                                         }
583                                         if ( verbose ) {
584                                                 fprintf( stderr, "added: \"%s\" (%08lx)\n",
585                                                                                  ctxcsn_e->e_dn, (long) ctxcsn_id );
586                                         }
587                                 } else {
588                                         if ( verbose ) {
589                                                 fprintf( stderr, "(dry) added: \"%s\"\n",
590                                                                                         ctxcsn_e->e_dn );
591                                         }
592                                 }
593                                 entry_free( ctxcsn_e );
594                         } else {
595                                 ret = be->be_id2entry_get( be, ctxcsn_id, &ctxcsn_e );
596                                 if ( ret == LDAP_SUCCESS ) {
597                                         attr = attr_find( ctxcsn_e->e_attrs,
598                                                                           slap_schema.si_ad_syncreplCookie );
599                                         AC_MEMCPY( attr->a_vals[0].bv_val, mc.bv_val, mc.bv_len );
600                                         attr->a_vals[0].bv_val[maxcsn.bv_len] = '\0';
601                                         attr->a_vals[0].bv_len = maxcsn.bv_len;
602                                 
603                                         /* dryrun moved earlier */
604                                         assert( !dryrun );
605
606                                         if ( !dryrun ) {
607                                                 ctxcsn_id = be->be_entry_modify( be,
608                                                                                         ctxcsn_e, &bvtext );
609                                                 if( ctxcsn_id == NOID ) {
610                                                         fprintf( stderr, "%s: could not modify ctxcsn "
611                                                                                          "subentry\n", progname);
612                                                         rc = EXIT_FAILURE;
613                                                 }
614                                                 if ( verbose ) {
615                                                         fprintf( stderr, "modified: \"%s\" (%08lx)\n",
616                                                                                          ctxcsn_e->e_dn, (long) ctxcsn_id );
617                                                 }
618                                         } else {
619                                                 if ( verbose ) {
620                                                         fprintf( stderr, "(dry) modified: \"%s\"\n",
621                                                                                          ctxcsn_e->e_dn );
622                                                 }
623                                         }
624                                 } else {
625                                         fprintf( stderr, "%s: could not modify ctxcsn subentry\n",
626                                                                          progname);
627                                         rc = EXIT_FAILURE;
628                                 }
629                         }
630                 }
631                 
632                 if ( slap_syncrepl_bv.bv_val ) {
633                         ch_free( slap_syncrepl_bv.bv_val );
634                 }
635                 if ( slap_syncrepl_cn_bv.bv_val ) {
636                         ch_free( slap_syncrepl_cn_bv.bv_val );
637                 }
638         } else if ( SLAP_LASTMOD(be) && replica_demotion &&
639                                 !LDAP_SLIST_EMPTY( &consumer_subentry )) {
640
641                 LDAP_SLIST_FOREACH( sei, &consumer_subentry, sei_next ) {
642                         ctxcsn_id = be->be_dn2id_get( be, &sei->ndn );
643
644                         if ( ctxcsn_id == NOID ) {
645                                 ctxcsn_e = slap_create_syncrepl_entry( be, &sei->cookie,
646                                                 &sei->rdn, &sei->cn );
647
648                                 /* dryrun moved earlier */
649                                 assert( !dryrun );
650
651                                 if ( !dryrun ) {
652                                         ctxcsn_id = be->be_entry_put( be, ctxcsn_e, &bvtext );
653                                         if( ctxcsn_id == NOID ) {
654                                                 fprintf( stderr, "%s: could not add ctxcsn subentry\n",
655                                                                                  progname);
656                                                 rc = EXIT_FAILURE;
657                                         }
658                                         if ( verbose ) {
659                                                 fprintf( stderr, "added: \"%s\" (%08lx)\n",
660                                                                                  ctxcsn_e->e_dn, (long) ctxcsn_id );
661                                         }
662                                 } else {
663                                         if ( verbose ) {
664                                                 fprintf( stderr, "(dry) added: \"%s\"\n",
665                                                                                         ctxcsn_e->e_dn );
666                                         }
667                                 }
668                                 entry_free( ctxcsn_e );
669                         } else {
670                                 ret = be->be_id2entry_get( be, ctxcsn_id, &ctxcsn_e );
671                                 if ( ret == LDAP_SUCCESS ) {
672                                         attr = attr_find( ctxcsn_e->e_attrs,
673                                                                           slap_schema.si_ad_syncreplCookie );
674                                         AC_MEMCPY( attr->a_vals[0].bv_val, sei->cookie.bv_val, sei->cookie.bv_len );
675                                         attr->a_vals[0].bv_val[sei->cookie.bv_len] = '\0';
676                                         attr->a_vals[0].bv_len = sei->cookie.bv_len;
677                                         
678                                         /* dryrun moved earlier */
679                                         assert( !dryrun );
680
681                                         if ( !dryrun ) {
682                                                 ctxcsn_id = be->be_entry_modify( be,
683                                                                                         ctxcsn_e, &bvtext );
684                                                 if( ctxcsn_id == NOID ) {
685                                                         fprintf( stderr, "%s: could not modify ctxcsn "
686                                                                                          "subentry\n", progname);
687                                                         rc = EXIT_FAILURE;
688                                                 }
689                                                 if ( verbose ) {
690                                                         fprintf( stderr, "modified: \"%s\" (%08lx)\n",
691                                                                                          ctxcsn_e->e_dn, (long) ctxcsn_id );
692                                                 }
693                                         } else {
694                                                 if ( verbose ) {
695                                                         fprintf( stderr, "(dry) modified: \"%s\"\n",
696                                                                                          ctxcsn_e->e_dn );
697                                                 }
698                                         }
699                                 } else {
700                                         fprintf( stderr, "%s: could not modify ctxcsn subentry\n",
701                                                                          progname);
702                                         rc = EXIT_FAILURE;
703                                 }
704                         }
705                 }
706                 
707                 if ( slap_syncrepl_bv.bv_val ) {
708                         ch_free( slap_syncrepl_bv.bv_val );
709                 }
710                 if ( slap_syncrepl_cn_bv.bv_val ) {
711                         ch_free( slap_syncrepl_cn_bv.bv_val );
712                 }
713         }
714
715         sei = LDAP_SLIST_FIRST( &consumer_subentry );
716         while ( sei ) {
717                 ch_free( sei->cn.bv_val );
718                 ch_free( sei->ndn.bv_val );
719                 ch_free( sei->rdn.bv_val );
720                 ch_free( sei->cookie.bv_val );
721                 LDAP_SLIST_REMOVE_HEAD( &consumer_subentry, sei_next );
722                 ch_free( sei );
723                 sei = LDAP_SLIST_FIRST( &consumer_subentry );
724         }
725
726         ch_free( buf );
727
728         if ( !dryrun ) {
729                 if( be->be_entry_close( be ) ) {
730                         rc = EXIT_FAILURE;
731                 }
732
733                 if( be->be_sync ) {
734                         be->be_sync( be );
735                 }
736         }
737
738         slap_tool_destroy();
739
740         return rc;
741 }
742