Browse Source

Bug 182507 - clear-password mod from replica is discarded before changelogged

https://bugzilla.redhat.com/show_bug.cgi?id=182507

Description:
Replication drops unhashed passwords which is necessary for
the AD password sync.  This patch allows the passwords replicated
and introduces a method to encrypt logs in the changelog.

See also http://directory.fedoraproject.org/wiki/Changelog_Encryption
Noriko Hosoi 15 years ago
parent
commit
7aef407a3d

+ 1 - 0
Makefile.am

@@ -991,6 +991,7 @@ libreplication_plugin_la_SOURCES = ldap/servers/plugins/replication/cl5_api.c \
 	ldap/servers/plugins/replication/cl5_clcache.c \
 	ldap/servers/plugins/replication/cl5_config.c \
 	ldap/servers/plugins/replication/cl5_init.c \
+	ldap/servers/plugins/replication/cl_crypt.c \
 	ldap/servers/plugins/replication/csnpl.c \
 	ldap/servers/plugins/replication/legacy_consumer.c \
 	ldap/servers/plugins/replication/llist.c \

+ 15 - 0
Makefile.in

@@ -483,6 +483,7 @@ am_libreplication_plugin_la_OBJECTS = ldap/servers/plugins/replication/libreplic
 	ldap/servers/plugins/replication/libreplication_plugin_la-cl5_clcache.lo \
 	ldap/servers/plugins/replication/libreplication_plugin_la-cl5_config.lo \
 	ldap/servers/plugins/replication/libreplication_plugin_la-cl5_init.lo \
+	ldap/servers/plugins/replication/libreplication_plugin_la-cl_crypt.lo \
 	ldap/servers/plugins/replication/libreplication_plugin_la-csnpl.lo \
 	ldap/servers/plugins/replication/libreplication_plugin_la-legacy_consumer.lo \
 	ldap/servers/plugins/replication/libreplication_plugin_la-llist.lo \
@@ -2101,6 +2102,7 @@ libreplication_plugin_la_SOURCES = ldap/servers/plugins/replication/cl5_api.c \
 	ldap/servers/plugins/replication/cl5_clcache.c \
 	ldap/servers/plugins/replication/cl5_config.c \
 	ldap/servers/plugins/replication/cl5_init.c \
+	ldap/servers/plugins/replication/cl_crypt.c \
 	ldap/servers/plugins/replication/csnpl.c \
 	ldap/servers/plugins/replication/legacy_consumer.c \
 	ldap/servers/plugins/replication/llist.c \
@@ -3463,6 +3465,9 @@ ldap/servers/plugins/replication/libreplication_plugin_la-cl5_config.lo:  \
 ldap/servers/plugins/replication/libreplication_plugin_la-cl5_init.lo:  \
 	ldap/servers/plugins/replication/$(am__dirstamp) \
 	ldap/servers/plugins/replication/$(DEPDIR)/$(am__dirstamp)
+ldap/servers/plugins/replication/libreplication_plugin_la-cl_crypt.lo:  \
+	ldap/servers/plugins/replication/$(am__dirstamp) \
+	ldap/servers/plugins/replication/$(DEPDIR)/$(am__dirstamp)
 ldap/servers/plugins/replication/libreplication_plugin_la-csnpl.lo:  \
 	ldap/servers/plugins/replication/$(am__dirstamp) \
 	ldap/servers/plugins/replication/$(DEPDIR)/$(am__dirstamp)
@@ -4763,6 +4768,8 @@ mostlyclean-compile:
 	-rm -f ldap/servers/plugins/replication/libreplication_plugin_la-cl5_config.lo
 	-rm -f ldap/servers/plugins/replication/libreplication_plugin_la-cl5_init.$(OBJEXT)
 	-rm -f ldap/servers/plugins/replication/libreplication_plugin_la-cl5_init.lo
+	-rm -f ldap/servers/plugins/replication/libreplication_plugin_la-cl_crypt.$(OBJEXT)
+	-rm -f ldap/servers/plugins/replication/libreplication_plugin_la-cl_crypt.lo
 	-rm -f ldap/servers/plugins/replication/libreplication_plugin_la-csnpl.$(OBJEXT)
 	-rm -f ldap/servers/plugins/replication/libreplication_plugin_la-csnpl.lo
 	-rm -f ldap/servers/plugins/replication/libreplication_plugin_la-legacy_consumer.$(OBJEXT)
@@ -5519,6 +5526,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-cl5_clcache.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-cl5_config.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-cl5_init.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-cl_crypt.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-csnpl.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-legacy_consumer.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-llist.Plo@am__quote@
@@ -7191,6 +7199,13 @@ ldap/servers/plugins/replication/libreplication_plugin_la-cl5_init.lo: ldap/serv
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libreplication_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/plugins/replication/libreplication_plugin_la-cl5_init.lo `test -f 'ldap/servers/plugins/replication/cl5_init.c' || echo '$(srcdir)/'`ldap/servers/plugins/replication/cl5_init.c
 
+ldap/servers/plugins/replication/libreplication_plugin_la-cl_crypt.lo: ldap/servers/plugins/replication/cl_crypt.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libreplication_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/plugins/replication/libreplication_plugin_la-cl_crypt.lo -MD -MP -MF ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-cl_crypt.Tpo -c -o ldap/servers/plugins/replication/libreplication_plugin_la-cl_crypt.lo `test -f 'ldap/servers/plugins/replication/cl_crypt.c' || echo '$(srcdir)/'`ldap/servers/plugins/replication/cl_crypt.c
+@am__fastdepCC_TRUE@	$(am__mv) ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-cl_crypt.Tpo ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-cl_crypt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='ldap/servers/plugins/replication/cl_crypt.c' object='ldap/servers/plugins/replication/libreplication_plugin_la-cl_crypt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libreplication_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/plugins/replication/libreplication_plugin_la-cl_crypt.lo `test -f 'ldap/servers/plugins/replication/cl_crypt.c' || echo '$(srcdir)/'`ldap/servers/plugins/replication/cl_crypt.c
+
 ldap/servers/plugins/replication/libreplication_plugin_la-csnpl.lo: ldap/servers/plugins/replication/csnpl.c
 @am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libreplication_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/plugins/replication/libreplication_plugin_la-csnpl.lo -MD -MP -MF ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-csnpl.Tpo -c -o ldap/servers/plugins/replication/libreplication_plugin_la-csnpl.lo `test -f 'ldap/servers/plugins/replication/csnpl.c' || echo '$(srcdir)/'`ldap/servers/plugins/replication/csnpl.c
 @am__fastdepCC_TRUE@	$(am__mv) ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-csnpl.Tpo ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-csnpl.Plo

+ 1 - 0
ldap/servers/plugins/replication/cl5.h

@@ -55,6 +55,7 @@ typedef struct changelog5Config
 	int	 maxEntries;
 /* the changelog DB configuration parameters are defined as CL5DBConfig in cl5_api.h */
 	CL5DBConfig dbconfig;	
+	char *symmetricKey;
 }changelog5Config;
 
 /* initializes changelog*/

+ 96 - 11
ldap/servers/plugins/replication/cl5_api.c

@@ -57,6 +57,7 @@
 
 
 #include "cl5_api.h"
+#include "cl_crypt.h"
 #include "plhash.h" 
 #include "plstr.h"
 
@@ -249,6 +250,7 @@ typedef struct cl5desc
 							   deadlock detection, etc. */
 	PRLock		*clLock;	/* Lock associated to clVar, used to notify threads on close */
 	PRCondVar	*clCvar;	/* Condition Variable used to notify threads on close */
+	void        *clcrypt_handle; /* for cl encryption */
 } CL5Desc;
 
 typedef void (*VFP)(void *);
@@ -513,9 +515,12 @@ int cl5Open (const char *dir, const CL5DBConfig *config)
 	{
 		s_cl5Desc.dbState = CL5_STATE_OPEN;	
 		clcache_set_config();
+
+		/* Set the cl encryption algorithm (if configured) */
+		rc = clcrypt_init(config, &s_cl5Desc.clcrypt_handle);
 	}
 
-done:;	
+done:
 	PR_RWLock_Unlock (s_cl5Desc.stLock);
 
 	return rc;
@@ -1830,7 +1835,7 @@ static int _cl5AppInit (PRBool *didRecovery)
 	{
 		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
 				"_cl5AppInit: failed to fetch backend dbenv (%p) and/or "
-				"index page size (%ld)\n", dbEnv, pagesize);
+				"index page size (%u)\n", dbEnv, pagesize);
 		return CL5_DB_ERROR;
 	}
 }
@@ -1960,11 +1965,21 @@ static int _cl5Entry2DBData (const CL5Entry *entry, char **data, PRUint32 *len)
 											size ++; /* we just store NULL char */
 										slapi_entry2mods (op->p.p_add.target_entry, &rawDN/* dn */, &add_mods);										
 										size += strlen (rawDN) + 1;
-										size += _cl5GetModsSize (add_mods);
+										/* Need larger buffer for the encrypted changelog */
+										if (s_cl5Desc.clcrypt_handle) {
+											size += (_cl5GetModsSize (add_mods) * (1 + BACK_CRYPT_OUTBUFF_EXTLEN));
+										} else {
+											size += _cl5GetModsSize (add_mods);
+										}
 										break;
 
 		case SLAPI_OPERATION_MODIFY:	size += strlen (op->target_address.dn) + 1;
-										size += _cl5GetModsSize (op->p.p_modify.modify_mods);
+										/* Need larger buffer for the encrypted changelog */
+										if (s_cl5Desc.clcrypt_handle) {
+											size += (_cl5GetModsSize (op->p.p_modify.modify_mods) * (1 + BACK_CRYPT_OUTBUFF_EXTLEN));
+										} else {
+											size += _cl5GetModsSize (op->p.p_modify.modify_mods);
+										}
 										break;
 
 		case SLAPI_OPERATION_MODRDN:	size += strlen (op->target_address.dn) + 1;
@@ -1978,7 +1993,12 @@ static int _cl5Entry2DBData (const CL5Entry *entry, char **data, PRUint32 *len)
 											size += strlen (op->p.p_modrdn.modrdn_newsuperior_address.uniqueid) + 1;
 										else
 											size ++; /* for NULL char */
