Makefile.am | 1
Makefile.in | 15
ldap/servers/plugins/replication/cl5.h | 1
ldap/servers/plugins/replication/cl5_api.c | 107 +
ldap/servers/plugins/replication/cl5_api.h | 2
ldap/servers/plugins/replication/cl5_config.c | 37
ldap/servers/plugins/replication/cl_crypt.c | 203 +++
ldap/servers/plugins/replication/cl_crypt.h | 53
ldap/servers/plugins/replication/repl_shared.h | 17
ldap/servers/plugins/replication/windows_protocol_util.c | 2
ldap/servers/slapd/back-ldbm/dblayer.c | 42
ldap/servers/slapd/back-ldbm/id2entry.c | 20
ldap/servers/slapd/back-ldbm/init.c | 2
ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c | 818 ++++++++++++---
ldap/servers/slapd/back-ldbm/proto-back-ldbm.h | 6
ldap/servers/slapd/backend.c | 11
ldap/servers/slapd/opshared.c | 7
ldap/servers/slapd/pblock.c | 6
ldap/servers/slapd/slap.h | 3
ldap/servers/slapd/slapi-plugin.h | 42
ldap/servers/slapd/slapi-private.h | 1
21 files changed, 1203 insertions(+), 193 deletions(-)
New commits:
commit 7aef407a3d621f3b03455b75cfcbf2f26fcfd1fe
Author: Noriko Hosoi <nhosoi(a)jiji.usersys.redhat.com>
Date: Wed Dec 15 13:01:04 2010 -0800
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
diff --git a/Makefile.am b/Makefile.am
index 051a958..1b43a0a 100644
--- a/Makefile.am
+++ b/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 \
diff --git a/Makefile.in b/Makefile.in
index 9f631c8..a5a5c3e 100644
--- a/Makefile.in
+++ b/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(a)am__quote@
@AMDEP_TRUE@@am__include@
@am__quote@ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-cl5_config.Plo(a)am__quote@
@AMDEP_TRUE@@am__include@
@am__quote@ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-cl5_init.Plo(a)am__quote@
+@AMDEP_TRUE@@am__include@
@am__quote@ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-cl_crypt.Plo(a)am__quote@
@AMDEP_TRUE@@am__include@
@am__quote@ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-csnpl.Plo(a)am__quote@
@AMDEP_TRUE@@am__include@
@am__quote@ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-legacy_consumer.Plo(a)am__quote@
@AMDEP_TRUE@@am__include@
@am__quote@ldap/servers/plugins/replication/$(DEPDIR)/libreplication_plugin_la-llist.Plo(a)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
diff --git a/ldap/servers/plugins/replication/cl5.h
b/ldap/servers/plugins/replication/cl5.h
index 1b95973..4c92ecd 100644
--- a/ldap/servers/plugins/replication/cl5.h
+++ b/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*/
diff --git a/ldap/servers/plugins/replication/cl5_api.c
b/ldap/servers/plugins/replication/cl5_api.c
index f781dce..ed93ed2 100644
--- a/ldap/servers/plugins/replication/cl5_api.c
+++ b/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);
}
diff --git a/ldap/servers/plugins/replication/cl5_api.h
b/ldap/servers/plugins/replication/cl5_api.h
index f300cd8..9590dd1 100644
--- a/ldap/servers/plugins/replication/cl5_api.h
+++ b/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 */
diff --git a/ldap/servers/plugins/replication/cl5_config.c
b/ldap/servers/plugins/replication/cl5_config.c
index 2e66917..0698c55 100644
--- a/ldap/servers/plugins/replication/cl5_config.c
+++ b/ldap/servers/plugins/replication/cl5_config.c
@@ -390,6 +390,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
{
*returncode = LDAP_UNWILLING_TO_PERFORM;
@@ -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)
diff --git a/ldap/servers/plugins/replication/cl_crypt.c
b/ldap/servers/plugins/replication/cl_crypt.c
new file mode 100644
index 0000000..f950b3c
--- /dev/null
+++ b/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;
+}
diff --git a/ldap/servers/plugins/replication/cl_crypt.h
b/ldap/servers/plugins/replication/cl_crypt.h
new file mode 100644
index 0000000..a306e36
--- /dev/null
+++ b/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_ */
diff --git a/ldap/servers/plugins/replication/repl_shared.h
b/ldap/servers/plugins/replication/repl_shared.h
index 5cff861..99f785e 100644
--- a/ldap/servers/plugins/replication/repl_shared.h
+++ b/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
diff --git a/ldap/servers/plugins/replication/windows_protocol_util.c
b/ldap/servers/plugins/replication/windows_protocol_util.c
index 5fb6e7b..428f5f1 100644
--- a/ldap/servers/plugins/replication/windows_protocol_util.c
+++ b/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;
}
diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c
b/ldap/servers/slapd/back-ldbm/dblayer.c
index 3c9b5d6..39a214c 100644
--- a/ldap/servers/slapd/back-ldbm/dblayer.c
+++ b/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;
+}
diff --git a/ldap/servers/slapd/back-ldbm/id2entry.c
b/ldap/servers/slapd/back-ldbm/id2entry.c
index 57ada09..c509d3a 100644
--- a/ldap/servers/slapd/back-ldbm/id2entry.c
+++ b/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);
diff --git a/ldap/servers/slapd/back-ldbm/init.c b/ldap/servers/slapd/back-ldbm/init.c
index 5b3d9c8..c645444 100644
--- a/ldap/servers/slapd/back-ldbm/init.c
+++ b/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 );
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c
b/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c
index deb818d..88d78fc 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c
+++ b/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;
+}
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
index e09981a..c5df007 100644
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
+++ b/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);
/*
diff --git a/ldap/servers/slapd/backend.c b/ldap/servers/slapd/backend.c
index 9bdc0af..24993c1 100644
--- a/ldap/servers/slapd/backend.c
+++ b/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;
+}
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
index a2684f9..1f14341 100644
--- a/ldap/servers/slapd/opshared.c
+++ b/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",
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
index 4cc6536..2418b71 100644
--- a/ldap/servers/slapd/pblock.c
+++ b/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 );
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 1cb5212..d5ac772 100644
--- a/ldap/servers/slapd/slap.h
+++ b/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,
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 536809d..fd2bf11 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/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
}
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
index ef213f5..d9da346 100644
--- a/ldap/servers/slapd/slapi-private.h
+++ b/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. **************************************/