]> git.sur5r.net Git - openldap/commitdiff
add slapmodify (ITS#6165; may need cleanup)
authorPierangelo Masarati <ando@openldap.org>
Tue, 20 Apr 2010 06:00:16 +0000 (06:00 +0000)
committerPierangelo Masarati <ando@openldap.org>
Tue, 20 Apr 2010 06:00:16 +0000 (06:00 +0000)
servers/slapd/Makefile.in
servers/slapd/main.c
servers/slapd/slapcommon.c
servers/slapd/slapcommon.h
servers/slapd/slapmodify.c [new file with mode: 0644]

index c170d7945ede5fe6b8a315f7d1ce7ef31d478695..d234ef56cecaed92a68eef6f284ee0478c45179b 100644 (file)
@@ -13,7 +13,7 @@
 ## top-level directory of the distribution or, alternatively, at
 ## <http://www.OpenLDAP.org/license.html>.
 
-SLAPTOOLS=slapadd slapcat slapdn slapindex slappasswd slaptest slapauth slapacl slapschema
+SLAPTOOLS=slapadd slapcat slapdn slapindex slapmodify slappasswd slaptest slapauth slapacl slapschema
 PROGRAMS=slapd $(SLAPTOOLS)
 XPROGRAMS=sslapd libbackends.a .backend liboverlays.a
 XSRCS=version.c
@@ -38,7 +38,7 @@ SRCS  = main.c globals.c bconfig.c config.c daemon.c \
                backglue.c backover.c ctxcsn.c ldapsync.c frontend.c \
                slapadd.c slapcat.c slapcommon.c slapdn.c slapindex.c \
                slappasswd.c slaptest.c slapauth.c slapacl.c component.c \
-               aci.c alock.c txn.c slapschema.c \
+               aci.c alock.c txn.c slapschema.c slapmodify.c \
                $(@PLAT@_SRCS)
 
 OBJS   = main.o globals.o bconfig.o config.o daemon.o \
@@ -56,7 +56,7 @@ OBJS  = main.o globals.o bconfig.o config.o daemon.o \
                backglue.o backover.o ctxcsn.o ldapsync.o frontend.o \
                slapadd.o slapcat.o slapcommon.o slapdn.o slapindex.o \
                slappasswd.o slaptest.o slapauth.o slapacl.o component.o \
-               aci.o alock.o txn.o slapschema.o \
+               aci.o alock.o txn.o slapschema.o slapmodify.o \
                $(@PLAT@_OBJS)
 
 LDAP_INCDIR= ../../include -I$(srcdir) -I$(srcdir)/slapi -I.
index 6990e916744dbd3942de2fb01fd9f92d4b047411..a172b5009cbf71c2d0e899977a7e2dca07166f26 100644 (file)
@@ -65,7 +65,7 @@ static struct sockaddr_in     bind_addr;
 
 typedef int (MainFunc) LDAP_P(( int argc, char *argv[] ));
 extern MainFunc slapadd, slapcat, slapdn, slapindex, slappasswd,
-       slaptest, slapauth, slapacl, slapschema;
+       slaptest, slapauth, slapacl, slapschema, slapmodify;
 
 static struct {
        char *name;
@@ -75,6 +75,7 @@ static struct {
        {"slapcat", slapcat},
        {"slapdn", slapdn},
        {"slapindex", slapindex},
+       {"slapmodify", slapmodify},
        {"slappasswd", slappasswd},
        {"slapschema", slapschema},
        {"slaptest", slaptest},
@@ -307,7 +308,7 @@ usage( char *name )
        fprintf( stderr,
                "\t-4\t\tIPv4 only\n"
                "\t-6\t\tIPv6 only\n"
-               "\t-T {acl|add|auth|cat|dn|index|passwd|test}\n"
+               "\t-T {acl|add|auth|cat|dn|index|modify|passwd|test}\n"
                "\t\t\tRun in Tool mode\n"
                "\t-c cookie\tSync cookie of consumer\n"
                "\t-d level\tDebug level" "\n"
index f4e2eff51ce28df37aca66df7eabc84d63771f38..1c3c489dd6674f527d544f8f1f0f8f1440ed2bf0 100644 (file)
@@ -264,6 +264,10 @@ slap_tool_init(
                mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
                break;
 
+       case SLAPMODIFY:
+               options = "b:cd:f:F:gj:l:n:o:qsS:uvw";
+               break;
+
        case SLAPSCHEMA:
                options = "a:b:cd:f:F:gH:l:n:o:s:v";
                mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
@@ -527,6 +531,7 @@ slap_tool_init(
        switch ( tool ) {
        case SLAPADD:
        case SLAPCAT:
+       case SLAPMODIFY:
        case SLAPSCHEMA:
                if ( ( argc != optind ) || (dbnum >= 0 && base.bv_val != NULL ) ) {
                        usage( tool, progname );
@@ -626,6 +631,7 @@ slap_tool_init(
        case SLAPADD:
        case SLAPCAT:
        case SLAPINDEX:
+       case SLAPMODIFY:
        case SLAPSCHEMA:
                if ( !nbackends ) {
                        fprintf( stderr, "No databases found "
index dae63cd012c0cac2c078bcb19b9f2034366a49df..5041f374d76f4780f1295129724b808f17ebfc25 100644 (file)
@@ -25,6 +25,7 @@ enum slaptool {
        SLAPCAT,        /* database -> LDIF tool */
        SLAPDN,         /* DN check w/ syntax tool */
        SLAPINDEX,      /* database index tool */
+       SLAPMODIFY,     /* database modify tool */
        SLAPPASSWD,     /* password generation tool */
        SLAPSCHEMA,     /* schema checking tool */
        SLAPTEST,       /* slapd.conf test tool */
diff --git a/servers/slapd/slapmodify.c b/servers/slapd/slapmodify.c
new file mode 100644 (file)
index 0000000..f1ef863
--- /dev/null
@@ -0,0 +1,728 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2010 The OpenLDAP Foundation.
+ * Portions Copyright 1998-2003 Kurt D. Zeilenga.
+ * Portions Copyright 2003 IBM Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include "ac/stdlib.h"
+
+#include "ac/ctype.h"
+#include "ac/string.h"
+#include "ac/socket.h"
+#include "ac/unistd.h"
+
+#include "lber.h"
+#include "ldif.h"
+#include "lutil.h"
+#include "lutil_meter.h"
+#include <sys/stat.h>
+
+#include "slapcommon.h"
+
+static char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ];
+static char maxcsnbuf[ LDAP_PVT_CSNSTR_BUFSIZE * ( SLAP_SYNC_SID_MAX + 1 ) ];
+
+int
+slapmodify( int argc, char **argv )
+{
+       char *buf = NULL;
+       const char *text;
+       char textbuf[SLAP_TEXT_BUFLEN] = { '\0' };
+       size_t textlen = sizeof textbuf;
+       const char *progname = "slapmodify";
+
+       struct berval csn;
+       struct berval maxcsn[ SLAP_SYNC_SID_MAX + 1 ];
+       unsigned long sid;
+       struct berval bvtext;
+       Entry *ctxcsn_e;
+       ID      ctxcsn_id, id;
+       OperationBuffer opbuf;
+       Operation *op;
+
+       int match;
+       int checkvals;
+       int lineno, nextline, ldifrc;
+       int lmax;
+       int rc = EXIT_SUCCESS;
+       int manage = 0; 
+
+       int enable_meter = 0;
+       lutil_meter_t meter;
+       struct stat stat_buf;
+
+       /* default "000" */
+       csnsid = 0;
+
+       if ( isatty (2) ) enable_meter = 1;
+       slap_tool_init( progname, SLAPMODIFY, argc, argv );
+
+       memset( &opbuf, 0, sizeof(opbuf) );
+       op = &opbuf.ob_op;
+       op->o_hdr = &opbuf.ob_hdr;
+
+       if ( !be->be_entry_open ||
+               !be->be_entry_close ||
+               !be->be_entry_put ||
+               !be->be_dn2id_get ||
+               !be->be_entry_get ||
+               !be->be_entry_modify )
+       {
+               fprintf( stderr, "%s: database doesn't support necessary operations.\n",
+                       progname );
+               if ( dryrun ) {
+                       fprintf( stderr, "\t(dry) continuing...\n" );
+
+               } else {
+                       exit( EXIT_FAILURE );
+               }
+       }
+
+       checkvals = (slapMode & SLAP_TOOL_QUICK) ? 0 : 1;
+
+       lmax = 0;
+       nextline = 0;
+
+       /* enforce schema checking unless not disabled */
+       if ( (slapMode & SLAP_TOOL_NO_SCHEMA_CHECK) == 0) {
+               SLAP_DBFLAGS(be) &= ~(SLAP_DBFLAG_NO_SCHEMA_CHECK);
+       }
+
+       if( !dryrun && be->be_entry_open( be, 1 ) != 0 ) {
+               fprintf( stderr, "%s: could not open database.\n",
+                       progname );
+               exit( EXIT_FAILURE );
+       }
+
+       if ( enable_meter 
+#ifdef LDAP_DEBUG
+               /* tools default to "none" */
+               && slap_debug == LDAP_DEBUG_NONE
+#endif
+               && !fstat ( fileno ( ldiffp->fp ), &stat_buf )
+               && S_ISREG(stat_buf.st_mode) ) {
+               enable_meter = !lutil_meter_open(
+                       &meter,
+                       &lutil_meter_text_display,
+                       &lutil_meter_linear_estimator,
+                       stat_buf.st_size);
+       } else {
+               enable_meter = 0;
+       }
+
+       /* nextline is the line number of the end of the current entry */
+       for( lineno=1; ( ldifrc = ldif_read_record( ldiffp, &nextline, &buf, &lmax )) > 0;
+               lineno=nextline+1 )
+       {
+               BackendDB *bd;
+               Entry *e;
+               struct berval rbuf;
+               LDIFRecord lr;
+               struct berval ndn;
+               int n;
+               int is_oc = 0;
+               int local_rc;
+               int mod_err = 0;
+               char *request = "(unknown)";
+
+               ber_str2bv( buf, 0, 0, &rbuf );
+
+               if ( lineno < jumpline )
+                       continue;
+
+               if ( enable_meter )
+                       lutil_meter_update( &meter,
+                                        ftell( ldiffp->fp ),
+                                        0);
+
+               /*
+                * Initialize text buffer
+                */
+               bvtext.bv_len = textlen;
+               bvtext.bv_val = textbuf;
+               bvtext.bv_val[0] = '\0';
+
+               local_rc = ldap_parse_ldif_record( &rbuf, lineno, &lr,
+                       "slapmodify", LDIF_NO_CONTROLS );
+
+               if ( local_rc != LDAP_SUCCESS ) {
+                       fprintf( stderr, "%s: could not parse entry (line=%d)\n",
+                               progname, lineno );
+                       rc = EXIT_FAILURE;
+                       if( continuemode ) continue;
+                       break;
+               }
+
+               switch ( lr.lr_op ) {
+               case LDAP_REQ_ADD:
+                       request = "add";
+                       break;
+
+               case LDAP_REQ_MODIFY:
+                       request = "modify";
+                       break;
+
+               case LDAP_REQ_MODRDN:
+               case LDAP_REQ_DELETE:
+                       fprintf( stderr, "%s: request 0x%lx not supported (line=%d)\n",
+                               progname, (unsigned long)lr.lr_op, lineno );
+                       rc = EXIT_FAILURE;
+                       if( continuemode ) continue;
+                       goto done;
+
+               default:
+                       fprintf( stderr, "%s: unknown request 0x%lx (line=%d)\n",
+                               progname, (unsigned long)lr.lr_op, lineno );
+                       rc = EXIT_FAILURE;
+                       if( continuemode ) continue;
+                       goto done;
+               }
+
+               local_rc = dnNormalize( 0, NULL, NULL, &lr.lr_dn, &ndn, NULL );
+               if ( local_rc != LDAP_SUCCESS ) {
+                       fprintf( stderr, "%s: DN=\"%s\" normalization failed (line=%d)\n",
+                               progname, lr.lr_dn.bv_val, lineno );
+                       rc = EXIT_FAILURE;
+                       if( continuemode ) continue;
+                       break;
+               }
+
+               /* make sure the DN is not empty */
+               if( BER_BVISEMPTY( &ndn ) &&
+                       !BER_BVISEMPTY( be->be_nsuffix ))
+               {
+                       fprintf( stderr, "%s: line %d: "
+                               "%s entry with empty dn=\"\"",
+                               progname, lineno, request );
+                       bd = select_backend( &ndn, nosubordinates );
+                       if ( bd ) {
+                               BackendDB *bdtmp;
+                               int dbidx = 0;
+                               LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) {
+                                       if ( bdtmp == bd ) break;
+                                       dbidx++;
+                               }
+
+                               assert( bdtmp != NULL );
+                               
+                               fprintf( stderr, "; did you mean to use database #%d (%s)?",
+                                       dbidx,
+                                       bd->be_suffix[0].bv_val );
+
+                       }
+                       fprintf( stderr, "\n" );
+                       rc = EXIT_FAILURE;
+                       SLAP_FREE( ndn.bv_val );
+                       ldap_ldif_record_done( &lr );
+                       if( continuemode ) continue;
+                       break;
+               }
+
+               /* check backend */
+               bd = select_backend( &ndn, nosubordinates );
+               if ( bd != be ) {
+                       fprintf( stderr, "%s: line %d: "
+                               "database #%d (%s) not configured to hold \"%s\"",
+                               progname, lineno,
+                               dbnum,
+                               be->be_suffix[0].bv_val,
+                               lr.lr_dn.bv_val );
+                       if ( bd ) {
+                               BackendDB *bdtmp;
+                               int dbidx = 0;
+                               LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) {
+                                       if ( bdtmp == bd ) break;
+                                       dbidx++;
+                               }
+
+                               assert( bdtmp != NULL );
+                               
+                               fprintf( stderr, "; did you mean to use database #%d (%s)?",
+                                       dbidx,
+                                       bd->be_suffix[0].bv_val );
+
+                       } else {
+                               fprintf( stderr, "; no database configured for that naming context" );
+                       }
+                       fprintf( stderr, "\n" );
+                       rc = EXIT_FAILURE;
+                       SLAP_FREE( ndn.bv_val );
+                       ldap_ldif_record_done( &lr );
+                       if( continuemode ) continue;
+                       break;
+               }
+
+               /* get entry */
+               id = be->be_dn2id_get( be, &ndn );
+               e = be->be_entry_get( be, id );
+               if ( e != NULL ) {
+                       Entry *e_tmp = entry_dup( e );
+                       /* FIXME: release? */
+                       e = e_tmp;
+               }
+
+               for ( n = 0; lr.lrop_mods[ n ] != NULL; n++ ) {
+                       LDAPMod *mod = lr.lrop_mods[ n ];
+                       Modification mods = { 0 };
+                       unsigned i = 0;
+                       int bin = (mod->mod_op & LDAP_MOD_BVALUES);
+                       int pretty = 0;
+                       int normalize = 0;
+
+                       local_rc = slap_str2ad( mod->mod_type, &mods.sm_desc, &text );
+                       if ( local_rc != LDAP_SUCCESS ) {
+                               fprintf( stderr, "%s: slap_str2ad(\"%s\") failed for entry \"%s\" (%d: %s, lineno=%d)\n",
+                                       progname, mod->mod_type, lr.lr_dn.bv_val, local_rc, text, lineno );
+                               rc = EXIT_FAILURE;
+                               mod_err = 1;
+                               if( continuemode ) continue;
+                               SLAP_FREE( ndn.bv_val );
+                               ldap_ldif_record_done( &lr );
+                               entry_free( e );
+                               goto done;
+                       }
+
+                       mods.sm_type = mods.sm_desc->ad_cname;
+
+                       if ( mods.sm_desc->ad_type->sat_syntax->ssyn_pretty ) {
+                               pretty = 1;
+
+                       } else {
+                               assert( mods.sm_desc->ad_type->sat_syntax->ssyn_validate != NULL );
+                       }
+
+                       if ( mods.sm_desc->ad_type->sat_equality &&
+                               mods.sm_desc->ad_type->sat_equality->smr_normalize )
+                       {
+                               normalize = 1;
+                       }
+
+                       if ( bin && mod->mod_bvalues ) {
+                               for ( i = 0; mod->mod_bvalues[ i ] != NULL; i++ )
+                                       ;
+
+                       } else if ( !bin && mod->mod_values ) {
+                               for ( i = 0; mod->mod_values[ i ] != NULL; i++ )
+                                       ;
+                       }
+
+                       mods.sm_values = SLAP_CALLOC( sizeof( struct berval ), i + 1 );
+                       if ( normalize ) {
+                               mods.sm_nvalues = SLAP_CALLOC( sizeof( struct berval ), i + 1 );
+                       } else {
+                               mods.sm_nvalues = NULL;
+                       }
+                       mods.sm_numvals = i;
+
+                       for ( i = 0; i < mods.sm_numvals; i++ ) {
+                               struct berval bv;
+
+                               if ( bin ) {
+                                       bv = *mod->mod_bvalues[ i ];
+                               } else {
+                                       ber_str2bv( mod->mod_values[ i ], 0, 0, &bv );
+                               }
+
+                               if ( pretty ) {
+                                       local_rc = ordered_value_pretty( mods.sm_desc,
+                                       &bv, &mods.sm_values[i], NULL );
+
+                               } else {
+                                       local_rc = ordered_value_validate( mods.sm_desc,
+                                               &bv, 0 );
+                               }
+
+                               if ( local_rc != LDAP_SUCCESS ) {
+                                       fprintf( stderr, "%s: DN=\"%s\": unable to %s attr=%s value #%d\n",
+                                               progname, e->e_dn, pretty ? "prettify" : "validate",
+                                               mods.sm_desc->ad_cname.bv_val, i );
+                                       /* handle error */
+                                       mod_err = 1;
+                                       rc = EXIT_FAILURE;
+                                       ber_bvarray_free( mods.sm_values );
+                                       ber_bvarray_free( mods.sm_nvalues );
+                                       if( continuemode ) continue;
+                                       SLAP_FREE( ndn.bv_val );
+                                       ldap_ldif_record_done( &lr );
+                                       entry_free( e );
+                                       goto done;
+                               }
+
+                               if ( !pretty ) {
+                                       ber_dupbv( &mods.sm_values[i], &bv );
+                               }
+
+                               if ( normalize ) {
+                                       local_rc = ordered_value_normalize(
+                                               SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
+                                               mods.sm_desc,
+                                               mods.sm_desc->ad_type->sat_equality,
+                                               &mods.sm_values[i], &mods.sm_nvalues[i],
+                                               NULL );
+                                       if ( local_rc != LDAP_SUCCESS ) {
+                                               fprintf( stderr, "%s: DN=\"%s\": unable to normalize attr=%s value #%d\n",
+                                                       progname, e->e_dn, mods.sm_desc->ad_cname.bv_val, i );
+                                               /* handle error */
+                                               mod_err = 1;
+                                               rc = EXIT_FAILURE;
+                                               ber_bvarray_free( mods.sm_values );
+                                               ber_bvarray_free( mods.sm_nvalues );
+                                               if( continuemode ) continue;
+                                               SLAP_FREE( ndn.bv_val );
+                                               ldap_ldif_record_done( &lr );
+                                               entry_free( e );
+                                               goto done;
+                                       }
+                               }
+                       }
+
+                       mods.sm_op = (mod->mod_op & ~LDAP_MOD_BVALUES);
+                       mods.sm_flags = 0;
+
+                       if ( mods.sm_desc == slap_schema.si_ad_objectClass ) {
+                               is_oc = 1;
+                       }
+
+                       switch ( mods.sm_op ) {
+                       case LDAP_MOD_ADD:
+                               local_rc = modify_add_values( e, &mods,
+                                       0, &text, textbuf, textlen );
+                               break;
+
+                       case LDAP_MOD_DELETE:
+                               local_rc = modify_delete_values( e, &mods,
+                                       0, &text, textbuf, textlen );
+                               break;
+
+                       case LDAP_MOD_REPLACE:
+                               local_rc = modify_replace_values( e, &mods,
+                                       0, &text, textbuf, textlen );
+                               break;
+
+                       case LDAP_MOD_INCREMENT:
+                               local_rc = modify_increment_values( e, &mods,
+                                       0, &text, textbuf, textlen );
+                               break;
+                       }
+
+                       if ( local_rc != LDAP_SUCCESS ) {
+                               fprintf( stderr, "%s: DN=\"%s\": unable to modify attr=%s\n",
+                                       progname, e->e_dn, mods.sm_desc->ad_cname.bv_val );
+                               rc = EXIT_FAILURE;
+                               ber_bvarray_free( mods.sm_values );
+                               ber_bvarray_free( mods.sm_nvalues );
+                               if( continuemode ) continue;
+                               SLAP_FREE( ndn.bv_val );
+                               ldap_ldif_record_done( &lr );
+                               entry_free( e );
+                               goto done;
+                       }
+               }
+
+               if ( SLAP_LASTMOD(be) ) {
+                       time_t now = slap_get_time();
+                       char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
+                       struct berval vals[ 2 ];
+
+                       struct berval name, timestamp;
+
+                       struct berval nvals[ 2 ];
+                       struct berval nname;
+                       char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
+
+                       Attribute *a;
+
+                       vals[1].bv_len = 0;
+                       vals[1].bv_val = NULL;
+
+                       nvals[1].bv_len = 0;
+                       nvals[1].bv_val = NULL;
+
+                       csn.bv_len = ldap_pvt_csnstr( csnbuf, sizeof( csnbuf ), csnsid, 0 );
+                       csn.bv_val = csnbuf;
+
+                       timestamp.bv_val = timebuf;
+                       timestamp.bv_len = sizeof(timebuf);
+
+                       slap_timestamp( &now, &timestamp );
+
+                       if ( BER_BVISEMPTY( &be->be_rootndn ) ) {
+                               BER_BVSTR( &name, SLAPD_ANONYMOUS );
+                               nname = name;
+                       } else {
+                               name = be->be_rootdn;
+                               nname = be->be_rootndn;
+                       }
+
+                       a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID );
+                       if ( a != NULL ) {
+                               vals[0].bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
+                               vals[0].bv_val = uuidbuf;
+                               if ( a->a_vals != a->a_nvals ) {
+                                       SLAP_FREE( a->a_nvals[0].bv_val );
+                                       SLAP_FREE( a->a_nvals );
+                               }
+                               SLAP_FREE( a->a_vals[0].bv_val );
+                               SLAP_FREE( a->a_vals );
+                               a->a_vals = NULL;
+                               a->a_nvals = NULL;
+                               a->a_numvals = 0;
+                       }
+                       attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID, vals, NULL );
+
+                       a = attr_find( e->e_attrs, slap_schema.si_ad_creatorsName );
+                       if ( a == NULL ) {
+                               vals[0] = name;
+                               nvals[0] = nname;
+                               attr_merge( e, slap_schema.si_ad_creatorsName, vals, nvals );
+
+                       } else {
+                               ber_bvreplace( &a->a_vals[0], &name );
+                               ber_bvreplace( &a->a_nvals[0], &nname );
+                       }
+
+                       a = attr_find( e->e_attrs, slap_schema.si_ad_createTimestamp );
+                       if ( a == NULL ) {
+                               vals[0] = timestamp;
+                               attr_merge( e, slap_schema.si_ad_createTimestamp, vals, NULL );
+
+                       } else {
+                               ber_bvreplace( &a->a_vals[0], &timestamp );
+                       }
+
+                       a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
+                       if ( a == NULL ) {
+                               vals[0] = csn;
+                               attr_merge( e, slap_schema.si_ad_entryCSN, vals, NULL );
+
+                       } else {
+                               ber_bvreplace( &a->a_vals[0], &csn );
+                       }
+
+                       a = attr_find( e->e_attrs, slap_schema.si_ad_modifiersName );
+                       if ( a == NULL ) {
+                               vals[0] = name;
+                               nvals[0] = nname;
+                               attr_merge( e, slap_schema.si_ad_modifiersName, vals, nvals );
+
+                       } else {
+                               ber_bvreplace( &a->a_vals[0], &name );
+                               ber_bvreplace( &a->a_nvals[0], &nname );
+                       }
+
+                       a = attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp );
+                       if ( a == NULL ) {
+                               vals[0] = timestamp;
+                               attr_merge( e, slap_schema.si_ad_modifyTimestamp, vals, NULL );
+
+                       } else {
+                               ber_bvreplace( &a->a_vals[0], &timestamp );
+                       }
+               }
+
+               if ( mod_err ) break;
+
+               /* check schema, objectClass etc */
+
+               if ( !dryrun ) {
+                       switch ( lr.lr_op ) {
+                       case LDAP_REQ_ADD:
+                               id = be->be_entry_put( be, e, &bvtext );
+                               break;
+
+                       case LDAP_REQ_MODIFY:
+                               id = be->be_entry_modify( be, e, &bvtext );
+                               break;
+
+                       }
+
+                       if( id == NOID ) {
+                               fprintf( stderr, "%s: could not %s entry dn=\"%s\" "
+                                       "(line=%d): %s\n", progname, request, e->e_dn,
+                                       lineno, bvtext.bv_val );
+                               rc = EXIT_FAILURE;
+                               entry_free( e );
+                               if( continuemode ) continue;
+                               break;
+                       }
+
+                       if ( verbose )
+                               fprintf( stderr, "%s: \"%s\" (%08lx)\n",
+                                       request, e->e_dn, (long) id );
+               } else {
+                       if ( verbose )
+                               fprintf( stderr, "%s: \"%s\"\n",
+                                       request, e->e_dn );
+               }
+
+               entry_free( e );
+       }
+
+done:;
+       if ( ldifrc < 0 )
+               rc = EXIT_FAILURE;
+
+       bvtext.bv_len = textlen;
+       bvtext.bv_val = textbuf;
+       bvtext.bv_val[0] = '\0';
+
+       if ( enable_meter ) {
+               lutil_meter_update( &meter, ftell( ldiffp->fp ), 1);
+               lutil_meter_close( &meter );
+       }
+
+       if ( rc == EXIT_SUCCESS && update_ctxcsn && !dryrun && sid != SLAP_SYNC_SID_MAX + 1 ) {
+               struct berval ctxdn;
+               if ( SLAP_SYNC_SUBENTRY( be )) {
+                       build_new_dn( &ctxdn, &be->be_nsuffix[0],
+                               (struct berval *)&slap_ldapsync_cn_bv, NULL );
+               } else {
+                       ctxdn = be->be_nsuffix[0];
+               }
+               ctxcsn_id = be->be_dn2id_get( be, &ctxdn );
+               if ( ctxcsn_id == NOID ) {
+                       if ( SLAP_SYNC_SUBENTRY( be )) {
+                               ctxcsn_e = slap_create_context_csn_entry( be, NULL );
+                               for ( sid = 0; sid <= SLAP_SYNC_SID_MAX; sid++ ) {
+                                       if ( maxcsn[ sid ].bv_len ) {
+                                               attr_merge_one( ctxcsn_e, slap_schema.si_ad_contextCSN,
+                                                       &maxcsn[ sid ], NULL );
+                                       }
+                               }
+                               ctxcsn_id = be->be_entry_put( be, ctxcsn_e, &bvtext );
+                               if ( ctxcsn_id == NOID ) {
+                                       fprintf( stderr, "%s: couldn't create context entry\n", progname );
+                                       rc = EXIT_FAILURE;
+                               }
+                       } else {
+                               fprintf( stderr, "%s: context entry is missing\n", progname );
+                               rc = EXIT_FAILURE;
+                       }
+               } else {
+                       ctxcsn_e = be->be_entry_get( be, ctxcsn_id );
+                       if ( ctxcsn_e != NULL ) {
+                               Entry *e = entry_dup( ctxcsn_e );
+                               int change;
+                               Attribute *attr = attr_find( e->e_attrs, slap_schema.si_ad_contextCSN );
+                               if ( attr ) {
+                                       int             i;
+
+                                       change = 0;
+
+                                       for ( i = 0; !BER_BVISNULL( &attr->a_nvals[ i ] ); i++ ) {
+                                               int rc_sid;
+
+                                               rc_sid = slap_parse_csn_sid( &attr->a_nvals[ i ] );
+                                               if ( rc_sid < 0 ) {
+                                                       Debug( LDAP_DEBUG_ANY,
+                                                               "%s: unable to extract SID "
+                                                               "from #%d contextCSN=%s\n",
+                                                               progname, i,
+                                                               attr->a_nvals[ i ].bv_val );
+                                                       continue;
+                                               }
+
+                                               assert( rc_sid <= SLAP_SYNC_SID_MAX );
+
+                                               sid = (unsigned)rc_sid;
+
+                                               if ( maxcsn[ sid ].bv_len == 0 ) {
+                                                       match = -1;
+
+                                               } else {
+                                                       value_match( &match, slap_schema.si_ad_entryCSN,
+                                                               slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
+                                                               SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
+                                                               &maxcsn[ sid ], &attr->a_nvals[i], &text );
+                                               }
+
+                                               if ( match > 0 ) {
+                                                       change = 1;
+                                               } else {
+                                                       AC_MEMCPY( maxcsn[ sid ].bv_val,
+                                                               attr->a_nvals[ i ].bv_val,
+                                                               attr->a_nvals[ i ].bv_len );
+                                                       maxcsn[ sid ].bv_val[ attr->a_nvals[ i ].bv_len ] = '\0';
+                                                       maxcsn[ sid ].bv_len = attr->a_nvals[ i ].bv_len;
+                                               }
+                                       }
+
+                                       if ( change ) {
+                                               if ( attr->a_nvals != attr->a_vals ) {
+                                                       ber_bvarray_free( attr->a_nvals );
+                                               }
+                                               attr->a_nvals = NULL;
+                                               ber_bvarray_free( attr->a_vals );
+                                               attr->a_vals = NULL;
+                                               attr->a_numvals = 0;
+                                       }
+                               } else {
+                                       change = 1;
+                               }
+
+                               if ( change ) {
+                                       for ( sid = 0; sid <= SLAP_SYNC_SID_MAX; sid++ ) {
+                                               if ( maxcsn[ sid ].bv_len ) {
+                                                       attr_merge_one( e, slap_schema.si_ad_contextCSN,
+                                                               &maxcsn[ sid], NULL );
+                                               }
+                                       }
+
+                                       ctxcsn_id = be->be_entry_modify( be, e, &bvtext );
+                                       if( ctxcsn_id == NOID ) {
+                                               fprintf( stderr, "%s: could not modify ctxcsn\n",
+                                                       progname);
+                                               rc = EXIT_FAILURE;
+                                       } else if ( verbose ) {
+                                               fprintf( stderr, "modified: \"%s\" (%08lx)\n",
+                                                       e->e_dn, (long) ctxcsn_id );
+                                       }
+                               }
+                               entry_free( e );
+                       }
+               } 
+       }
+
+       ch_free( buf );
+
+       if ( !dryrun ) {
+               if ( enable_meter ) {
+                       fprintf( stderr, "Closing DB..." );
+               }
+               if( be->be_entry_close( be ) ) {
+                       rc = EXIT_FAILURE;
+               }
+
+               if( be->be_sync ) {
+                       be->be_sync( be );
+               }
+               if ( enable_meter ) {
+                       fprintf( stderr, "\n" );
+               }
+       }
+
+       if ( slap_tool_destroy())
+               rc = EXIT_FAILURE;
+
+       return rc;
+}
+