-										size += _cl5GetModsSize (op->p.p_modrdn.modrdn_mods);
+										/* Need larger buffer for the encrypted changelog */
+										if (s_cl5Desc.clcrypt_handle) {
+											size += (_cl5GetModsSize (op->p.p_modrdn.modrdn_mods) * (1 + BACK_CRYPT_OUTBUFF_EXTLEN));
+										} else {
+											size += _cl5GetModsSize (op->p.p_modrdn.modrdn_mods);
+										}
 										break;
 
 		case SLAPI_OPERATION_DELETE:	size += strlen (op->target_address.dn) + 1;
@@ -2038,8 +2058,16 @@ static int _cl5Entry2DBData (const CL5Entry *entry, char **data, PRUint32 *len)
 										break;
 	}
 	
-	(*len) = size;
-	
+	/* (*len) != size in case encrypted */
+	(*len) = pos - *data;
+
+	if (*len > size) {
+		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
+						"_cl5Entry2DBData: real len %d > estimated size %d\n",
+						*len, size);
+		return CL5_MEMORY_ERROR;
+	}
+
     return CL5_SUCCESS;
 }
 
@@ -2274,7 +2302,10 @@ static void _cl5WriteMod (LDAPMod *mod, char **buff)
 	char *pos;
 	PRInt32 count;
 	struct berval *bv;
+	struct berval *encbv;
+	struct berval *bv_to_use;
 	Slapi_Mod smod;
+	int rc = 0;
 
 	slapi_mod_init_byref(&smod, mod);
 
@@ -2293,7 +2324,26 @@ static void _cl5WriteMod (LDAPMod *mod, char **buff)
 	bv = slapi_mod_get_first_value (&smod);
 	while (bv)
 	{
-        _cl5WriteBerval (bv, &pos);
+		encbv = NULL;
+		rc = 0;
+		rc = clcrypt_encrypt_value(s_cl5Desc.clcrypt_handle, 
+		                           bv, &encbv);
+		if (rc > 0) {
+			/* no encryption needed. use the original bv */
+			bv_to_use = bv;
+		} else if ((0 == rc) && encbv) {
+			/* successfully encrypted. use the encrypted bv */
+			bv_to_use = encbv;
+		} else { /* failed */
+			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
+						"_cl5WriteMod: encrypting \"%s: %s\" failed\n",
+						slapi_mod_get_type(&smod), bv->bv_val);
+			bv_to_use = NULL;
+		}
+		if (bv_to_use) {
+			_cl5WriteBerval (bv_to_use, &pos);
+		}
+		slapi_ch_bvfree(&encbv);
 		bv = slapi_mod_get_next_value (&smod);
 	}
 
@@ -2358,6 +2408,9 @@ static int _cl5ReadMod (Slapi_Mod *smod, char **buff)
 	char *type;
 	int op;
 	struct berval bv;
+	struct berval *decbv;
+	struct berval *bv_to_use;
+	int rc = 0;
 
 	op = (*pos) & 0x000000FF;
 	pos ++;
@@ -2373,11 +2426,43 @@ static int _cl5ReadMod (Slapi_Mod *smod, char **buff)
 	slapi_mod_set_operation (smod, op|LDAP_MOD_BVALUES); 
 	slapi_mod_set_type (smod, type);
 	slapi_ch_free ((void**)&type);
-								
+
 	for (i = 0; i < val_count; i++)
 	{
-        _cl5ReadBerval (&bv, &pos);
-		slapi_mod_add_value (smod, &bv);
+		_cl5ReadBerval (&bv, &pos);
+		decbv = NULL;
+		rc = 0;
+		rc = clcrypt_decrypt_value(s_cl5Desc.clcrypt_handle,
+		                           &bv, &decbv);
+		if (rc > 0) {
+			/* not encrypted. use the original bv */
+			bv_to_use = &bv;
+		} else if ((0 == rc) && decbv) {
+			/* successfully decrypted. use the decrypted bv */
+			bv_to_use = decbv;
+		} else { /* failed */
+			char encstr[128];
+			char *encend = encstr + 128;
+			char *ptr;
+			int i;
+			for (i = 0, ptr = encstr; (i < bv.bv_len) && (ptr < encend - 4);
+				 i++, ptr += 3) {
+				sprintf(ptr, "%x", 0xff & bv.bv_val[i]);
+			}
+			if (ptr >= encend - 4) {
+				sprintf(ptr, "...");
+				ptr += 3;
+			}
+			*ptr = '\0';
+			slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, 
+						"_cl5ReadMod: decrypting \"%s: %s\" failed\n",
+						slapi_mod_get_type(smod), encstr);
+			bv_to_use = NULL;
+		}
+		if (bv_to_use) {
+			slapi_mod_add_value (smod, bv_to_use);
+		}
+		slapi_ch_bvfree(&decbv);
 		slapi_ch_free((void **) &bv.bv_val);
 	}
 

+ 2 - 0
ldap/servers/plugins/replication/cl5_api.h

@@ -70,6 +70,8 @@ typedef struct cl5dbconfig
 	size_t	pageSize;			/* page size in bytes */
 	PRInt32	fileMode;			/* file mode */
 	PRUint32 maxConcurrentWrites;	/* max number of concurrent cl writes */
+	char *encryptionAlgorithm;	/* nsslapd-encryptionalgorithm */
+	char *symmetricKey;
 } CL5DBConfig;
 
 /* changelog entry format */

+ 36 - 1
ldap/servers/plugins/replication/cl5_config.c

@@ -389,6 +389,14 @@ changelog5_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entr
 				{
 					slapi_ch_free_string(&config.maxAge);
                     config.maxAge = slapi_ch_strdup(config_attr_value);
+                }
+                else if ( strcasecmp ( config_attr, CONFIG_CHANGELOG_SYMMETRIC_KEY ) == 0 )
+                {
+                    slapi_ch_free_string(&config.symmetricKey);
+                    config.symmetricKey = slapi_ch_strdup(config_attr_value);
+                    /* Storing the encryption symmetric key */
+                    /* no need to change any changelog configuration */
+                    goto done;
                 }
 				else 
 				{
@@ -720,7 +728,6 @@ static void changelog5_extract_config(Slapi_Entry* entry, changelog5Config *conf
 
 	/* 
 	 * Read the Changelog Internal Configuration Parameters for the Changelog DB
-	 * (db cache size, db settings...)
 	 */
 	arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_MAX_CONCURRENT_WRITES);
 	if (arg)
@@ -732,6 +739,34 @@ static void changelog5_extract_config(Slapi_Entry* entry, changelog5Config *conf
 	{
 		config->dbconfig.maxConcurrentWrites = CL5_DEFAULT_CONFIG_MAX_CONCURRENT_WRITES;
 	}
+
+	/* 
+	 * changelog encryption
+	 */
+	arg = slapi_entry_attr_get_charptr(entry,
+	                                   CONFIG_CHANGELOG_ENCRYPTION_ALGORITHM);
+	if (arg)
+	{
+		config->dbconfig.encryptionAlgorithm = slapi_ch_strdup(arg);
+		slapi_ch_free_string(&arg);
+	}
+	else
+	{
+		config->dbconfig.encryptionAlgorithm = NULL; /* no encryption */
+	}
+	/* 
+	 * symmetric key
+	 */
+	arg = slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_SYMMETRIC_KEY);
+	if (arg)
+	{
+		config->dbconfig.symmetricKey = slapi_ch_strdup(arg);
+		slapi_ch_free_string(&arg);
+	}
+	else
+	{
+		config->dbconfig.symmetricKey = NULL; /* no symmetric key */
+	}
 }
 
 static void replace_bslash (char *dir)

+ 203 - 0
ldap/servers/plugins/replication/cl_crypt.c

