[389-commits] ldap/servers

Noriko Hosoi nhosoi at fedoraproject.org
Wed Jan 12 17:39:40 UTC 2011


 ldap/servers/plugins/replication/cl5_api.c              |  277 ++++++++++--
 ldap/servers/plugins/replication/cl5_clcache.c          |   15 
 ldap/servers/plugins/replication/repl5_replica_config.c |  345 +++++++++++++++-
 ldap/servers/plugins/replication/repl5_ruv.c            |    7 
 ldap/servers/slapd/slapi-private.h                      |    1 
 5 files changed, 576 insertions(+), 69 deletions(-)

New commits:
commit ad3c528db4824d4d5568b6b3c36ade917905f445
Author: Noriko Hosoi <nhosoi at jiji.usersys.redhat.com>
Date:   Tue Jan 11 18:57:08 2011 -0800

    Bug 663752 - Cert renewal for attrcrypt and encchangelog
    
    https://bugzilla.redhat.com/show_bug.cgi?id=663752
    
    Description: In fixing Bug 182507, the feature to encrypt changelogs
    had been introduced. The changelog encryption depends on the server
    certificate as the attrcrypt does.  When the server certificate is
    renewed, the encrypted changelog won't be decrypted.  This patch
    implements/completes the feature to export and import the contents
    of the changelog to provide the scenario to update the encrypted
    changelogs along with the cert renewal.
    
    See also this section for the steps to export/import changelogs.
    http://directory.fedoraproject.org/wiki/Changelog_Encryption#Steps_for_Certificate_Renewal

diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
index e257ccd..9922131 100644
--- a/ldap/servers/plugins/replication/cl5_api.c
+++ b/ldap/servers/plugins/replication/cl5_api.c
@@ -852,8 +852,7 @@ done:;
    Description:	imports ldif file into changelog; changelog must be in the closed state
    Parameters:  clDir - changelog dir
 				ldifFile - absolute path to the ldif file to import
-				replicas - optional list of replicas whose data should be imported;
-						   if the list is NULL, all data in the file is imported.
+				replicas - optional list of replicas whose data should be imported.
    Return:		CL5_SUCCESS if function is successfull;
 				CL5_BAD_DATA if invalid parameter is passed;
 				CL5_BAD_STATE if changelog is open or not inititalized;
@@ -861,7 +860,8 @@ done:;
 				CL5_SYSTEM_ERROR if NSPR call fails;
 				CL5_MEMORY_ERROR if memory allocation fials.
  */
-int cl5ImportLDIF (const char *clDir, const char *ldifFile, Object **replicas)
+int
+cl5ImportLDIF (const char *clDir, const char *ldifFile, Object **replicas)
 {
 #if defined(USE_OPENLDAP)
 	LDIFFP *file = NULL;
@@ -873,8 +873,19 @@ int cl5ImportLDIF (const char *clDir, const char *ldifFile, Object **replicas)
 	char *buff = NULL;
 	int lineno = 0;
 	slapi_operation_parameters op;
-    Object *replica = NULL;
-    char *replGen = NULL;
+	Object *prim_replica_obj = NULL;
+	Object *replica_obj = NULL;
+	Object *file_obj = NULL;
+	Replica *prim_replica = NULL;
+	char *replGen = NULL;
+	CL5DBFile *dbfile = NULL;
+	struct berval **purgevals = NULL;
+	struct berval **maxvals = NULL;
+	int purgeidx = 0;
+	int maxidx = 0;
+	int maxpurgesz = 8;
+	int maxmaxsz = 8;
+	int entryCount = 0;
 
 	/* validate params */
 	if (ldifFile == NULL)
@@ -891,6 +902,16 @@ int cl5ImportLDIF (const char *clDir, const char *ldifFile, Object **replicas)
 		return CL5_BAD_STATE;	
 	}
 
+	prim_replica_obj = replicas[0];
+	if (NULL == prim_replica_obj)
+	{
+		/* Never happens for now. (see replica_execute_ldif2cl_task) */
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
+						"cl5ImportLDIF: empty replica list\n");
+		return CL5_BAD_DATA;
+	}
+	prim_replica = (Replica*)object_get_data(prim_replica_obj);
+
 	/* make sure that nobody change changelog state while import is in progress */
 	PR_RWLock_Wlock (s_cl5Desc.stLock);
 
@@ -936,6 +957,7 @@ int cl5ImportLDIF (const char *clDir, const char *ldifFile, Object **replicas)
 						"cl5ImportLDIF: failed to open changelog\n");
 		goto done;
 	}
+	s_cl5Desc.dbState = CL5_STATE_OPEN; /* force to change the state */
 	
 	/* read entries and write them to changelog */
 #if defined(USE_OPENLDAP)
