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