@@ -0,0 +1,203 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ * 
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ * 
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception. 
+ * 
+ * 
+ * Copyright (C) 2010 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+/* cl_crypt.c - handles changelog encryption. */
+
+#include <errno.h>
+#include <sys/stat.h>
+#if defined( OS_solaris ) || defined( hpux )
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#endif
+#if defined( linux )
+#include <sys/vfs.h>
+#endif
+
+#include "slapi-plugin.h"
+#include "cl5_api.h"
+#include "cl_crypt.h"
+
+/*
+ * BACK_INFO_CRYPT_INIT
+ */
+int
+clcrypt_init(const CL5DBConfig *config, void **clcrypt_handle)
+{
+    int rc = 0;
+    char *cookie = NULL;
+    Slapi_Backend *be = NULL;
+    back_info_crypt_init crypt_init = {0};
+
+    slapi_log_error(SLAPI_LOG_TRACE, repl_plugin_name, "-> clcrypt_init\n");
+    /* Encryption is not specified */
+    if (!config->encryptionAlgorithm || !clcrypt_handle) {
+        goto bail;
+    }
+    crypt_init.dn = "cn=changelog5,cn=config";
+    crypt_init.encryptionAlgorithm = config->encryptionAlgorithm;
+
+    be = slapi_get_first_backend(&cookie);
+    while (be) {
+        crypt_init.be = be;
+        rc = slapi_back_ctrl_info(be, BACK_INFO_CRYPT_INIT,
+                                  (void *)&crypt_init);
+        if (LDAP_SUCCESS == rc) {
+            break; /* Successfully fetched */
+        }
+        be = slapi_get_next_backend(cookie);
+    }
+    slapi_ch_free((void **)&cookie);
+
+    if (LDAP_SUCCESS == rc && crypt_init.state_priv) {
+        *clcrypt_handle = crypt_init.state_priv;
+        rc = 0;
+    } else {
+        rc = 1;
+    }
+bail:
+    slapi_log_error(SLAPI_LOG_TRACE, repl_plugin_name,
+                    "<- clcrypt_init : %d\n", rc);
+    return rc;
+}
+
+/*
+ * return values:  0 - success
+ *              :  1 - no encryption
+ *              : -1 - error 
+ *
+ * output value: out: non-NULL - encryption successful
+ *                  :     NULL - no encryption or failure
+ */
+int
+clcrypt_encrypt_value(void *clcrypt_handle,
+                      struct berval *in, struct berval **out)
+{
+    int rc = -1;
+    char *cookie = NULL;
+    Slapi_Backend *be = NULL;
+    back_info_crypt_value crypt_value = {0};
+
+    slapi_log_error(SLAPI_LOG_TRACE, repl_plugin_name, 
+                    "-> clcrypt_encrypt_value\n");
+    if (NULL == out) {
+        goto bail;
+    }
+    *out = NULL;
+    if (NULL == clcrypt_handle) {
+        rc = 1;
+        goto bail;
+    }
+    crypt_value.state_priv = clcrypt_handle;
+    crypt_value.in = in;
+
+    be = slapi_get_first_backend(&cookie);
+    while (be) {
+        rc = slapi_back_ctrl_info(be, BACK_INFO_CRYPT_ENCRYPT_VALUE,
+                                  (void *)&crypt_value);
+        if (LDAP_SUCCESS == rc) {
+            break; /* Successfully fetched */
+        }
+        be = slapi_get_next_backend(cookie);
+    }
+    slapi_ch_free((void **)&cookie);
+    if (LDAP_SUCCESS == rc && crypt_value.out) {
+        *out = crypt_value.out;
+        rc = 0;
+    } else {
+        rc = -1;
+    }
+bail:
+    slapi_log_error(SLAPI_LOG_TRACE, repl_plugin_name, 
+                    "<- clcrypt_encrypt_entry (returning %d)\n", rc);
+    return rc;
+}
+
+/*
+ * return values:  0 - success
+ *              :  1 - no encryption
+ *              : -1 - error 
+ *
+ * output value: out: non-NULL - encryption successful
+ *                  :     NULL - no encryption or failure
+ */
+int 
+clcrypt_decrypt_value(void *clcrypt_handle,
+                      struct berval *in, struct berval **out)
+{
+    int rc = -1;
+    char *cookie = NULL;
+    Slapi_Backend *be = NULL;
+    back_info_crypt_value crypt_value = {0};
+
+    slapi_log_error(SLAPI_LOG_TRACE, repl_plugin_name, 
+                    "-> clcrypt_decrypt_value\n");
+    if (NULL == out) {
+        goto bail;
+    }
+    *out = NULL;
+    if (NULL == clcrypt_handle) {
+        rc = 1;
+        goto bail;
+    }
+    crypt_value.state_priv = clcrypt_handle;
+    crypt_value.in = in;
+
+    be = slapi_get_first_backend(&cookie);
+    while (be) {
+        rc = slapi_back_ctrl_info(be, BACK_INFO_CRYPT_DECRYPT_VALUE,
+                                  (void *)&crypt_value);
+        if (LDAP_SUCCESS == rc) {
+            break; /* Successfully fetched */
+        }
+        be = slapi_get_next_backend(cookie);
+    }
+    slapi_ch_free((void **)&cookie);
+    if (LDAP_SUCCESS == rc && crypt_value.out) {
+        *out = crypt_value.out;
+        rc = 0;
+    } else {
+        rc = -1;
+    }
+bail:
+    slapi_log_error(SLAPI_LOG_TRACE, repl_plugin_name, 
+                    "<- clcrypt_decrypt_entry (returning %d)\n", rc);
+    return rc;
+}

+ 53 - 0
ldap/servers/plugins/replication/cl_crypt.h

@@ -0,0 +1,53 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ * 
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ * 
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception. 
+ * 
+ * 
+ * Copyright (C) 2010/ Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifndef _CLCRYPT_H_
+#define _CLCRYPT_H_
+
+#include "pk11func.h"
+#include "keyhi.h"
+#include "nss.h"
+#include "cert.h"
+
+int clcrypt_init(const CL5DBConfig *config, void **clcrypt_handle);
+int clcrypt_encrypt_value(void *clcrypt_handle, struct berval *in, struct berval **out);
+int clcrypt_decrypt_value(void *state_priv, struct berval *in, struct berval **out);
+#endif /* _CLCRYPT_H_ */

+ 2 - 15
ldap/servers/plugins/replication/repl_shared.h

@@ -62,23 +62,10 @@
 #define CONFIG_CHANGELOG_DIR_ATTRIBUTE		"nsslapd-changelogdir"
 #define CONFIG_CHANGELOG_MAXENTRIES_ATTRIBUTE	"nsslapd-changelogmaxentries"
 #define CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE	"nsslapd-changelogmaxage"
-/* Changelog Internal Configuration Parameters -> DB related */
-#define CONFIG_CHANGELOG_DB_DBCACHESIZE			"nsslapd-dbcachesize"
-#define CONFIG_CHANGELOG_DB_DURABLE_TRANSACTIONS	"nsslapd-db-durable-transaction"
-#define CONFIG_CHANGELOG_DB_CHECKPOINT_INTERVAL		"nsslapd-db-checkpoint-interval"
-#define CONFIG_CHANGELOG_DB_CIRCULAR_LOGGING		"nsslapd-db-circular-logging"
-#define CONFIG_CHANGELOG_DB_PAGE_SIZE			"nsslapd-db-page-size"
-#define CONFIG_CHANGELOG_DB_LOGFILE_SIZE		"nsslapd-db-logfile-size"
-#define CONFIG_CHANGELOG_DB_MAXTXN_SIZE			"nsslapd-db-max-txn"
-#define CONFIG_CHANGELOG_DB_VERBOSE			"nsslapd-db-verbose"
-#define CONFIG_CHANGELOG_DB_DEBUG			"nsslapd-db-debug"
-#define CONFIG_CHANGELOG_DB_TRICKLE_PERCENTAGE		"nsslapd-db-trickle-percentage"
-#define CONFIG_CHANGELOG_DB_SPINCOUNT			"nsslapd-db-spin-count"
 /* Changelog Internal Configuration Parameters -> Changelog Cache related */
-#define CONFIG_CHANGELOG_CACHESIZE			"nsslapd-cachesize"
-#define CONFIG_CHANGELOG_CACHEMEMSIZE			"nsslapd-cachememsize"
-#define CONFIG_CHANGELOG_NB_LOCK	"nsslapd-db-locks"
 #define CONFIG_CHANGELOG_MAX_CONCURRENT_WRITES	"nsslapd-changelogmaxconcurrentwrites"
+#define CONFIG_CHANGELOG_ENCRYPTION_ALGORITHM	"nsslapd-encryptionalgorithm"
+#define CONFIG_CHANGELOG_SYMMETRIC_KEY	"nsSymmetricKey"
 
 #define	T_CHANGETYPESTR		"changetype"
 #define	T_CHANGETYPE		1

+ 1 - 1
ldap/servers/plugins/replication/windows_protocol_util.c

@@ -4608,7 +4608,7 @@ windows_search_local_entry_by_uniqueid(Private_Repl_Protocol *prp, const char *u
 		PR_smprintf_free(filter_string);
 	}
 
-    if (is_global) slapi_sdn_free(&local_subtree);
+    if (is_global) slapi_sdn_free((Slapi_DN **)&local_subtree);
     return rc;
 }
 

+ 40 - 2
ldap/servers/slapd/back-ldbm/dblayer.c

@@ -924,7 +924,7 @@ void dblayer_sys_pages(size_t *pagesize, size_t *pages, size_t *procpages, size_
                 if (feof(f))
                     break;
                 if (strncmp(s, "VmSize:", 7) == 0) {
-                    sscanf(s+7, "%lu", procpages);
+                    sscanf(s+7, "%u", procpages);
                     break;
                 }
             }
@@ -4213,7 +4213,7 @@ static int commit_good_database(dblayer_private *priv)
             filename, PR_GetError(), slapd_pr_strerror(PR_GetError()) );
         return -1;
     } 
-    PR_snprintf(line,sizeof(line),"cachesize:%lu\nncache:%d\nversion:%d\n",
+    PR_snprintf(line,sizeof(line),"cachesize:%u\nncache:%d\nversion:%d\n",
             priv->dblayer_cachesize, priv->dblayer_ncache, DB_VERSION_MAJOR);
     num_bytes = strlen(line);
     return_value = slapi_write_buffer(prfd, line, num_bytes);
@@ -6544,3 +6544,41 @@ ldbm_back_set_info(Slapi_Backend *be, int cmd, void *info)
 
     return rc;
 }
+
+int
+ldbm_back_ctrl_info(Slapi_Backend *be, int cmd, void *info)
+{
+    int rc = -1;
+    if (!be || !info) {
+        return rc;
+    }
+
+    switch (cmd) {
+    case BACK_INFO_CRYPT_INIT:
+    {
+        back_info_crypt_init *crypt_init = (back_info_crypt_init *)info;
+        rc = back_crypt_init(crypt_init->be, crypt_init->dn,
+                             crypt_init->encryptionAlgorithm, 
+                             &(crypt_init->state_priv));
+        break;
+    }
+    case BACK_INFO_CRYPT_ENCRYPT_VALUE:
+    {
+        back_info_crypt_value *crypt_value = (back_info_crypt_value *)info;
+        rc = back_crypt_encrypt_value(crypt_value->state_priv, crypt_value->in, 
+                                      &(crypt_value->out));
+        break;
+    }
+    case BACK_INFO_CRYPT_DECRYPT_VALUE:
+    {
+        back_info_crypt_value *crypt_value = (back_info_crypt_value *)info;
+        rc = back_crypt_decrypt_value(crypt_value->state_priv, crypt_value->in, 
+                                      &(crypt_value->out));
+        break;
+    }
+    default:
+        break;
+    }
+
+    return rc;
+}

+ 14 - 6
ldap/servers/slapd/back-ldbm/id2entry.c

@@ -46,6 +46,10 @@
 
 #define ID2ENTRY "id2entry"
 
+static char *protected_attrs_all [] = {PSEUDO_ATTR_UNHASHEDUSERPASSWORD,
+                                       LDBM_ENTRYDN_STR,
+                                       NULL};
+
 /* 
  * The caller MUST check for DB_LOCK_DEADLOCK and DB_RUNRECOVERY returned
  */