@@ -945,50 +967,154 @@ int cl5ImportLDIF (const char *clDir, const char *ldifFile, Object **replicas)
 #endif
 	{
 		rc = _cl5LDIF2Operation (buff, &op, &replGen);
-		slapi_ch_free_string(&buff);
 		if (rc != CL5_SUCCESS)
 		{
-			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
-				"cl5ImportLDIF: failed to convert LDIF fragment to LDAP operation; "
-				"end of fragment line number - %d\n", lineno);
-			goto done;
+            /*
+             * clpurgeruv: {replicageneration} 4d13a124000000010000
+             * clpurgeruv: {replica 2 ldap://host:port} 
+             * clpurgeruv: {replica 1 ldap://host:port} 
+             * clmaxruv: {replicageneration} 4d13a124000000010000
+             * clmaxruv: {replica 2} <mincsn> <maxcsn> <timestamp>
+             * clmaxruv: {replica 1} <mincsn> <maxcsn> <timestamp>
+             */
+            char *line;
+            char *next = buff;
+            struct berval type, value;
+            int freeval = 0;
+
+            purgevals = (struct berval **)slapi_ch_malloc(
+                                          sizeof(struct berval *) * maxpurgesz);
+            maxvals = (struct berval **)slapi_ch_malloc(
+                                          sizeof(struct berval *) * maxmaxsz);
+            while ((line = ldif_getline(&next)) != NULL) {
+                rc = slapi_ldif_parse_line(line, &type, &value, &freeval);
+                /* ruv_dump (dbfile->purgeRUV, "clpurgeruv", prFile); */
+                if (0 == strcasecmp (type.bv_val, "clpurgeruv")) {
+                    if (maxpurgesz == purgeidx + 2) {
+                        maxpurgesz *= 2;
+                        purgevals = (struct berval **)slapi_ch_realloc(
+                                          (char *)purgevals,
+                                          sizeof(struct berval *) * maxpurgesz);
+                    }
+                    purgevals[purgeidx++] = slapi_ch_bvdup(&value);
+                }
+                /* ruv_dump (dbfile->maxRUV, "clmaxruv", prFile); */
+                else if (0 == strcasecmp (type.bv_val, "clmaxruv")) {
+                    if (maxmaxsz == maxidx + 2) {
+                        maxmaxsz *= 2;
+                        maxvals = (struct berval **)slapi_ch_realloc(
+                                          (char *)maxvals,
+                                          sizeof(struct berval *) * maxmaxsz);
+                    }
+                    /* {replica #} min_csn csn [last_modified] */
+                    /* get rid of last_modified, if any */
+                    maxvals[maxidx++] = slapi_ch_bvdup(&value);
+                }
+                if (freeval) {
+                    slapi_ch_free_string(&value.bv_val);
+                }
+            }
+            slapi_ch_free_string(&buff);
+            goto next;
 		}
+		slapi_ch_free_string(&buff);
 
 		/* if we perform selective import, check if the operation should be wriiten to changelog */
-        replica = _cl5GetReplica (&op, replGen);
-        if (replica == NULL)
+        replica_obj = _cl5GetReplica (&op, replGen);
+        if (replica_obj == NULL)
         {
-            slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
-				"cl5ImportLDIF: failed to locate replica for target dn (%s) and "
-                "replica generation %s\n", op.target_address.dn, replGen);
-			
-            slapi_ch_free_string(&replGen);
-            operation_parameters_done (&op);
-			goto done;
+            /* 
+             * changetype: delete
+             * replgen: 4d13a124000000010000
+             * csn: 4d23b909000000020000
+             * nsuniqueid: 00000000-00000000-00000000-00000000
+             * dn: cn=start iteration
+             */
+            rc = _cl5WriteOperation (replica_get_name(prim_replica), 
+                                     replGen, &op, 1);
+            if (rc != CL5_SUCCESS)
+            {
+                slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
+                        "cl5ImportLDIF: "
+                        "failed to write operation to the changelog: "
+                        "type: %lu, dn: %s\n",
+                        op.operation_type, op.target_address.dn);
+                object_release (replica_obj);
+                slapi_ch_free_string(&replGen);
+                operation_parameters_done (&op);
+                goto done;
+            }
+            entryCount++;
+            goto next;
         }
 
-		if (!replicas || _cl5ReplicaInList (replica, replicas))
+		if (!replicas || _cl5ReplicaInList (replica_obj, replicas))
 		{
 			/* write operation creates the file if it does not exist */
-			rc = _cl5WriteOperation (replica_get_name ((Replica*)object_get_data(replica)), 
+			rc = _cl5WriteOperation (replica_get_name ((Replica*)object_get_data(replica_obj)), 
                                      replGen, &op, 1);
 			if (rc != CL5_SUCCESS)
 			{
-				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
-						"cl5ImportLDIF: failed to write operation to the changelog\n");
-                object_release (replica);
+                slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
+                        "cl5ImportLDIF: "
+                        "failed to write operation to the changelog: "
+                        "type: %lu, dn: %s\n",
+                        op.operation_type, op.target_address.dn);
+                object_release (replica_obj);
                 slapi_ch_free_string(&replGen);
 				operation_parameters_done (&op);
 				goto done;
 			}
+            entryCount++;
 		}
-        
-        object_release (replica);
+next:
+        if (replica_obj) {
+            object_release (replica_obj);
+        }
         slapi_ch_free_string(&replGen);
-		operation_parameters_done (&op);
+        operation_parameters_done (&op);
 	}
 
