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