@@ -60,6 +64,7 @@ id2entry_add_ext( backend *be, struct backentry *e, back_txn *txn, int encrypt
     int    len, rc;
     char   temp_id[sizeof(ID)];
     struct backentry *encrypted_entry = NULL;
+    char **paap = NULL;
     char *entrydn = NULL;
 
     LDAPDebug( LDAP_DEBUG_TRACE, "=> id2entry_add( %lu, \"%s\" )\n",
@@ -120,12 +125,15 @@ id2entry_add_ext( backend *be, struct backentry *e, back_txn *txn, int encrypt
             LDAPDebug2Args( LDAP_DEBUG_TRACE,
                    "=> id2entry_add (dncache) ( %lu, \"%s\" )\n",
                    (u_long)e->ep_id, slapi_entry_get_dn_const(entry_to_use) );
-            /* If entrydn exists in the entry, we have to remove it before
-             * writing the entry to the database. */
-            if (0 == slapi_entry_attr_find(entry_to_use,
-                                           LDBM_ENTRYDN_STR, &eattr)) {
-                /* entrydn exists in the entry.  let's removed it. */
-                slapi_entry_delete_values(entry_to_use, LDBM_ENTRYDN_STR, NULL);
+            /* 
+             * If protected attributes exist in the entry, 
+             * we have to remove them before writing the entry to the database.
+             */
+            for (paap = protected_attrs_all; paap && *paap; paap++) {
+                if (0 == slapi_entry_attr_find(entry_to_use, *paap, &eattr)) {
+                    /* a protected attr exists in the entry. removed it. */
+                    slapi_entry_delete_values(entry_to_use, *paap, NULL);
+                }
             }
         }
         data.dptr = slapi_entry2str_with_options(entry_to_use, &len, options);

+ 2 - 0
ldap/servers/slapd/back-ldbm/init.c

@@ -250,6 +250,8 @@ ldbm_back_init( Slapi_PBlock *pb )
 	    (void *) ldbm_back_get_info );
 	rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_SET_INFO_FN,
 	    (void *) ldbm_back_set_info );
+	rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_CTRL_INFO_FN,
+	    (void *) ldbm_back_ctrl_info );
 
 	if ( rc != 0 ) {
 		LDAPDebug( LDAP_DEBUG_ANY, "ldbm_back_init failed\n", 0, 0, 0 );

+ 667 - 151
ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c

@@ -31,7 +31,7 @@
  * exception. 
  * 
  * 
- * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2010 Red Hat, Inc.
  * All rights reserved.
  * END COPYRIGHT BLOCK **/
 
@@ -39,9 +39,8 @@
 #  include <config.h>
 #endif
 
-/* This file handles attribute encryption.
- */
-
+/* This file handles attribute encryption.  */
+/* #define DEBUG_ATTRCRYPT 1 */
 
 #include "back-ldbm.h"
 #include "attrcrypt.h"
@@ -54,6 +53,8 @@
  * Remember to free the private structures in the attrinfos, so avoid a leak.
  */
 
+#define ATTRCRYPT "attrcrypt"
+
 attrcrypt_cipher_entry attrcrypt_cipher_list[] = { {ATTRCRYPT_CIPHER_AES, "AES", CKM_AES_CBC_PAD, CKM_AES_CBC_PAD, CKM_AES_CBC_PAD, 128/8, 16} , 
 	{ATTRCRYPT_CIPHER_DES3 , "3DES" , CKM_DES3_CBC_PAD, CKM_DES3_CBC_PAD, CKM_DES3_CBC_PAD, 112/8, 8}, 
 	{0} };
@@ -76,8 +77,25 @@ struct _attrcrypt_state_private {
 	attrcrypt_cipher_state *acs_array[1];
 };
 
+/*
+ * Return 
+ */
+enum
+{
+    KEYMGMT_SUCCESS = 0,
+    KEYMGMT_ERR_NO_ENTRY,       /* Entry to store key does not exist */
+    KEYMGMT_ERR_NO_KEY_ATTR,    /* Entry has no key attribute */
+    KEYMGMT_ERR_NO_KEY_VALUE,   /* Empty key */
+    KEYMGMT_ERR_CANT_UNWRAP,    /* Key failed to unwrap */
+    KEYMGMT_ERR_OTHER           /* Other error */
+};
+
 static int attrcrypt_wrap_key(attrcrypt_cipher_state *acs, PK11SymKey *symmetric_key, SECKEYPublicKey *public_key, SECItem *wrapped_symmetric_key);
 static int attrcrypt_unwrap_key(attrcrypt_cipher_state *acs, SECKEYPrivateKey *private_key, SECItem *wrapped_symmetric_key, PK11SymKey **unwrapped_symmetric_key);
+static int _back_crypt_cleanup_private(attrcrypt_state_private **state_priv);
+static void _back_crypt_acs_list_add(attrcrypt_state_private **state_priv, attrcrypt_cipher_state *acs);
+static int _back_crypt_keymgmt_get_key(attrcrypt_cipher_state *acs, SECKEYPrivateKey *private_key, PK11SymKey **key_from_store, const char *dn_string);
+static int _back_crypt_crypto_op(attrcrypt_private *priv, attrcrypt_cipher_state *acs, char *in_data, size_t in_size, char **out_data, size_t *out_size, int encrypt, backend *be, struct attrinfo *ai /* just for debugging */);
 
 /*
  * Copied from front-end because it's private to plugins
@@ -141,10 +159,8 @@ static int
 attrcrypt_keymgmt_get_key(ldbm_instance *li, attrcrypt_cipher_state *acs, SECKEYPrivateKey *private_key, PK11SymKey **key_from_store)
 {
 	int ret = 0;
-	Slapi_Entry *entry = NULL;
 	char *dn_template = "cn=%s,cn=encrypted attribute keys,cn=%s,cn=%s,cn=plugins,cn=config";
 	char *instance_name =  li->inst_name;
-	Slapi_Attr *keyattr = NULL;
 	char *dn_string = NULL;
 	
 	LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_keymgmt_get_key\n", 0, 0, 0);
@@ -161,27 +177,8 @@ attrcrypt_keymgmt_get_key(ldbm_instance *li, attrcrypt_cipher_state *acs, SECKEY
 		ret = -1;
 		goto bail;
 	}
-	/* Fetch the entry */
-	getConfigEntry(dn_string, &entry);
-	/* Did we find the entry ? */
-	if (NULL != entry) {
-		SECItem key_to_unwrap = {0};
-		/* If so then look for the attribute that contains the key */
-		slapi_entry_attr_find(entry, KEY_ATTRIBUTE_NAME, &keyattr);
-		if (keyattr != NULL) {
-			Slapi_Value *v = NULL;
-			slapi_valueset_first_value( &keyattr->a_present_values, &v);
-			key_to_unwrap.len = slapi_value_get_length(v);
-			key_to_unwrap.data = (void*)slapi_value_get_string(v);
-    		}
-		/* Unwrap it */
-		ret = attrcrypt_unwrap_key(acs, private_key, &key_to_unwrap, key_from_store);
-		if (entry) {
-			freeConfigEntry(&entry);
-		}
-	} else {
-		ret = -2; /* Means: we didn't find the entry (which happens if the key has never been generated) */	
-	}
+	ret = _back_crypt_keymgmt_get_key(acs, private_key, key_from_store, 
+	                                  (const char *)dn_string);
 bail:
 	slapi_ch_free_string(&dn_string);
 	LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_keymgmt_get_key\n", 0, 0, 0);
@@ -402,34 +399,51 @@ attrcrypt_cipher_init(ldbm_instance *li, attrcrypt_cipher_entry *ace, SECKEYPriv
 	acs->ace = ace;
 	acs->cipher_display_name = ace->cipher_display_name;
 	if (NULL == acs->cipher_lock) {
-		LDAPDebug(LDAP_DEBUG_ANY,"Failed to create cipher lock in attrcrypt_cipher_init\n", 0, 0, 0);
+		slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+			"Failed to create cipher lock in attrcrypt_cipher_init\n");
 	}
 	acs->slot = slapd_pk11_GetInternalKeySlot();
 	if (NULL == acs->slot) {
-		LDAPDebug(LDAP_DEBUG_ANY,"Failed to create a slot for cipher %s in attrcrypt_cipher_entry\n", acs->cipher_display_name, 0, 0);
+		slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+			"Failed to create a slot for cipher %s in attrcrypt_cipher_entry\n",
+			acs->cipher_display_name);
 		goto error;
 	}
 	/* Try to get the symmetric key for this cipher */
 	ret = attrcrypt_keymgmt_get_key(li,acs,private_key,&symmetric_key);
-	if (ret) {
-		if (-2 == ret) {
-			LDAPDebug(LDAP_DEBUG_ANY,"No symmetric key found for cipher %s in backend %s, attempting to create one...\n", acs->cipher_display_name, li->inst_name, 0);
-			ret = attrcrypt_generate_key(acs,&symmetric_key);
+	if (KEYMGMT_ERR_NO_ENTRY == ret) {
+		slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+			"No symmetric key found for cipher %s in backend %s, "
+			"attempting to create one...\n",
+			acs->cipher_display_name, li->inst_name);
+		ret = attrcrypt_generate_key(acs,&symmetric_key);
+		if (ret) {
+			slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+				"Failed to generate key for %s in attrcrypt_cipher_init\n",
+				acs->cipher_display_name);
+		}
+		if (symmetric_key) {
+			ret = attrcrypt_keymgmt_store_key(li,acs,public_key,symmetric_key);
 			if (ret) {
-				LDAPDebug(LDAP_DEBUG_ANY,"Failed to generate key for %s in attrcrypt_cipher_init\n", acs->cipher_display_name, 0, 0);
+				slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+					"Failed to store key for cipher %s in "
+					"attrcrypt_cipher_init\n", acs->cipher_display_name);
+			} else {
+				slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+					"Key for cipher %s successfully generated and stored\n",
+					acs->cipher_display_name);
 			}
-			if (symmetric_key) {
-				ret = attrcrypt_keymgmt_store_key(li,acs,public_key,symmetric_key);
-				if (ret) {
-					LDAPDebug(LDAP_DEBUG_ANY,"Failed to store key for cipher %s in attrcrypt_cipher_init\n", acs->cipher_display_name, 0, 0);
-				} else {
-					LDAPDebug(LDAP_DEBUG_ANY,"Key for cipher %s successfully generated and stored\n", acs->cipher_display_name, 0, 0);
-				}
-			}
-			
-		}  else {
-			LDAPDebug(LDAP_DEBUG_ANY,"Failed to retrieve key for cipher %s in attrcrypt_cipher_init\n", acs->cipher_display_name, 0, 0);
 		}