-done:;
+    /* Set RUVs and entry count */
+    file_obj = objset_first_obj(s_cl5Desc.dbFiles);
+    while (file_obj)
+    {
+        dbfile = (CL5DBFile *)object_get_data(file_obj);
+        if (0 == strcasecmp(dbfile->replName, replica_get_name(prim_replica))) {
+            break;
+        }
+        dbfile = NULL;
+        file_obj = objset_next_obj(s_cl5Desc.dbFiles, file_obj);
+    }
+
+    if (dbfile) {
+        if (purgeidx > 0) {
+            ruv_destroy (&dbfile->purgeRUV);
+            purgevals[purgeidx] = NULL;
+            rc = ruv_init_from_bervals(purgevals, &dbfile->purgeRUV);
+        }
+        if (maxidx > 0) {
+            ruv_destroy (&dbfile->maxRUV);
+            maxvals[maxidx] = NULL;
+            rc = ruv_init_from_bervals(maxvals, &dbfile->maxRUV);
+        }
+
+        for (purgeidx = 0; purgevals && purgevals[purgeidx]; purgeidx++) {
+            slapi_ch_bvfree(&purgevals[purgeidx]);
+        }
+        slapi_ch_free((void **)&purgevals);
+        for (maxidx = 0; maxvals && maxvals[maxidx]; maxidx++) {
+            slapi_ch_bvfree(&maxvals[maxidx]);
+        }
+        slapi_ch_free((void **)&maxvals);
+
+        dbfile->entryCount = entryCount;
+    }
+    if (file_obj) {
+        object_release (file_obj);
+    }
+
+done:
 	if (file) {
 #if defined(USE_OPENLDAP)
 		ldif_close(file);
@@ -996,7 +1122,10 @@ done:;
 		fclose(file);
 #endif
 	}
-	_cl5Close ();
+	if (CL5_STATE_OPEN == s_cl5Desc.dbState) {
+		_cl5Close ();
+		s_cl5Desc.dbState = CL5_STATE_CLOSED; /* force to change the state */
+	}
 	PR_RWLock_Unlock (s_cl5Desc.stLock);
     return rc;
 }
@@ -1702,6 +1831,9 @@ static int _cl5Open (const char *dir, const CL5DBConfig *config, CL5OpenMode ope
 		goto done;
 	}
 
+	if (s_cl5Desc.dbDir) {
+		slapi_ch_free_string (&s_cl5Desc.dbDir);
+	}
 	s_cl5Desc.dbDir = slapi_ch_strdup (dir);
 
 	/* check database version */
@@ -1902,7 +2034,8 @@ static int _cl5DBOpen ()
 
                 PR_snprintf(fullpathname, MAXPATHLEN, "%s/%s", s_cl5Desc.dbDir, entry->name);
                 rc = s_cl5Desc.dbEnv->dbremove(s_cl5Desc.dbEnv,
-                                               0, fullpathname, 0, 0);
+                                               0, fullpathname, 0,
+                                               DEFAULT_DB_OP_FLAGS);
                 if (rc != 0)
                 {
                     slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
@@ -3089,12 +3222,24 @@ static int  _cl5Delete (const char *clDir, int rmDir)
 		PR_snprintf(filename, MAXPATHLEN, "%s/%s", clDir, entry->name);
 		/* _cl5Delete deletes the whole changelog directory with all the files 
 		 * underneath.  Thus, we can just remove them physically. */
-		rc = PR_Delete(filename);
-		if (rc != PR_SUCCESS)
-		{
-			slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, 
-					"_cl5Delete: failed to remove (%s) file; NSPR error - %d\n",
+		if (0 == strcmp(entry->name, VERSION_FILE)) {
+			/* DBVERSION */
+			rc = PR_Delete(filename) != PR_SUCCESS;
+			if (PR_SUCCESS != rc) {
+				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
+					"_cl5Delete: failed to remove \"%s\"; NSPR error - %d\n",
 					filename, PR_GetError ());
+			}
+		} else {
+			/* DB files */
+			rc = s_cl5Desc.dbEnv->dbremove(s_cl5Desc.dbEnv, 0, filename, 0,
+                                           DEFAULT_DB_OP_FLAGS);
+			if (rc) {
+				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
+				                "_cl5Delete: failed to remove \"%s\"; "
+				                "libdb error - %d (%s)\n",
+				                filename, rc, db_strerror(rc));
+			}
 		}
 	}
 		
