summaryrefslogtreecommitdiffstats
path: root/ldap/servers/plugins/retrocl/retrocl_po.c
diff options
context:
space:
mode:
authorcvsadm <cvsadm>2005-01-21 00:44:34 +0000
committercvsadm <cvsadm>2005-01-21 00:44:34 +0000
commitb2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch)
treecf58939393a9032182c4fbc4441164a9456e82f8 /ldap/servers/plugins/retrocl/retrocl_po.c
downloadds-ldapserver7x.tar.gz
ds-ldapserver7x.tar.xz
ds-ldapserver7x.zip
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'ldap/servers/plugins/retrocl/retrocl_po.c')
-rw-r--r--ldap/servers/plugins/retrocl/retrocl_po.c529
1 files changed, 529 insertions, 0 deletions
diff --git a/ldap/servers/plugins/retrocl/retrocl_po.c b/ldap/servers/plugins/retrocl/retrocl_po.c
new file mode 100644
index 00000000..96512a51
--- /dev/null
+++ b/ldap/servers/plugins/retrocl/retrocl_po.c
@@ -0,0 +1,529 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "retrocl.h"
+
+static int
+entry2reple( Slapi_Entry *e, Slapi_Entry *oe );
+
+static int
+mods2reple( Slapi_Entry *e, LDAPMod **ldm );
+
+static int
+modrdn2reple( Slapi_Entry *e, const char *newrdn, int deloldrdn,
+ LDAPMod **ldm, const char *newsup );
+
+/******************************/
+
+const char *attr_changenumber = "changenumber";
+const char *attr_targetdn = "targetdn";
+const char *attr_changetype = "changetype";
+const char *attr_newrdn = "newrdn";
+const char *attr_deleteoldrdn = "deleteoldrdn";
+const char *attr_changes = "changes";
+const char *attr_newsuperior = "newsuperior";
+const char *attr_changetime = "changetime";
+const char *attr_objectclass = "objectclass";
+
+/*
+ * Function: make_changes_string
+ *
+ * Returns:
+ *
+ * Arguments:
+ *
+ * Description:
+ * loop through the LDAPMod struct and construct the changes attribute/
+ *
+ */
+
+static lenstr *make_changes_string(LDAPMod **ldm, const char **includeattrs)
+{
+ lenstr *l;
+ int i, j, len;
+ int skip;
+
+ l = lenstr_new();
+
+ for ( i = 0; ldm[ i ] != NULL; i++ ) {
+ /* If a list of explicit attributes was given, only add those */
+ if ( NULL != includeattrs ) {
+ skip = 1;
+ for ( j = 0; includeattrs[ j ] != NULL; j++ ) {
+ if ( strcasecmp( includeattrs[ j ], ldm[ i ]->mod_type ) == 0 ) {
+ skip = 0;
+ break;
+ }
+ }
+ if ( skip ) {
+ continue;
+ }
+ }
+ switch ( ldm[ i ]->mod_op & ~LDAP_MOD_BVALUES ) {
+ case LDAP_MOD_ADD:
+ addlenstr( l, "add: " );
+ addlenstr( l, ldm[ i ]->mod_type );
+ addlenstr( l, "\n" );
+ break;
+ case LDAP_MOD_DELETE:
+ addlenstr( l, "delete: " );
+ addlenstr( l, ldm[ i ]->mod_type );
+ addlenstr( l, "\n" );
+ break;
+ case LDAP_MOD_REPLACE:
+ addlenstr( l, "replace: " );
+ addlenstr( l, ldm[ i ]->mod_type );
+ addlenstr( l, "\n" );
+ break;
+ }
+ for ( j = 0; ldm[ i ]->mod_bvalues != NULL &&
+ ldm[ i ]->mod_bvalues[ j ] != NULL; j++ ) {
+ char *buf = NULL;
+ char *bufp = NULL;
+
+ len = strlen( ldm[ i ]->mod_type );
+ len = LDIF_SIZE_NEEDED( len,
+ ldm[ i ]->mod_bvalues[ j ]->bv_len ) + 1;
+ buf = slapi_ch_malloc( len );
+ bufp = buf;
+ ldif_put_type_and_value( &bufp, ldm[ i ]->mod_type,
+ ldm[ i ]->mod_bvalues[ j ]->bv_val,
+ ldm[ i ]->mod_bvalues[ j ]->bv_len );
+ *bufp = '\0';
+
+ addlenstr( l, buf );
+
+ free( buf );
+ }
+ addlenstr( l, "-\n" );
+ }
+ return l;
+}
+
+/*
+ * Function: write_replog_db
+ * Arguments: be - backend to which this change is being applied
+ * optype - type of LDAP operation being logged
+ * dn - distinguished name of entry being changed
+ * log_m - pointer to the actual change operation on a modify
+ * flag - only used by modrdn operations - value of deleteoldrdn
+ * curtime - the current time
+ * Returns: nothing
+ * Description: Given a change, construct an entry which is to be added to the
+ * changelog database.
+ */
+static void
+write_replog_db(
+ int optype,
+ char *dn,
+ LDAPMod **log_m,
+ int flag,
+ time_t curtime,
+ Slapi_Entry *log_e,
+ const char *newrdn,
+ LDAPMod **modrdn_mods,
+ const char *newsuperior
+)
+{
+ char *pat, *edn;
+ struct berval *vals[ 2 ];
+ struct berval val;
+ Slapi_Entry *e;
+ char chnobuf[ 20 ];
+ int err;
+ Slapi_PBlock *pb = NULL;
+ changeNumber changenum;
+
+ PR_Lock(retrocl_internal_lock);
+ changenum = retrocl_assign_changenumber();
+
+ PR_ASSERT( changenum > 0UL );
+ slapi_log_error( SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
+ "write_replog_db: write change record %d for dn: \"%s\"\n",
+ changenum, ( dn == NULL ) ? "NULL" : dn );
+
+ /* Construct the dn of this change record */
+ pat = "%s=%lu,%s";
+ edn = slapi_ch_malloc( strlen( pat ) + strlen( RETROCL_CHANGELOG_DN) + 20 );
+ sprintf( edn, pat, attr_changenumber, changenum, RETROCL_CHANGELOG_DN);
+
+ /*
+ * Create the entry struct, and fill in fields common to all types
+ * of change records.
+ */
+ vals[ 0 ] = &val;
+ vals[ 1 ] = NULL;
+
+ e = slapi_entry_alloc();
+ slapi_entry_set_dn( e, slapi_ch_strdup( edn ));
+
+ /* Set the objectclass attribute */
+ val.bv_val = "top";
+ val.bv_len = 3;
+ slapi_entry_add_values( e, "objectclass", vals );
+
+ val.bv_val = "changelogentry";
+ val.bv_len = 14;
+ slapi_entry_add_values( e, "objectclass", vals );
+
+ /* Set the changeNumber attribute */
+ sprintf( chnobuf, "%lu", changenum );
+ val.bv_val = chnobuf;
+ val.bv_len = strlen( chnobuf );
+ slapi_entry_add_values( e, attr_changenumber, vals );
+
+ /* Set the targetentrydn attribute */
+ val.bv_val = dn;
+ val.bv_len = strlen( dn );
+ slapi_entry_add_values( e, attr_targetdn, vals );
+
+ /* Set the changeTime attribute */
+ val.bv_val = format_genTime (curtime);
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_add_values( e, attr_changetime, vals );
+ free( val.bv_val );
+
+ /*
+ * Finish constructing the entry. How to do it depends on the type
+ * of modification being logged.
+ */
+ err = 0;
+ switch ( optype ) {
+ case OP_ADD:
+ if ( entry2reple( e, log_e ) != 0 ) {
+ err = 1;
+ }
+ break;
+
+ case OP_MODIFY:
+ if ( mods2reple( e, log_m ) != 0 ) {
+ err = 1;
+ }
+ break;
+
+ case OP_MODRDN:
+ if ( modrdn2reple( e, newrdn, flag, modrdn_mods, newsuperior ) != 0 ) {
+ err = 1;
+ }
+ break;
+
+ case OP_DELETE:
+ /* Set the changetype attribute */
+ val.bv_val = "delete";
+ val.bv_len = 6;
+ slapi_entry_add_values( e, attr_changetype, vals );
+ break;
+ default:
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "replog: Unknown LDAP operation type "
+ "%d.\n", optype );
+ err = 1;
+ }
+
+ /* Call the repl backend to add this entry */
+ if ( 0 == err ) {
+ int rc;
+
+ pb = slapi_pblock_new ();
+ slapi_add_entry_internal_set_pb( pb, e, NULL /* controls */,
+ g_plg_identity[PLUGIN_RETROCL],
+ 0 /* actions */ );
+ slapi_add_internal_pb (pb);
+ slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rc );
+ slapi_pblock_destroy(pb);
+ if ( 0 != rc ) {
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "replog: an error occured while adding change "
+ "number %d, dn = %s: %s. \n",
+ changenum, edn, ldap_err2string( rc ));
+ retrocl_release_changenumber();
+ } else {
+ /* Tell the change numbering system this one's committed to disk */
+ retrocl_commit_changenumber( );
+ }
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "An error occurred while constructing "
+ "change record number %ld.\n", changenum );
+ retrocl_release_changenumber();
+ }
+ PR_Unlock(retrocl_internal_lock);
+ if ( NULL != edn ) {
+ slapi_ch_free((void **) &edn);
+ }
+
+}
+
+
+/*
+ * Function: entry2reple
+ * Arguments: e - a partially-constructed Slapi_Entry structure
+ * oe - the original entry (an entry being added by a client).
+ * Returns: 0 on success.
+ * Description: Given an Slapi_Entry struct, construct a changelog entry which will be
+ * added to the replication database. It is assumed that e points
+ * to an entry obtained from slapi_entry_alloc().
+ */
+static int
+entry2reple( Slapi_Entry *e, Slapi_Entry *oe )
+{
+ char *p, *estr;
+ struct berval *vals[ 2 ];
+ struct berval val;
+ int len;
+
+ vals[ 0 ] = &val;
+ vals[ 1 ] = NULL;
+
+ /* Set the changetype attribute */
+ val.bv_val = "add";
+ val.bv_len = 3;
+ slapi_entry_add_values( e, attr_changetype, vals );
+
+ estr = slapi_entry2str( oe, &len );
+ p = estr;
+ /* Skip over the dn: line */
+ while (( p = strchr( p, '\n' )) != NULL ) {
+ p++;
+ if ( !ldap_utf8isspace( p )) {
+ break;
+ }
+ }
+ val.bv_val = p;
+ val.bv_len = len - ( p - estr ); /* length + terminating \0 */
+ slapi_entry_add_values( e, attr_changes, vals );
+ free( estr );
+ return 0;
+}
+
+/*
+ * Function: mods2reple
+ * Arguments: e - a partially-constructed Slapi_Entry structure
+ * ldm - an array of pointers to LDAPMod structures describing the
+ * change applied.
+ * Returns: 0 on success.
+ * Description: Given a pointer to an LDAPMod struct and a dn, construct
+ * a new entry which will be added to the replication database.
+ * It is assumed that e points to an entry obtained from
+ * slapi_entry_alloc().
+ */
+static int
+mods2reple( Slapi_Entry *e, LDAPMod **ldm )
+{
+ struct berval val;
+ struct berval *vals[ 2 ];
+ lenstr *l;
+
+ vals[ 0 ] = &val;
+ vals[ 1 ] = NULL;
+
+ /* Set the changetype attribute */
+ val.bv_val = "modify";
+ val.bv_len = 6;
+ slapi_entry_add_values( e, "changetype", vals );
+
+ if (NULL != ldm) {
+ l = make_changes_string( ldm, NULL );
+ if ( NULL != l ) {
+ val.bv_val = l->ls_buf;
+ val.bv_len = l->ls_len + 1; /* string + terminating \0 */
+ slapi_entry_add_values( e, attr_changes, vals );
+ lenstr_free( &l );
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * Function: modrdn2reple
+ * Arguments: e - a partially-constructed Slapi_Entry structure
+ * newrdn - the new relative distinguished name for the entry
+ * deloldrdn - the "deleteoldrdn" flag provided by the client
+ * ldm - any modifications applied as a side-effect of the modrdn
+ * Returns: 0 on success
+ * Description: Given a dn, a new rdn, and a deleteoldrdn flag, construct
+ * a new entry which will be added to the replication database reflecting a
+ * completed modrdn operation. The entry has the same form as above.
+ * It is assumed that e points to an entry obtained from slapi_entry_alloc().
+ */
+static int
+modrdn2reple(
+ Slapi_Entry *e,
+ const char *newrdn,
+ int deloldrdn,
+ LDAPMod **ldm,
+ const char *newsuperior
+)
+{
+ struct berval val;
+ struct berval *vals[ 2 ];
+ lenstr *l;
+ static const char *lastmodattrs[] = {"modifiersname", "modifytimestamp",
+ "creatorsname", "createtimestamp",
+ NULL };
+
+ vals[ 0 ] = &val;
+ vals[ 1 ] = NULL;
+
+ val.bv_val = "modrdn";
+ val.bv_len = 6;
+ slapi_entry_add_values( e, attr_changetype, vals );
+
+ if (newrdn) {
+ val.bv_val = (char *)newrdn; /* cast away const */
+ val.bv_len = strlen( newrdn );
+ slapi_entry_add_values( e, attr_newrdn, vals );
+ }
+
+ if ( deloldrdn == 0 ) {
+ val.bv_val = "FALSE";
+ val.bv_len = 5;
+ } else {
+ val.bv_val = "TRUE";
+ val.bv_len = 4;
+ }
+ slapi_entry_add_values( e, attr_deleteoldrdn, vals );
+
+ if (newsuperior) {
+ val.bv_val = (char *)newsuperior; /* cast away const */
+ val.bv_len = strlen(newsuperior);
+ slapi_entry_add_values(e, attr_newsuperior,vals);
+ }
+
+ if (NULL != ldm) {
+ l = make_changes_string( ldm, lastmodattrs );
+ if ( NULL != l ) {
+ val.bv_val = l->ls_buf;
+ val.bv_len = l->ls_len + 1; /* string + terminating \0 */
+ slapi_entry_add_values( e, attr_changes, vals );
+ lenstr_free( &l );
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Function: retrocl_postob
+ *
+ * Returns: 0 on success
+ *
+ * Arguments: pblock, optype (add, del, modify etc)
+ *
+ * Description: called from retrocl.c op-specific plugins.
+ *
+ * Please be aware that operation threads may be scheduled out between their
+ * being performed inside of the LDBM database and the changelog plugin
+ * running. For example, suppose MA and MB are two modify operations on the
+ * same entry. MA may be performed on the LDBM database, and then block
+ * before the changelog runs. MB then runs against the LDBM database and then
+ * is written to the changelog. MA starts running. In the changelog, MB will
+ * appear to have been performed before MA, but in the LDBM database the
+ * opposite will have occured.
+ *
+ *
+ */
+
+int retrocl_postob (Slapi_PBlock *pb,int optype)
+{
+ char *dn;
+ LDAPMod **log_m = NULL;
+ int flag = 0;
+ Slapi_Entry *te = NULL;
+ Slapi_Operation *op = NULL;
+ LDAPMod **modrdn_mods = NULL;
+ char *newrdn = NULL;
+ char *newsuperior = NULL;
+ Slapi_Backend *be = NULL;
+ time_t curtime;
+ int rc;
+
+ /*
+ * Check to see if the change was made to the replication backend db.
+ * If so, don't try to log it to the db (otherwise, we'd get in a loop).
+ */
+
+ (void)slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+
+ if (slapi_be_logchanges(be) == 0) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if not logging\n",
+ 0,0,0);
+ return 0;
+ }
+
+ if (retrocl_be_changelog == NULL || be == retrocl_be_changelog) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if no/cl be\n",0,0,0);
+ return 0;
+ }
+
+ slapi_pblock_get(pb, SLAPI_RESULT_CODE, &rc);
+
+ if (rc != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if op failed %d\n",rc,
+ 0,0);
+ return 0;
+ }
+
+ if (slapi_op_abandoned(pb)) {
+ LDAPDebug(LDAP_DEBUG_PLUGIN,"not applying change if op abandoned\n",
+ 0,0,0);
+ return 0;
+ }
+
+ curtime = current_time();
+
+ (void)slapi_pblock_get( pb, SLAPI_ORIGINAL_TARGET_DN, &dn );
+
+ /* change number could be retrieved from Operation extension stored in
+ * the pblock, or else it needs to be made dynamically. */
+
+ /* get the operation extension and retrieve the change number */
+ slapi_pblock_get( pb, SLAPI_OPERATION, &op );
+
+ if (op == NULL) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if no op\n",0,0,0);
+ return 0;
+ }
+
+ if (operation_is_flag_set(op, OP_FLAG_TOMBSTONE_ENTRY)){
+ LDAPDebug(LDAP_DEBUG_TRACE,"not applying change for nsTombstone entries\n",0,0,0);
+ return 0;
+ }
+
+ switch ( optype ) {
+ case OP_MODIFY:
+ (void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &log_m );
+ break;
+ case OP_ADD:
+ /*
+ * For adds, we want the unnormalized dn, so we can preserve
+ * spacing, case, when replicating it.
+ */
+ (void)slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &te );
+ if ( NULL != te ) {
+ dn = slapi_entry_get_dn( te );
+ }
+ break;
+ case OP_DELETE:
+ break;
+ case OP_MODRDN:
+ (void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn );
+ (void)slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &flag );
+ (void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &modrdn_mods );
+ (void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR, &newsuperior);
+ break;
+ }
+
+
+ /* check if we should log change to retro changelog, and
+ * if so, do it here */
+ write_replog_db( optype, dn, log_m, flag, curtime, te,
+ newrdn, modrdn_mods, newsuperior );
+
+ return 0;
+}
+
+