+	} else if (KEYMGMT_ERR_CANT_UNWRAP == ret) {
+		slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+				"attrcrypt_cipher_init: symmetric key failed to unwrap "
+				"with the private key; Cert might have been renewed since "
+				"the key is wrapped.  To recover the encrypted contents, "
+				"keep the wrapped symmetric key value.\n");
+	} else if (ret) {
+		slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+			"Failed to retrieve key for cipher %s in attrcrypt_cipher_init "
+			"(%d)\n", acs->cipher_display_name, ret);
 	}
 	if (symmetric_key) {
 		/* we loaded the symmetric key, store it in the acs */
@@ -444,21 +458,7 @@ static void
 attrcrypt_acs_list_add(ldbm_instance *li,attrcrypt_cipher_state *acs)
 {
 	/* Realloc the existing list and add to the end */
-	attrcrypt_cipher_state **current = NULL;
-	size_t list_size = 0;
-	/* Is the list already there ? */
-	if (NULL == li->inst_attrcrypt_state_private) {
-		/* If not, add it */
-		li->inst_attrcrypt_state_private = (attrcrypt_state_private *) slapi_ch_calloc(sizeof(attrcrypt_cipher_state *), 2); /* 2 == The pointer and a NULL terminator */
-	} else {
-		/* Otherwise re-size it */
-		for (current = &(li->inst_attrcrypt_state_private->acs_array[0]); *current; current++) {
-			list_size++;
-		}
-		li->inst_attrcrypt_state_private = (attrcrypt_state_private *) slapi_ch_realloc((char*)li->inst_attrcrypt_state_private,sizeof(attrcrypt_cipher_state *) * (list_size + 2));
-		li->inst_attrcrypt_state_private->acs_array[list_size + 1] = NULL; 
-	}
-	li->inst_attrcrypt_state_private->acs_array[list_size] = acs;
+    _back_crypt_acs_list_add(&(li->inst_attrcrypt_state_private), acs);
 }
 
 int
@@ -495,7 +495,6 @@ attrcrypt_init(ldbm_instance *li)
 						attrcrypt_acs_list_add(li,acs);
 						LDAPDebug(LDAP_DEBUG_TRACE,"Initialized cipher %s in attrcrypt_init\n", ace->cipher_display_name, 0, 0);
 					}
-					
 				}
 			}
 			slapd_pk11_DestroyPublicKey(public_key);
@@ -548,16 +547,9 @@ attrcrypt_cleanup(attrcrypt_cipher_state *acs)
 int
 attrcrypt_cleanup_private(ldbm_instance *li)
 {
-	attrcrypt_cipher_state **current = NULL;
-
 	LDAPDebug(LDAP_DEBUG_TRACE, "-> attrcrypt_cleanup_private\n", 0, 0, 0);
 	if (li && li->inst_attrcrypt_state_private) {
-		for (current = &(li->inst_attrcrypt_state_private->acs_array[0]);
-			 *current; current++) {
-			attrcrypt_cleanup(*current);
-			slapi_ch_free((void **)current);
-		}
-		slapi_ch_free((void **)&li->inst_attrcrypt_state_private);
+        _back_crypt_cleanup_private(&(li->inst_attrcrypt_state_private));
 	}
 	LDAPDebug(LDAP_DEBUG_TRACE, "<- attrcrypt_cleanup_private\n", 0, 0, 0);
 	return 0;
@@ -609,14 +601,6 @@ static int
 attrcrypt_crypto_op(attrcrypt_private *priv, backend *be, struct attrinfo *ai, char *in_data, size_t in_size, char **out_data, size_t *out_size, int encrypt)
 {
 	int ret = -1;
-	SECStatus secret = 0;
-	PK11Context* sec_context = NULL;
-	SECItem iv_item = {0};
-	SECItem *security_parameter = NULL;
-	int output_buffer_length = 0;
-	int output_buffer_size1 = 0;
-	unsigned int output_buffer_size2 = 0;
-	unsigned char *output_buffer = NULL;
 	attrcrypt_cipher_state *acs = NULL;
 
 	LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op\n", 0, 0, 0);
@@ -632,80 +616,8 @@ attrcrypt_crypto_op(attrcrypt_private *priv, backend *be, struct attrinfo *ai, c
 		log_bytes("attrcrypt_crypto_op decrypt '%s' (%d)\n", (unsigned char *)in_data, in_size);
 	}
 #endif
-	/* Allocate the output buffer */
-	output_buffer_length = in_size + 16;
-	output_buffer = (unsigned char *)slapi_ch_malloc(output_buffer_length);
-	/* Now call NSS to do the cipher op */
-	iv_item.data = (unsigned char *)"aaaaaaaaaaaaaaaa"; /* ptr to an array of IV bytes */
-	iv_item.len = acs->ace->iv_length; /* length of the array of IV bytes */
-	security_parameter = slapd_pk11_ParamFromIV(acs->ace->cipher_mechanism, &iv_item);
-	if (NULL == security_parameter) {
-		int errorCode = PR_GetError();
-		LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op failed to make IV for cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
-		goto error;
-	}
-	sec_context = slapd_pk11_createContextBySymKey(acs->ace->cipher_mechanism, (encrypt ? CKA_ENCRYPT : CKA_DECRYPT), acs->key, security_parameter); 
-	if (NULL == sec_context) {
-		int errorCode = PR_GetError();
-		LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op failed on cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
-		goto error;
-	}	
-	secret = slapd_pk11_cipherOp(sec_context, output_buffer, &output_buffer_size1, output_buffer_length, (unsigned char *)in_data, in_size);
-	if (SECSuccess != secret) {
-		int errorCode = PR_GetError();
-		LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op failed on cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
-		goto error;
-	}
-#if defined(DEBUG_ATTRCRYPT)
-	LDAPDebug(LDAP_DEBUG_ANY,"slapd_pk11_cipherOp %d\n", output_buffer_size1, 0, 0);
-#endif
-	secret = slapd_pk11_DigestFinal(sec_context, output_buffer + output_buffer_size1, &output_buffer_size2, output_buffer_length - output_buffer_size1);
-	if (SECSuccess != secret) {
-		int errorCode = PR_GetError();
-		LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op digest final failed on cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
-		goto error;
-	} else {
-#if defined(DEBUG_ATTRCRYPT)
-		int recurse = 1;
-		if (encrypt) {
-			log_bytes("slapd_pk11_DigestFinal '%s' (%d)\n", output_buffer, output_buffer_size1 + output_buffer_size2);
-		} else {
-			LDAPDebug(LDAP_DEBUG_ANY,"slapd_pk11_DigestFinal '%s', %u\n", output_buffer, output_buffer_size2, 0);
-		}
-		if (*out_size == -1) {
-			recurse = 0;
-		}
-#endif
-		*out_size = output_buffer_size1 + output_buffer_size2;
-		*out_data = (char *)output_buffer;
-		ret = 0; /* success */
-#if defined(DEBUG_ATTRCRYPT)
-		if (recurse) {
-			char *redo_data = NULL;
-			size_t redo_size = -1;
-			int redo_ret;
-
-			LDAPDebug(LDAP_DEBUG_ANY,"------> check result of crypto op\n", 0, 0, 0);
-			redo_ret = attrcrypt_crypto_op(priv, be, ai, *out_data, *out_size, &redo_data, &redo_size, !encrypt);
-			slapi_log_error(SLAPI_LOG_FATAL, "DEBUG_ATTRCRYPT",
-							"orig length %ld redone length %ld\n", in_size, redo_size);
-			log_bytes("DEBUG_ATTRCRYPT orig bytes '%s' (%d)\n", (unsigned char *)in_data, in_size);
-			log_bytes("DEBUG_ATTRCRYPT redo bytes '%s' (%d)\n", (unsigned char *)redo_data, redo_size);
-
-			LDAPDebug(LDAP_DEBUG_ANY,"<------ check result of crypto op\n", 0, 0, 0);
-		}
-#endif
-	}
-error:
-	if (sec_context) {
-		slapd_pk11_DestroyContext(sec_context, PR_TRUE);
-	}
-	if (security_parameter) {
-		slapd_SECITEM_FreeItem(security_parameter, PR_TRUE);
-	}
-	if (ret) {
-		slapi_ch_free_string((char **)&output_buffer);
-	}
+	ret = _back_crypt_crypto_op(priv, acs, in_data, in_size,
+	                            out_data, out_size, encrypt, be, ai);
 	LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op\n", 0, 0, 0);
 	return ret;
 }
@@ -1026,3 +938,607 @@ bail:
 
 	return rc;
 }