@@ -4115,18 +4260,20 @@ static int
 _cl5LDIF2Operation (char *ldifEntry, slapi_operation_parameters *op, char **replGen)
 {
 	int rc;
+	int rval = CL5_BAD_FORMAT;
 	char *next, *line;
 	struct berval type, value;
 	struct berval bv_null = {0, NULL};
 	int freeval = 0;
 	Slapi_Mods *mods;
 	char *rawDN = NULL;
+	char *ldifEntryWork = slapi_ch_strdup(ldifEntry);
 
 	PR_ASSERT (op && ldifEntry && replGen);
 	
 	memset (op, 0, sizeof (*op));
 	
-	next = ldifEntry;
+	next = ldifEntryWork;
 	while ((line = ldif_getline(&next)) != NULL) 
 	{
 		if ( *line == '\n' || *line == '\0' ) 
@@ -4144,8 +4291,9 @@ _cl5LDIF2Operation (char *ldifEntry, slapi_operation_parameters *op, char **repl
 							"_cl5LDIF2Operation: warning - failed to parse ldif line\n");
 			continue;
 		}
-
-		if (strncasecmp (type.bv_val, T_CHANGETYPESTR, type.bv_len) == 0)
+		if (strncasecmp (type.bv_val, T_CHANGETYPESTR,
+			             strlen(T_CHANGETYPESTR)>type.bv_len?
+						 strlen(T_CHANGETYPESTR):type.bv_len) == 0)
 		{
 			op->operation_type = _cl5Str2OperationType (value.bv_val);	
 		}
@@ -4193,7 +4341,9 @@ _cl5LDIF2Operation (char *ldifEntry, slapi_operation_parameters *op, char **repl
 		{
 			op->p.p_modrdn.modrdn_newsuperior_address.uniqueid = slapi_ch_strdup (value.bv_val);
 		}
-		else if (strncasecmp (type.bv_val, T_CHANGESTR, type.bv_len) == 0)
+		else if (strncasecmp (type.bv_val, T_CHANGESTR,
+			                  strlen(T_CHANGESTR)>type.bv_len?
+						      strlen(T_CHANGESTR):type.bv_len) == 0)
 		{
 			PR_ASSERT (op->operation_type);
 
@@ -4210,6 +4360,7 @@ _cl5LDIF2Operation (char *ldifEntry, slapi_operation_parameters *op, char **repl
 																"_cl5LDIF2Operation: corrupted format "
 																"for operation type - %lu\n", 
 																 op->operation_type);
+													slapi_ch_free_string(&ldifEntryWork);
 													return CL5_BAD_FORMAT;
 												}
 												mods = parse_changes_string(value.bv_val);
@@ -4238,6 +4389,7 @@ _cl5LDIF2Operation (char *ldifEntry, slapi_operation_parameters *op, char **repl
 												if (freeval) {
 													slapi_ch_free_string(&value.bv_val);
 												}
+												slapi_ch_free_string(&ldifEntryWork);
 												return CL5_BAD_FORMAT;
 			}
 		}	
@@ -4246,12 +4398,21 @@ _cl5LDIF2Operation (char *ldifEntry, slapi_operation_parameters *op, char **repl
 		}
 	}
 
-	if (IsValidOperation (op))
-		return CL5_SUCCESS;
-	
-	slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
-					"_cl5LDIF2Operation: invalid data format\n");
-	return CL5_BAD_FORMAT;
+	if ((0 != strncmp(ldifEntryWork, "clpurgeruv", 10)) && /* skip RUV; */
+	    (0 != strncmp(ldifEntryWork, "clmaxruv", 8)))      /* RUV has NULL op */
+	{
+		if (IsValidOperation (op))
+		{
+			rval = CL5_SUCCESS;
+		}
+		else
+		{
+			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
+			                "_cl5LDIF2Operation: invalid data format\n");
+		}
+	}
+	slapi_ch_free_string(&ldifEntryWork);
+	return rval;
 }
 
 static int _cl5WriteOperation(const char *replName, const char *replGen, 
@@ -5339,7 +5500,6 @@ static int _cl5DBOpenFileByReplicaName (const char *replName, const char *replGe
         file_name = _cl5MakeFileName (replName, replGen);
 		tmpObj = objset_find (s_cl5Desc.dbFiles, _cl5CompareDBFile, file_name);
 		slapi_ch_free((void **)&file_name);
-		file_name = NULL;
 		if (tmpObj)	/* this file already exist */
 		{
 			slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, 
@@ -5629,6 +5789,7 @@ done:
 static void _cl5DBCloseFile (void **data)
 { 
 	CL5DBFile *file;
+	int rc = 0;
 
 	PR_ASSERT (data);
 
@@ -5651,18 +5812,23 @@ static void _cl5DBCloseFile (void **data)
 
 	/* close the db */
 	if (file->db) {
-	    file->db->close(file->db, 0);
-	    slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5DBCloseFile: "
-						"Closed the changelog database handle for %s\n", file->name);
+	    rc = file->db->close(file->db, 0);
+	    slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, 
+						"_cl5DBCloseFile: "
+						"Closed the changelog database handle for %s "
+						"(rc: %d)\n", file->name, rc);
 	    file->db = NULL;
 	}
 
 	if (file->flags & DB_FILE_DELETED)
     {
-		int rc = 0;
 		/* We need to use the libdb API to delete the files, otherwise we'll
 		 * run into problems when we try to checkpoint transactions later. */
-		rc = s_cl5Desc.dbEnv->dbremove(s_cl5Desc.dbEnv, 0, file->name, 0, 0);
+	    slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5DBCloseFile: "
+						"removing the changelog %s (flag %d)\n",
+						file->name, DEFAULT_DB_OP_FLAGS);
+		rc = s_cl5Desc.dbEnv->dbremove(s_cl5Desc.dbEnv, 0, file->name, 0,
+                                       DEFAULT_DB_OP_FLAGS);
 		if (rc != 0)
 		{
 			slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5DBCloseFile: "
@@ -5681,6 +5847,7 @@ static void _cl5DBCloseFile (void **data)
 	slapi_ch_free ((void**)&file->replGen);
 	ruv_destroy(&file->maxRUV);
 	ruv_destroy(&file->purgeRUV);
+	file->db = NULL;
 	if (file->sema) {
 		PR_CloseSemaphore (file->sema);
 		PR_DeleteSemaphore (file->semaName);
@@ -5838,7 +6005,7 @@ static int _cl5ExportFile (PRFileDesc *prFile, Object *obj)
 		if (rc != CL5_SUCCESS)
 		{
 			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
-						"_cl5ExportLDIF: failed to convert operation to ldif\n");
+						"_cl5ExportFile: failed to convert operation to ldif\n");
 			operation_parameters_done (&op);
 			break;
 		}
@@ -5848,7 +6015,7 @@ static int _cl5ExportFile (PRFileDesc *prFile, Object *obj)
 		if (wlen < len)
 		{
 			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
-						"_cl5ExportLDIF: failed to write to ldif file\n");
+						"_cl5ExportFile: failed to write to ldif file\n");
 			rc = CL5_SYSTEM_ERROR;
 			operation_parameters_done (&op);
 			break;
@@ -5867,7 +6034,7 @@ static int _cl5ExportFile (PRFileDesc *prFile, Object *obj)
 	if (rc != CL5_NOTFOUND)
 	{
 		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
-						"_cl5ExportLDIF: failed to retrieve changelog entry\n");
+						"_cl5ExportFile: failed to retrieve changelog entry\n");
 	}
 	else
 	{
@@ -5932,7 +6099,7 @@ static Object* _cl5GetReplica (const slapi_operation_parameters *op, const char*
             replObj = NULL;
         }
 
-        slapi_ch_free ((void**)&replGen);
+        slapi_ch_free ((void**)&newGen);
     }
 
     slapi_sdn_free (&sdn);
