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@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@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 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. **************************************/
389-commits@lists.fedoraproject.org