+
+/******************************************************************************/
+static int _back_crypt_cipher_init(Slapi_Backend *be, attrcrypt_state_private **state_priv, attrcrypt_cipher_entry *ace, SECKEYPrivateKey *private_key, SECKEYPublicKey *public_key, attrcrypt_cipher_state *acs, const char *dn_string);
+static int _back_crypt_keymgmt_store_key(Slapi_Backend *be, attrcrypt_cipher_state *acs, SECKEYPublicKey *public_key, PK11SymKey *key_to_store, const char *dn_string);
+static int _back_crypt_crypto_op_value(attrcrypt_state_private *state_priv, Slapi_Value *invalue, Slapi_Value **outvalue, int encrypt);
+
+int
+back_crypt_init(Slapi_Backend *be, const char *dn,
+                const char *encAlgorithm, void **handle)
+{
+    int ret = 0;
+    attrcrypt_cipher_entry *ace = NULL;
+    SECKEYPrivateKey *private_key = NULL;
+    SECKEYPublicKey *public_key = NULL;
+    attrcrypt_state_private **state_priv = (attrcrypt_state_private **)handle;
+
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT, "-> back_crypt_init\n");
+    /* Encryption is not specified */
+    if (!encAlgorithm || !handle) {
+        goto bail;
+    }
+    if (!slapd_security_library_is_initialized()) {
+        goto bail;
+    }
+    _back_crypt_cleanup_private(state_priv);
+
+    /* Get the server's private key, 
+     * which is used to unwrap the stored symmetric keys */
+    ret = attrcrypt_fetch_private_key(&private_key);
+    if (ret) {
+        goto bail;
+    }
+    ret = attrcrypt_fetch_public_key(&public_key);
+    if (ret) {
+        goto bail;
+    }
+    for (ace = attrcrypt_cipher_list;
+         ace && ace->cipher_number && !ret; ace++) {
+        if (strcasecmp(ace->cipher_display_name, encAlgorithm)) {
+            continue; /* did not match. next. */
+        }
+        /* Make a state object for this cipher */
+        attrcrypt_cipher_state *acs = (attrcrypt_cipher_state *)slapi_ch_calloc(
+                                             sizeof(attrcrypt_cipher_state), 1);
+        ret = _back_crypt_cipher_init(be, state_priv, ace,
+                                      private_key, public_key, acs, dn);
+        if (ret) {
+            slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+                            "back_crypt_init: Failed to initialize cipher %s\n",
+                            ace->cipher_display_name);
+            slapi_ch_free((void **)&acs);
+        } else {
+            /* Since we succeeded, set acs to state_priv */
+            _back_crypt_acs_list_add(state_priv, acs);
+            slapi_log_error(SLAPI_LOG_BACKLDBM, ATTRCRYPT,
+                           "back_crypt_init: Initialized cipher %s\n",
+                           ace->cipher_display_name);
+        }
+        break;
+    }
+    SECKEY_DestroyPublicKey(public_key);
+    public_key = NULL;
+    SECKEY_DestroyPrivateKey(private_key);
+    private_key = NULL;
+bail:
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT, 
+                    "<- back_crypt_init : %d\n", ret);
+    return ret;
+}
+
+/*
+ * return values:  0 - success
+ *              : -1 - error 
+ *
+ * output value: out: non-NULL - encryption successful
+ *                  :     NULL - no encryption or failure
+ */
+int
+back_crypt_encrypt_value(void *handle, struct berval *in, struct berval **out)
+{
+    int ret = -1;
+    Slapi_Value *invalue = NULL;
+    Slapi_Value *outvalue = NULL;
+    attrcrypt_state_private *state_priv = (attrcrypt_state_private *)handle;
+
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT, 
+                    "-> back_crypt_encrypt_value\n");
+    if (NULL == out) {
+        goto bail;
+    }
+    *out = NULL;
+    if (!state_priv || !state_priv->acs_array) {
+        goto bail;
+    }
+    invalue = slapi_value_new_berval(in);
+    /* Now encrypt the attribute values in place on the new entry */
+    ret = _back_crypt_crypto_op_value(state_priv, invalue, &outvalue, 1);
+    if (0 == ret) {
+        *out = slapi_ch_bvdup(slapi_value_get_berval(outvalue));
+    }
+bail:
+    slapi_value_free(&invalue);
+    slapi_value_free(&outvalue);
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT, 
+                    "<- back_crypt_encrypt_entry (returning %d)\n", ret);
+    return ret;
+}
+
+int 
+back_crypt_decrypt_value(void *handle, struct berval *in, struct berval **out)
+{
+    int ret = -1;
+    Slapi_Value *invalue = NULL;
+    Slapi_Value *outvalue = NULL;
+    attrcrypt_state_private *state_priv = (attrcrypt_state_private *)handle;
+
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT, 
+                    "-> back_crypt_decrypt_value\n");
+    if (NULL == out) {
+        goto bail;
+    }
+    *out = NULL;
+    if (!state_priv || !state_priv->acs_array) {
+        goto bail;
+    }
+    invalue = slapi_value_new_berval(in);
+    /* Now decrypt the value */
+    ret = _back_crypt_crypto_op_value(state_priv, invalue, &outvalue, 0);
+    if (0 == ret) {
+        *out = slapi_ch_bvdup(slapi_value_get_berval(outvalue));
+    }
+bail:
+    slapi_value_free(&invalue);
+    slapi_value_free(&outvalue);
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT, 
+                    "<- _back_crypt_decrypt_entry (returning %d)\n", ret);
+    return ret;
+}
+
+static int
+_back_crypt_crypto_op_value(attrcrypt_state_private *state_priv,
+                            Slapi_Value *invalue, Slapi_Value **outvalue,
+                            int encrypt)
+{
+    int ret = -1;
+    char *in_data = NULL;
+    size_t in_size = 0;
+    char *out_data = NULL;
+    size_t out_size = 0;
+    struct berval *bval = NULL;
+    attrcrypt_cipher_state *acs = NULL;
+
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT, 
+                    "-> _back_crypt_crypto_op_value\n");
+    if (NULL == invalue || NULL == outvalue) {
+        goto bail;
+    }
+    
+    bval = (struct berval *) slapi_value_get_berval(invalue);
+    if (NULL == bval) {
+        goto bail;
+    }
+    in_data = bval->bv_val;
+    in_size = bval->bv_len;
+
+    acs = state_priv->acs_array[0];
+    if (NULL == acs) {
+        /* This happens if SSL/NSS has not been enabled */
+        goto bail;
+    }
+    ret = _back_crypt_crypto_op(NULL, acs, in_data, in_size,
+                                &out_data, &out_size, encrypt, NULL, NULL);
+    if (0 == ret) {
+        struct berval outbervalue = {0};
+        outbervalue.bv_len = out_size;
+        outbervalue.bv_val = out_data;
+        /* This call makes a copy of the payload data, 
+         * so we need to free the original data after making the call */
+        *outvalue = slapi_value_new_berval(&outbervalue);
+        slapi_ch_free((void**)&out_data);
+    }
+
+bail:
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT, 
+                    "<- _back_crypt_crypto_op_value (returning %d)\n", ret);
+    return ret;
+}
+
+
+/* Initialize the structure for a single cipher */
+static int
+_back_crypt_cipher_init(Slapi_Backend *be,
+                        attrcrypt_state_private **state_priv,
+                        attrcrypt_cipher_entry *ace,
+                        SECKEYPrivateKey *private_key,
+                        SECKEYPublicKey *public_key,
+                        attrcrypt_cipher_state *acs,
+                        const char *dn_string)
+{
+    int ret = 1; /* fail by default */
+    PK11SymKey *symmetric_key = NULL;
+
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT, "-> _back_crypt_cipher_init\n");
+    acs->cipher_lock = PR_NewLock();
+    /* Fill in some basic stuff */
+    acs->ace = ace;
+    acs->cipher_display_name = ace->cipher_display_name;
+    if (NULL == acs->cipher_lock) {
+        slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+                        "_back_crypt_cipher_init: Cipher lock not found.\n");
+    }
+    acs->slot = slapd_pk11_getInternalKeySlot();
+    if (NULL == acs->slot) {
+        slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+            "_back_crypt_cipher_init: Failed to create a slot for cipher %s\n",
+            acs->cipher_display_name);
+        goto error;
+    }
+    /* Try to get the symmetric key for this cipher */
+    ret = _back_crypt_keymgmt_get_key(acs, private_key, 
+                                      &symmetric_key, dn_string);
+    if (KEYMGMT_ERR_NO_ENTRY == ret) {
+        slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+                "_back_crypt_cipher_init: entry storing key does not exist.\n");
+    } else if (KEYMGMT_ERR_OTHER == ret) {
+        slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+                "_back_crypt_cipher_init: coding error.\n");
+    } else if (KEYMGMT_ERR_CANT_UNWRAP == ret) {
+        slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+                "_back_crypt_cipher_init: symmetric key failed to unwrap "
+                "with the private key; Cert might have been renewed since "
+                "the key is wrapped.  To recover the encrypted contents, "
+                "keep the wrapped symmetric key value.\n");
+    } else if (ret) {
+        slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+                "_back_crypt_cipher_init: No symmetric key found for cipher "
+                "%s, attempting to create one...\n", acs->cipher_display_name);
+        ret = attrcrypt_generate_key(acs, &symmetric_key);
+        if (ret) {
+            slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+                    "_back_crypt_cipher_init: Failed to generate key for %s\n",
+                    acs->cipher_display_name);
+        }
+        if (symmetric_key) {
+            ret = _back_crypt_keymgmt_store_key(be, acs, public_key, 
+                                                symmetric_key, dn_string);
+            if (ret) {
+                slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+                    "_back_crypt_cipher_init: Failed to store key for cipher "
+                    "%s\n", acs->cipher_display_name);
+            } else {
+                slapi_log_error(SLAPI_LOG_BACKLDBM, ATTRCRYPT, 
+                    "Key for cipher %s successfully generated and stored\n",
+                    acs->cipher_display_name);
+            }
+        }
+    }
+    if (symmetric_key) {
+        /* we loaded the symmetric key, store it in the acs */
+        acs->key = symmetric_key;
+    }
+error:
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT,
+                    "<- _back_crypt_cipher_init (returning %d\n", ret);
+    return ret;
+}
+
+/*
+ * This function cleans up the state_private in cl5Desc
+ */
+static int
+_back_crypt_cleanup_private(attrcrypt_state_private **state_priv)
+{
+    attrcrypt_cipher_state **current = NULL;
+
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT,
+                    "-> _back_crypt_cleanup_private\n");
+    if (state_priv && *state_priv) {
+        for (current = &((*state_priv)->acs_array[0]); *current; current++) {
+            attrcrypt_cleanup(*current);
+            slapi_ch_free((void **)current);
+        }
+        slapi_ch_free((void **)state_priv);
+    }
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT,
+                    "<- _back_crypt_cleanup_private\n");
+    return 0;
+}
+
+/* Retrieve a symmetric key from dse.ldif for a specified cipher */
+/*
+ * return values: 0 -- successfully retrieved
+ *                KEYMGMT_ERR_NO_ENTRY     - Entry to store key does not exist
+ *                KEYMGMT_ERR_NO_KEY_ATTR  - Entry has no key attribute
+ *                KEYMGMT_ERR_NO_KEY_VALUE - Empty key
+ *                KEYMGMT_ERR_CANT_UNWRAP  - Key failed to unwrap
+ *                KEYMGMT_ERR_OTHER        - Other error
+ */
+static int
+_back_crypt_keymgmt_get_key(attrcrypt_cipher_state *acs,
+                            SECKEYPrivateKey *private_key,
+                            PK11SymKey **key_from_store,
+                            const char *dn_string)
+{
+    int ret = KEYMGMT_ERR_OTHER;
+    Slapi_Entry *entry = NULL;
+    Slapi_Attr *keyattr = NULL;
+    
+    if (NULL == key_from_store) {
+        return ret;
+    }
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT,
+                    "-> _back_crypt_keymgmt_get_key\n");
+    *key_from_store = NULL;
+    /* Fetch the entry */
+    getConfigEntry(dn_string, &entry);
+    /* Did we find the entry ? */
+    if (entry) {
+        SECItem key_to_unwrap = {0};
+        /* If so then look for the attribute that contains the key */
+        slapi_entry_attr_find(entry, KEY_ATTRIBUTE_NAME, &keyattr);
+        if (keyattr) {
+            Slapi_Value *v = NULL;
+            ret = slapi_attr_first_value(keyattr, &v);
+            if (ret < 0) {
+                ret = KEYMGMT_ERR_NO_KEY_VALUE; /* Empty key */
+                goto bail;
+            }
+            key_to_unwrap.len = slapi_value_get_length(v);
+            key_to_unwrap.data = (void*)slapi_value_get_string(v);
+            /* Unwrap it */
+            ret = attrcrypt_unwrap_key(acs, private_key,
+                                       &key_to_unwrap, key_from_store);
+            if (ret) {
+                ret = KEYMGMT_ERR_CANT_UNWRAP; /* Key failed to unwrap */
+            }
+        } else {
+            ret = KEYMGMT_ERR_NO_KEY_ATTR; /* Entry has no key attribute */
+        }
+    } else {
+        /* we didn't find the entry (which happens if the key has
+         * never been generated) */
+        ret = KEYMGMT_ERR_NO_ENTRY;
+    }
+bail:
+    freeConfigEntry(&entry);
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT,
+                    "<- _back_crypt_keymgmt_get_key (returning %d)\n", ret);
+    return ret;
+}
+
+/* Store a symmetric key for a given cipher in dse.ldif */
+static int
+_back_crypt_keymgmt_store_key(Slapi_Backend *be,
+                              attrcrypt_cipher_state *acs, 
+                              SECKEYPublicKey *public_key,
+                              PK11SymKey *key_to_store,
+                              const char *dn_string)
+{
+    int ret = 1;
+    SECItem wrapped_symmetric_key = {0};
+    ldbm_instance *li = NULL;
+
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT,
+                   "-> _back_crypt_keymgmt_store_key\n");
+    if (!be || !be->be_instance_info) {
+        goto bail;
+    }
+    li = (ldbm_instance *)be->be_instance_info;
+    /* Wrap the key and then store it in the right place in dse.ldif */
+    ret = attrcrypt_wrap_key(acs, key_to_store, 
+                             public_key, &wrapped_symmetric_key);
+    if (!ret) {
+        /* store the wrapped symmetric key to the specified entry (dn_string) */
+        Slapi_PBlock *pb = slapi_pblock_new();
+        Slapi_Value *key_value = NULL;
+        struct berval key_as_berval = {0};
+        Slapi_Mods *smods = slapi_mods_new();
+        Slapi_Value *va[2];
+        int rc = 0;
+
+        /* Add the key as a binary attribute */
+        key_as_berval.bv_val = (char *)wrapped_symmetric_key.data;
+        key_as_berval.bv_len = wrapped_symmetric_key.len;
+        key_value = slapi_value_new_berval(&key_as_berval);
+        va[0] = key_value;
+        va[1] = NULL;
+        /* key_value is now a copy of key_as_berval
+         * - free wrapped_symmetric_key */
+        slapi_ch_free_string((char **)&wrapped_symmetric_key.data);
+
+        slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
+                                  KEY_ATTRIBUTE_NAME, va);
+        slapi_modify_internal_set_pb(pb, dn_string,
+                slapi_mods_get_ldapmods_byref(smods), NULL, NULL, 
+                li->inst_li->li_identity, 0);
+        slapi_modify_internal_pb (pb);
+        slapi_value_free(&key_value);
+        slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+        if (rc) {
+            char *resulttext = NULL;
+            slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &resulttext);
+            slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT,
+                      "_back_crypt_keymgmt_store_key: failed to add config key "
+                     "to the DSE: %d: %s: %s\n", rc, ldap_err2string(rc),
+                     resulttext ? resulttext : "unknown");
+            ret = -1;
+        }
+        slapi_mods_free(&smods);
+        slapi_pblock_destroy(pb);
+    }
+bail:
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT,
+                  "<- _back_crypt_keymgmt_store_key (returning %d)\n", ret);
+    return ret;
+}
+
+static void 
+_back_crypt_acs_list_add(attrcrypt_state_private **state_priv,
+                         attrcrypt_cipher_state *acs)
+{
+    /* Realloc the existing list and add to the end */
+    attrcrypt_cipher_state **current = NULL;
+    size_t list_size = 0;
+
+    if (NULL == state_priv) {
+        return;
+    }
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT,
+                    "-> _back_crypt_acs_list_add\n");
+
+    /* Is the list already there ? */
+    if (NULL == *state_priv) {
+        /* If not, add it */
+        /* 2 == The pointer and a NULL terminator */
+        *state_priv = (attrcrypt_state_private *)slapi_ch_calloc(
+                                           sizeof(attrcrypt_cipher_state *), 2);
+    } else {
+        /* Otherwise re-size it */
+        for (current = &((*state_priv)->acs_array[0]); current && *current;
+             current++) {
+            list_size++;
+        }
+        *state_priv =
+            (attrcrypt_state_private *)slapi_ch_realloc((char *)*state_priv,
+                            sizeof(attrcrypt_cipher_state *) * (list_size + 2));
+        (*state_priv)->acs_array[list_size + 1] = NULL; 
+    }
+    (*state_priv)->acs_array[list_size] = acs;
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT,
+                    "<- _back_crypt_acs_list_add\n");
+    return;
+}
+
+/* Either encipher or decipher an attribute value */
+static int
+_back_crypt_crypto_op(attrcrypt_private *priv, 
+                      attrcrypt_cipher_state *acs,
+                      char *in_data, size_t in_size,
+                      char **out_data, size_t *out_size, int encrypt,
+                      backend *be, struct attrinfo *ai /* just for debugging */)
+{
+    int rc = -1;
+    SECStatus secret = 0;
+    PK11Context* sec_context = NULL;
+    SECItem iv_item = {0};
+    SECItem *security_parameter = NULL;
+    int output_buffer_length = 0;
+    int output_buffer_size1 = 0;
+    unsigned int output_buffer_size2 = 0;
+    unsigned char *output_buffer = NULL;
+
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT, "-> _back_crypt_crypto_op\n");
+    if (NULL == acs) {
+        goto bail;
+    }
+    if (encrypt) {
+        slapi_log_error(SLAPI_LOG_BACKLDBM, ATTRCRYPT,
+                        "_back_crypt_crypto_op encrypt '%s' (%d)\n", 
+                        in_data, in_size);
+    } else {
+        slapi_log_error(SLAPI_LOG_BACKLDBM, ATTRCRYPT,
+                        "_back_crypt_crypto_op decrypt (%d)\n", in_size);
+    }
+    /* Allocate the output buffer */
+    output_buffer_length = in_size + BACK_CRYPT_OUTBUFF_EXTLEN;
+    output_buffer = (unsigned char *)slapi_ch_malloc(output_buffer_length);
+    /* Now call NSS to do the cipher op */
+    iv_item.data = (unsigned char *)"aaaaaaaaaaaaaaaa"; /* ptr to an array 
+                                                           of IV bytes */
+    iv_item.len = acs->ace->iv_length; /* length of the array of IV bytes */
+    security_parameter = slapd_pk11_ParamFromIV(acs->ace->cipher_mechanism,
+                                                &iv_item);
+    if (NULL == security_parameter) {
+        int errorCode = PR_GetError();
+        slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+                        "back_crypt_crypto_op: failed to make IV for cipher %s "
+                        ": %d - %s\n", acs->ace->cipher_display_name, errorCode,
+                        slapd_pr_strerror(errorCode));
+        goto error;
+    }
+    sec_context = slapd_pk11_createContextBySymKey(acs->ace->cipher_mechanism,
+                                          (encrypt ? CKA_ENCRYPT : CKA_DECRYPT),
+                                          acs->key, security_parameter); 
+    if (NULL == sec_context) {
+        int errorCode = PR_GetError();
+        slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+                        "_back_crypt_crypto_op: failed on cipher %s : "
+                        "%d - %s\n", acs->ace->cipher_display_name, errorCode, 
+                        slapd_pr_strerror(errorCode));
+        goto error;
+    }    
+    secret = slapd_pk11_cipherOp(sec_context, output_buffer,
+                                 &output_buffer_size1, output_buffer_length,
+                                 (unsigned char *)in_data, in_size);
+    if (SECSuccess != secret) {
+        int errorCode = PR_GetError();
+        slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+                    "_back_crypt_crypto_op failed on cipher %s : %d - %s\n",
+                    acs->ace->cipher_display_name, errorCode, 
+                    slapd_pr_strerror(errorCode));
+        goto error;
+    }
+    secret = slapd_pk11_DigestFinal(sec_context,
+                                    output_buffer + output_buffer_size1,
+                                    &output_buffer_size2,
+                                    output_buffer_length - output_buffer_size1);
+    if (SECSuccess != secret) {
+        int errorCode = PR_GetError();
+        slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+                        "_back_crypt_crypto_op digest final failed on cipher "
+                        "%s : %d - %s\n", acs->ace->cipher_display_name,
+                        errorCode, slapd_pr_strerror(errorCode));
+        goto error;
+    } else {
+#if defined(DEBUG_ATTRCRYPT)
+        int recurse = 1;
+        if (encrypt) {
+            log_bytes("slapd_pk11_DigestFinal '%s' (%d)\n", 
+                    output_buffer, output_buffer_size1 + output_buffer_size2);
+        } else {
+            slapi_log_error(SLAPI_LOG_FATAL, "DEBUG_ATTRCRYPT", 
+                    "slapd_pk11_DigestFinal '%s', %u\n",
+                    output_buffer, output_buffer_size1 + output_buffer_size2);
+        }
+        if (*out_size == -1) {
+            recurse = 0;
+        }
+#endif
+        *out_size = output_buffer_size1 + output_buffer_size2;
+        *out_data = (char *)output_buffer;
+        rc = 0; /* success */
+#if defined(DEBUG_ATTRCRYPT)
+        if (recurse) {
+            char *redo_data = NULL;
+            size_t redo_size = -1;
+            int redo_ret;
+
+            slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+                            "------> check result of crypto op\n");
+            if (priv && be && ai) {
+                redo_ret = attrcrypt_crypto_op(priv, be, ai, 
+                                               *out_data, *out_size,
+                                               &redo_data, &redo_size,
+                                               !encrypt);
+                slapi_log_error(SLAPI_LOG_FATAL, "DEBUG_ATTRCRYPT",
+                                "attrcrypt_crypto_op returned (%d) "
+                                "orig length %u redone length %u\n", 
+                                redo_ret, in_size, redo_size);
+            } else {
+                redo_ret = _back_crypt_crypto_op(NULL, acs,
+                                                 *out_data, *out_size,
+                                                 &redo_data, &redo_size,
+                                                 !encrypt, NULL, NULL);
+                slapi_log_error(SLAPI_LOG_FATAL, "DEBUG_ATTRCRYPT",
+                                "_back_crypt_crypto_op returned (%d) "
+                                "orig length %u redone length %u\n", 
+                                redo_ret, in_size, redo_size);
+            }
+            log_bytes("DEBUG_ATTRCRYPT orig bytes '%s' (%d)\n", 
+                            (unsigned char *)in_data, in_size);
+            log_bytes("DEBUG_ATTRCRYPT redo bytes '%s' (%d)\n", 
+                            (unsigned char *)redo_data, redo_size);
+
+            slapi_log_error(SLAPI_LOG_FATAL, ATTRCRYPT, 
+                            "<------ check result of crypto op\n");
+        }
+#endif
+    }
+error:
+    if (sec_context) {
+        PK11_DestroyContext(sec_context, PR_TRUE);
+    }
+    if (security_parameter) {
+        SECITEM_FreeItem(security_parameter, PR_TRUE);
+    }
+    if (rc) {
+        slapi_ch_free_string((char **)&output_buffer);
+    }
+bail:
+    slapi_log_error(SLAPI_LOG_TRACE, ATTRCRYPT, 
+                    "<- _back_crypt_crypto_op (returning %d)\n", rc);
+    return rc;
+}