diff --git a/ldap/servers/plugins/replication/cl5_clcache.c b/ldap/servers/plugins/replication/cl5_clcache.c
index af2b7fe..6fa6985 100644
--- a/ldap/servers/plugins/replication/cl5_clcache.c
+++ b/ldap/servers/plugins/replication/cl5_clcache.c
@@ -379,7 +379,7 @@ clcache_load_buffer_bulk ( CLC_Buffer *buf, int flag )
 {
 	DB_TXN *txn = NULL;
 	DBC *cursor = NULL;
-	int rc;
+	int rc = 0;
 
 #if 0 /* txn control seems not improving anything so turn it off */
 	if ( *(_pool->pl_dbenv) ) {
@@ -387,6 +387,19 @@ clcache_load_buffer_bulk ( CLC_Buffer *buf, int flag )
 	}
 #endif
 
+	if (NULL == buf) {
+		slapi_log_error ( SLAPI_LOG_FATAL, "clcache_load_buffer_bulk",
+		                  "NULL buf\n" );
+		return rc;
+	}
+	if (NULL == buf->buf_busy_list) {
+		slapi_log_error ( SLAPI_LOG_FATAL, "clcache_load_buffer_bulk",
+		                  "%s%sno buf_busy_list\n",
+		                  buf->buf_agmt_name?buf->buf_agmt_name:"",
+		                  buf->buf_agmt_name?": ":"" );
+		return rc;
+	}
+
 	PR_Lock ( buf->buf_busy_list->bl_lock );
 	if ( 0 == ( rc = clcache_open_cursor ( txn, buf, &cursor )) ) {
 
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
index 80b5361..df9c12a 100644
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
@@ -46,20 +46,24 @@
 #include "repl.h"   /* ONREPL - this is bad */
 #include "repl5.h"
 #include "cl5_api.h"
+#include "cl5.h"
 
 /* CONFIG_BASE: no need to optimize */
 #define CONFIG_BASE		    "cn=mapping tree,cn=config"
 #define CONFIG_FILTER	    "(objectclass=nsDS5Replica)"
 #define TASK_ATTR           "nsds5Task"
 #define CL2LDIF_TASK        "CL2LDIF"
+#define LDIF2CL_TASK        "LDIF2CL"
 #define CLEANRUV            "CLEANRUV"
 #define CLEANRUVLEN         8
+#define REPLICA_RDN         "cn=replica"
 
 int slapi_log_urp = SLAPI_LOG_REPL;
 
 /* Forward Declartions */
 static int replica_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
 static int replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+static int replica_config_post_modify (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
 static int replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
 static int replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
 
@@ -68,7 +72,10 @@ static int replica_config_change_updatedn (Replica *r, const LDAPMod *mod, char
 static int replica_config_change_flags (Replica *r, const char *new_flags,  char *returntext, int apply_mods);
 static int replica_execute_task (Object *r, const char *task_name, char *returntext, int apply_mods);
 static int replica_execute_cl2ldif_task (Object *r, char *returntext);
+static int replica_execute_ldif2cl_task (Object *r, char *returntext);
 static int replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext);
+static int replica_cleanup_task (Object *r, const char *task_name, char *returntext, int apply_mods);
+static int replica_task_done(Replica *replica);
 												
 static multimaster_mtnode_extension * _replica_config_get_mtnode_ext (const Slapi_Entry *e);
 
@@ -104,6 +111,10 @@ replica_config_init()
 								   CONFIG_FILTER, replica_config_delete,NULL); 
     slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
 								   CONFIG_FILTER, replica_config_search,NULL); 
+    slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP, 
+                                   CONFIG_BASE, LDAP_SCOPE_SUBTREE,
+                                   CONFIG_FILTER, replica_config_post_modify,
+                                   NULL);
     return 0;
 }
 