+ 6 - 0
ldap/servers/slapd/back-ldbm/proto-back-ldbm.h

@@ -176,6 +176,7 @@ int dblayer_remove_env(struct ldbminfo *li);
 
 int ldbm_back_get_info(Slapi_Backend *be, int cmd, void **info);
 int ldbm_back_set_info(Slapi_Backend *be, int cmd, void *info);
+int ldbm_back_ctrl_info(Slapi_Backend *be, int cmd, void *info);
 
 /*
  * dn2entry.c
@@ -619,6 +620,11 @@ int ldbm_instance_attrcrypt_config_add_callback(Slapi_PBlock *pb, Slapi_Entry* e
 int ldbm_instance_attrcrypt_config_delete_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
 int ldbm_instance_attrcrypt_config_modify_callback(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg);
 
+int back_crypt_init(Slapi_Backend *be, const char *dn, const char *encAlgorithm, void **handle);
+int back_crypt_encrypt_value(void *handle, struct berval *in, struct berval **out);
+int
+back_crypt_decrypt_value(void *handle, struct berval *in, struct berval **out);
+
 void replace_ldbm_config_value(char *conftype, char *val, struct ldbminfo *li);
 
 /*

+ 11 - 0
ldap/servers/slapd/backend.c

@@ -603,3 +603,14 @@ slapi_back_set_info(Slapi_Backend *be, int cmd, void *info)
     rc = (*be->be_set_info)(be, cmd, info);
     return rc;
 }
+
+int
+slapi_back_ctrl_info(Slapi_Backend *be, int cmd, void *info)
+{
+    int rc = -1;
+    if (!be || !be->be_ctrl_info || !info) {
+        return rc;
+    }
+    rc = (*be->be_ctrl_info)(be, cmd, info);
+    return rc;
+}

+ 4 - 3
ldap/servers/slapd/opshared.c

@@ -52,9 +52,10 @@
 static void compute_limits (Slapi_PBlock *pb);
 
 /* attributes that no clients are allowed to add or modify */