@@ -127,6 +138,9 @@ replica_config_destroy ()
 								 CONFIG_FILTER, replica_config_delete);
     slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
 								 CONFIG_FILTER, replica_config_search);
+    slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, 
+                                 CONFIG_BASE, LDAP_SCOPE_SUBTREE,
+                                 CONFIG_FILTER, replica_config_post_modify);
 }
 
 static int 
@@ -448,6 +462,141 @@ done:
 }
 
 static int 
+replica_config_post_modify(Slapi_PBlock *pb,
+                           Slapi_Entry* entryBefore, 
+                           Slapi_Entry* e,
+                           int *returncode,
+                           char *returntext,
+                           void *arg)
+{
+    int rc= 0;
+    LDAPMod **mods;
+    int i, apply_mods;
+    multimaster_mtnode_extension *mtnode_ext;    
+    Replica *r = NULL;
+    char *replica_root = NULL; 
+    char buf [SLAPI_DSE_RETURNTEXT_SIZE];
+    char *errortext = returntext ? returntext : buf;
+    char *config_attr, *config_attr_value;
+    Slapi_Operation *op;
+    void *identity;
+
+    if (returntext)
+    {
+        returntext[0] = '\0';
+    }
+    *returncode = LDAP_SUCCESS;
+
+    /* just let internal operations originated from replication plugin to go through */
+    slapi_pblock_get (pb, SLAPI_OPERATION, &op);
+    slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);                
+
+    if (operation_is_flag_set(op, OP_FLAG_INTERNAL) &&
+        (identity == repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)))
+    {
+        *returncode = LDAP_SUCCESS;
+        return SLAPI_DSE_CALLBACK_OK;
+    }
+
+    replica_root = (char*)slapi_entry_attr_get_charptr (e, attr_replicaRoot);
+
+    PR_Lock (s_configLock);
+    
+    mtnode_ext = _replica_config_get_mtnode_ext (e);
+    PR_ASSERT (mtnode_ext);
+
+    if (mtnode_ext->replica)
+        object_acquire (mtnode_ext->replica);
+
+    if (mtnode_ext->replica == NULL)
+    {
+        PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE,
+                     "replica does not exist for %s", replica_root);
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+                        "replica_config_post_modify: %s\n",
+                        errortext);
+        *returncode = LDAP_OPERATIONS_ERROR;    
+        goto done;
+    }
+
+    r = object_get_data (mtnode_ext->replica);
+    PR_ASSERT (r);
+
+    slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+    for (apply_mods = 0; apply_mods <= 1; apply_mods++)
+    {
+        /* we only allow the replica ID and type to be modified together e.g.
+           if converting a read only replica to a master or vice versa - 
+           we will need to change both the replica ID and the type at the same
+           time - we must disallow changing the replica ID if the type is not
+           being changed and vice versa
+        */
+        if (*returncode != LDAP_SUCCESS)
+            break;
+
+        for (i = 0; (mods[i] && (LDAP_SUCCESS == rc)); i++)
+        {
+            if (*returncode != LDAP_SUCCESS)
+                break;
+
+            config_attr = (char *) mods[i]->mod_type;
+            PR_ASSERT (config_attr); 
+
+            /* disallow modifications or removal of replica root,
+               replica name and replica state attributes */
+            if (strcasecmp (config_attr, attr_replicaRoot) == 0 ||
+                strcasecmp (config_attr, attr_replicaName) == 0 ||
+                strcasecmp (config_attr, attr_state) == 0)
+            {
+                *returncode = LDAP_UNWILLING_TO_PERFORM;
+                PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE,
+                             "modification of %s attribute is not allowed", 
+                             config_attr);                         
+                slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+                                "replica_config_post_modify: %s\n", 
+                                errortext);
+            }
+            /* this is a request to delete an attribute */
+            else if (mods[i]->mod_op & LDAP_MOD_DELETE || 
+                     mods[i]->mod_bvalues == NULL ||
+                     mods[i]->mod_bvalues[0]->bv_val == NULL) 
+            {
+                ;
+            }
+            else    /* modify an attribute */
+            {
+                config_attr_value = (char *) mods[i]->mod_bvalues[0]->bv_val;
+
+                if (strcasecmp (config_attr, TASK_ATTR) == 0) 
+                {
+                    *returncode = replica_cleanup_task(mtnode_ext->replica,
+                                                       config_attr_value,
+                                                       errortext, apply_mods);
+                }
+            }
+        }
+    }
+
+done:
+    if (mtnode_ext->replica)
+        object_release (mtnode_ext->replica);
+    
+    /* slapi_ch_free accepts NULL pointer */
+    slapi_ch_free ((void**)&replica_root);
+
+    PR_Unlock (s_configLock);
+
+    if (*returncode != LDAP_SUCCESS)
+    {
+        return SLAPI_DSE_CALLBACK_ERROR;
+    }
+    else
+    {
+        return SLAPI_DSE_CALLBACK_OK;
+    }
+}
+
+static int 
 replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, 
 					   int *returncode, char *returntext, void *arg)
 {
@@ -653,6 +802,15 @@ static int replica_execute_task (Object *r, const char *task_name, char *returnt
 		else
 			return LDAP_SUCCESS;
 	}
+	else if (strcasecmp (task_name, LDIF2CL_TASK) == 0)
+    {
+		if (apply_mods)
+		{
+			return replica_execute_ldif2cl_task (r, returntext);
+		}
+		else
+			return LDAP_SUCCESS;
+	}
 	else if (strncasecmp (task_name, CLEANRUV, CLEANRUVLEN) == 0)
 	{
 		int temprid = atoi(&(task_name[CLEANRUVLEN]));
@@ -680,6 +838,69 @@ static int replica_execute_task (Object *r, const char *task_name, char *returnt
     
 }
 
+static int 
+replica_cleanup_task (Object *r, const char *task_name, char *returntext, 
+                      int apply_mods)
+{
+    int rc = LDAP_SUCCESS;
+    if (apply_mods) {
+        Replica *replica = (Replica*)object_get_data (r);
+        if (NULL == replica) {
+            rc = LDAP_OPERATIONS_ERROR;    
+        } else {
+            rc = replica_task_done(replica);
+        }
+    }
+    return rc;
+}
+
+static int
+replica_task_done(Replica *replica)
+{
+    int rc = LDAP_OPERATIONS_ERROR;
+    char *replica_dn = NULL;
+    Slapi_PBlock *pb = NULL;
+    LDAPMod *mods [2];
+    LDAPMod mod;
+    if (NULL == replica) {
+        return rc;
+    }
+    /* dn: cn=replica,cn=dc\3Dexample\2Cdc\3Dcom,cn=mapping tree,cn=config */
+    replica_dn = slapi_create_dn_string("%s,cn=\"%s\",%s",
+                                    REPLICA_RDN,
+                                    slapi_sdn_get_dn(replica_get_root(replica)),
+                                    CONFIG_BASE);
+    if (NULL == replica_dn) {
+        return rc;
+    }
+    pb = slapi_pblock_new();
+    mods[0] = &mod;
+    mods[1] = NULL;
+    mod.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
+    mod.mod_type = (char *)TASK_ATTR;
+    mod.mod_bvalues = NULL;
+
+    slapi_modify_internal_set_pb(pb, replica_dn, mods, NULL/* controls */, 
+                      NULL/* uniqueid */, 
+                      repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION),
+                      0/* flags */);
+    slapi_modify_internal_pb (pb);
+
+    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+    if ((rc != LDAP_SUCCESS) && (rc != LDAP_NO_SUCH_ATTRIBUTE)) {
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+                        "replica_task_done: "
+                        "failed to remove (%s) attribute from (%s) entry; "
+                        "LDAP error - %d\n",
+                        TASK_ATTR, replica_dn, rc);   
+    }
+
+    slapi_pblock_destroy (pb);
+    slapi_ch_free_string(&replica_dn);
+
+    return rc;
+}
+
 static int replica_execute_cl2ldif_task (Object *r, char *returntext)
 {
     int rc;
@@ -693,7 +914,8 @@ static int replica_execute_cl2ldif_task (Object *r, char *returntext)
         PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "changelog is not open");
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
                         "replica_execute_cl2ldif_task: %s\n", returntext);        
-        return LDAP_OPERATIONS_ERROR;
+        rc = LDAP_OPERATIONS_ERROR;    
+        goto bail;
     }
 
     rlist[0] = r;
@@ -702,25 +924,126 @@ static int replica_execute_cl2ldif_task (Object *r, char *returntext)
     /* file is stored in the changelog directory and is named
        <replica name>.ldif */
     clDir = cl5GetDir ();
-    PR_ASSERT (clDir);
+    if (NULL == clDir) {
+        rc = LDAP_OPERATIONS_ERROR;    
+        goto bail;
+    }
 
     replica = (Replica*)object_get_data (r);
-    PR_ASSERT (replica);
+    if (NULL == replica) {
+        rc = LDAP_OPERATIONS_ERROR;    
+        goto bail;
+    }
 
     PR_snprintf (fName, MAXPATHLEN, "%s/%s.ldif", clDir, replica_get_name (replica));
     slapi_ch_free ((void**)&clDir);
 
+    slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+                    "Beginning changelog export of replica \"%s\"\n",
+                    replica_get_name(replica));
     rc = cl5ExportLDIF (fName, rlist);
-    if (rc != CL5_SUCCESS)
+    if (rc == CL5_SUCCESS) {
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+                        "Finished changelog export of replica \"%s\"\n",
+                        replica_get_name(replica));
+        rc = LDAP_SUCCESS;
+    } else {
+        PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+                     "Failed changelog export replica %s; "
+                     "changelog error - %d", replica_get_name(replica), rc);
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+                        "replica_execute_cl2ldif_task: %s\n", returntext);
+        rc = LDAP_OPERATIONS_ERROR;    
+    }
+bail:
+    return rc;
+}
+
+static int replica_execute_ldif2cl_task (Object *r, char *returntext)
+{
+    int rc, imprc = 0;
+    Object *rlist [2];
+    Replica *replica;
+    char fName [MAXPATHLEN];
+    char *clDir;
+    changelog5Config config;
+
+    if (cl5GetState () != CL5_STATE_OPEN)
     {
-        PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "failed to export changelog data to file %s; "
-                 "changelog error - %d", fName, rc);
+        PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "changelog is not open");
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
-                        "replica_execute_cl2ldif_task: %s\n", returntext);        
-        return LDAP_OPERATIONS_ERROR;    
+                        "replica_execute_ldif2cl_task: %s\n", returntext);        
+        rc = LDAP_OPERATIONS_ERROR;
+        goto bail;
     }
 