-static char *protected_attrs_all [] = {    PSEUDO_ATTR_UNHASHEDUSERPASSWORD,
-                                        NULL
-                                      };
+/* PSEUDO_ATTR_UNHASHEDUSERPASSWORD used to be in protected_attrs_all. 
+ * Now it's moved to back-ldbm/id2entry.c to share it among repl masters.
+ * (bz 182507)*/
+static char *protected_attrs_all [] = { NULL };
 static char *pwpolicy_lock_attrs_all [] = { "passwordRetryCount",
                                             "retryCountResetTime",
                                             "accountUnlockTime",

+ 6 - 0
ldap/servers/slapd/pblock.c

@@ -616,6 +616,9 @@ slapi_pblock_get( Slapi_PBlock *pblock, int arg, void *value )
 	case SLAPI_PLUGIN_DB_SET_INFO_FN:
 		(*(IFP *)value) = pblock->pb_plugin->plg_set_info;
 		break;
+	case SLAPI_PLUGIN_DB_CTRL_INFO_FN:
+		(*(IFP *)value) = pblock->pb_plugin->plg_ctrl_info;
+		break;
 	case SLAPI_PLUGIN_DB_SEQ_FN:
 		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
 			return( -1 );
@@ -2038,6 +2041,9 @@ slapi_pblock_set( Slapi_PBlock *pblock, int arg, void *value )
 	case SLAPI_PLUGIN_DB_SET_INFO_FN:
 		pblock->pb_plugin->plg_set_info = (IFP) value;
 		break;
+	case SLAPI_PLUGIN_DB_CTRL_INFO_FN:
+		pblock->pb_plugin->plg_ctrl_info = (IFP) value;
+		break;
 	case SLAPI_PLUGIN_DB_SEQ_FN:
 		if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
 			return( -1 );

+ 3 - 0
ldap/servers/slapd/slap.h

@@ -845,6 +845,7 @@ struct slapdplugin {
 			IFP	plg_un_db_add_schema;     /* add schema */
 			IFP	plg_un_db_get_info;       /* get info */
 			IFP	plg_un_db_set_info;       /* set info */
+			IFP	plg_un_db_ctrl_info;      /* ctrl info */
 		} plg_un_db;
 #define plg_bind		plg_un.plg_un_db.plg_un_db_bind
 #define plg_unbind		plg_un.plg_un_db.plg_un_db_unbind
@@ -882,6 +883,7 @@ struct slapdplugin {
 #define plg_add_schema          plg_un.plg_un_db.plg_un_db_add_schema
 #define plg_get_info            plg_un.plg_un_db.plg_un_db_get_info
 #define plg_set_info            plg_un.plg_un_db.plg_un_db_set_info
+#define plg_ctrl_info            plg_un.plg_un_db.plg_un_db_ctrl_info
 
 		/* extended operation plugin structure */
 		struct plg_un_protocol_extension {
@@ -1162,6 +1164,7 @@ typedef struct backend {
 #define be_wire_import          be_database->plg_wire_import
 #define be_get_info             be_database->plg_get_info
 #define be_set_info             be_database->plg_set_info
+#define be_ctrl_info            be_database->plg_ctrl_info
 
 	void *be_instance_info;		/* If the database plugin pointed to by
 								 * be_database supports more than one instance,

+ 39 - 3
ldap/servers/slapd/slapi-plugin.h

@@ -6272,13 +6272,49 @@ int slapi_back_get_info(Slapi_Backend *be, int cmd, void **info);
  */
 int slapi_back_set_info(Slapi_Backend *be, int cmd, void *info);
 
+/**
+ * Execute cmd in backend
+ *
+ * \param be Backend where the command is executed
+ * \param cmd macro to specify the execution type
+ * \param info pointer to the information
+ * \return \c 0 if the operation was successful
+ * \return non-0 if the operation was not successful
+ *
+ * \note Implemented cmd:
+ * BACK_INFO_CRYPT_INIT - Initialize cipher (info: back_info_crypt_init)
+ * BACK_INFO_CRYPT_ENCRYPT_VALUE - Encrypt the given value (info: back_info_crypt_value)
+ * BACK_INFO_CRYPT_DECRYPT_VALUE - Decrypt the given value (info: back_info_crypt_value)
+ */
+int slapi_back_ctrl_info(Slapi_Backend *be, int cmd, void *info);
+
 /* cmd */
 enum
 {
-    BACK_INFO_DBENV,         /* Get the dbenv */
-    BACK_INFO_INDEXPAGESIZE, /* Get the index page size */
-    BACK_INFO_DBENV_OPENFLAGS/* Get the dbenv openflags */
+    BACK_INFO_DBENV,               /* Get the dbenv */
+    BACK_INFO_INDEXPAGESIZE,       /* Get the index page size */
+    BACK_INFO_DBENV_OPENFLAGS,     /* Get the dbenv openflags */
+    BACK_INFO_CRYPT_INIT,          /* Ctrl: clcrypt_init */
+    BACK_INFO_CRYPT_ENCRYPT_VALUE, /* Ctrl: clcrypt_encrypt_value */
+    BACK_INFO_CRYPT_DECRYPT_VALUE  /* Ctrl: clcrypt_decrypt_value */
+};
+
+struct _back_info_crypt_init {
+    char *dn;                  /* input -- entry to store nsSymmetricKey */
+    char *encryptionAlgorithm; /* input -- encryption althorithm */
+    Slapi_Backend *be;         /* input -- backend to use */
+    void *state_priv;          /* outout */
 };
+typedef struct _back_info_crypt_init back_info_crypt_init;
+
+struct _back_info_crypt_value {
+    void *state_priv;          /* input */
+    struct berval *in;          /* input */
+    struct berval *out;         /* output */
+};
+typedef struct _back_info_crypt_value back_info_crypt_value;
+
+#define BACK_CRYPT_OUTBUFF_EXTLEN 16
 
 #ifdef __cplusplus
 }

+ 1 - 0
ldap/servers/slapd/slapi-private.h

@@ -886,6 +886,7 @@ int proxyauth_get_dn( Slapi_PBlock *pb, char **proxydnp, char **errtextp );
 #define SLAPI_PLUGIN_DB_RMDB_FN         	280
 #define SLAPI_PLUGIN_DB_GET_INFO_FN			290
 #define SLAPI_PLUGIN_DB_SET_INFO_FN			291
+#define SLAPI_PLUGIN_DB_CTRL_INFO_FN			292
 
 /**** End of database plugin interface. **************************************/