-    return LDAP_SUCCESS;
+    rlist[0] = r;
+    rlist[1] = NULL;
+
+    /* file is stored in the changelog directory and is named
+       <replica name>.ldif */
+    clDir = cl5GetDir ();
+    if (NULL == clDir) {
+        rc = LDAP_OPERATIONS_ERROR;    
+        goto bail;
+    }
+
+    replica = (Replica*)object_get_data (r);
+    if (NULL == replica) {
+        rc = LDAP_OPERATIONS_ERROR;    
+        goto bail;
+    }
+
+    PR_snprintf (fName, MAXPATHLEN, "%s/%s.ldif", clDir, replica_get_name (replica));
+
+    rc = cl5Close();
+    if (rc != CL5_SUCCESS)
+    {
+        PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+                     "failed to close changelog to import changelog data; "
+                     "changelog error - %d", rc);
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+                        "replica_execute_ldif2cl_task: %s\n", returntext);
+        rc = LDAP_OPERATIONS_ERROR;
+        goto bail;
+    }
+    slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+                    "Beginning changelog import of replica \"%s\"\n",
+                    replica_get_name(replica));
+    imprc = cl5ImportLDIF (clDir, fName, rlist);
+    slapi_ch_free ((void**)&clDir);
+    if (CL5_SUCCESS == imprc)
+    {
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+                        "Finished changelog import of replica \"%s\"\n",
+                        replica_get_name(replica));
+    }
+	else
+    {
+        PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+                     "Failed changelog import replica %s; "
+                     "changelog error - %d", replica_get_name(replica), rc);
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+                        "replica_execute_ldif2cl_task: %s\n", returntext);
+        imprc = LDAP_OPERATIONS_ERROR;
+    }
+    changelog5_read_config (&config);
+    /* restart changelog */
+    rc = cl5Open (config.dir, &config.dbconfig);
+    if (CL5_SUCCESS == rc)
+    {
+        rc = LDAP_SUCCESS;
+    }
+    else
+    {
+        slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, 
+            "replica_execute_ldif2cl_task: failed to start changelog at %s\n",
+            config.dir);
+        rc = LDAP_OPERATIONS_ERROR;    
+    }
+bail:
+    /* if cl5ImportLDIF returned an error, report it first. */
+    return imprc?imprc:rc;
 }
 
 static multimaster_mtnode_extension * 
@@ -739,7 +1062,7 @@ _replica_config_get_mtnode_ext (const Slapi_Entry *e)
         slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: "
                         "configuration entry %s missing %s attribute\n",
                         escape_string(slapi_entry_get_dn((Slapi_Entry *)e), ebuf),
-						attr_replicaRoot);   
+                        attr_replicaRoot);   
         return NULL;
     }
 
@@ -756,7 +1079,7 @@ _replica_config_get_mtnode_ext (const Slapi_Entry *e)
     else
     {
         /* check if replica object already exists for the specified subtree */
-	    ext = (multimaster_mtnode_extension *)repl_con_get_ext (REPL_CON_EXT_MTNODE, mtnode);    
+        ext = (multimaster_mtnode_extension *)repl_con_get_ext (REPL_CON_EXT_MTNODE, mtnode);    
     }
     
     slapi_sdn_free (&sdn);
diff --git a/ldap/servers/plugins/replication/repl5_ruv.c b/ldap/servers/plugins/replication/repl5_ruv.c
index 02f9c1b..4a55d0b 100644
--- a/ldap/servers/plugins/replication/repl5_ruv.c
+++ b/ldap/servers/plugins/replication/repl5_ruv.c
@@ -1715,9 +1715,12 @@ get_ruvelement_from_berval(const struct berval *bval)
 		}
 		else
 		{
-			if (bval->bv_len - mincsnbegin != (_CSN_VALIDCSN_STRLEN * 2) + 1)
+			if ((bval->bv_len - mincsnbegin != (_CSN_VALIDCSN_STRLEN * 2) + 1)
+			 && (bval->bv_len - mincsnbegin != (_CSN_VALIDCSN_STRLEN * 2) + 10))
 			{
-				/* Malformed - incorrect length for 2 CSNs + space */
+				/* Malformed - incorrect length for 2 CSNs + space AND
+				 *             incorrect length for 2 CSNs + 2 spaces +
+				 *                              last_modified (see ruv_dump) */
 				goto loser;
 			}
 			else
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
index d9da346..91a6023 100644
--- a/ldap/servers/slapd/slapi-private.h
+++ b/ldap/servers/slapd/slapi-private.h
@@ -182,6 +182,7 @@ CSN *csn_new();
 CSN *csn_new_by_string(const char *s);
 void csn_init_by_csn(CSN *csn1,const CSN *csn2);
 void csn_init_by_string(CSN *csn, const char *s);
+void csn_init(CSN *csn);
 CSN *csn_dup(const CSN *csn);
 void csn_free(CSN **csn);
 void csn_set_replicaid(CSN *csn, ReplicaId rid);




More information about the 389-commits mailing list