andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
Blob Blame History Raw
From 9022d77690b7e932e7fddc9d4c354f52c9c8121f Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nhosoi@redhat.com>
Date: Thu, 2 Apr 2015 11:49:46 -0700
Subject: [PATCH 309/319] Ticket #561 - disable writing unhashed#user#password
 to changelog

Backported:
. commit c4bd52e2211c043087765f74df6cf6cd41b8f234
  Ticket #561 - disable writing unhashed#user#password to changelog

. commit da3be3fbf497775f608d1289f72cfe427850f950
  Fix optimization issue introduced with fix for ticket #561,

. commit 1d4f3ca2e931e6d930056aeb683256965503c5e1
  Fixing a compiler warning introduced by Ticket #561

. commit 84b8bfd7d18a0613920dce36f1d3775d75e45a3e
  Fix for CVE-2014-8112

Description:
Introducing a config parameter nsslapd-unhashed-pw-switch to cn=config.
The parameter takes 3 values:
  on    - unhashed password is stored in the entry extension
          and logged in the changelog.
  nolog - unhashed password is stored in the entry extension
          but not logged in the changelog.
  off   - unhashed password is not stored in the entry extension.

https://fedorahosted.org/389/ticket/561

(cherry picked from commit bb565bd8e664a22aed754af092121d293d2fee5d)
---
 ldap/servers/plugins/replication/cl5_api.c | 48 +++++++++++++----
 ldap/servers/plugins/retrocl/retrocl_po.c  |  6 +++
 ldap/servers/slapd/add.c                   | 13 ++---
 ldap/servers/slapd/libglobs.c              | 84 +++++++++++++++++++++++++++++-
 ldap/servers/slapd/modify.c                | 45 +++++++++-------
 ldap/servers/slapd/opshared.c              | 35 +++++--------
 ldap/servers/slapd/proto-slap.h            |  2 +
 ldap/servers/slapd/slap.h                  |  8 +--
 ldap/servers/slapd/slapi-plugin.h          |  8 +++
 ldap/servers/slapd/slapi-private.h         |  1 +
 ldap/servers/slapd/util.c                  | 11 ++--
 11 files changed, 194 insertions(+), 67 deletions(-)

diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
index ae522a3..0618d9b 100644
--- a/ldap/servers/plugins/replication/cl5_api.c
+++ b/ldap/servers/plugins/replication/cl5_api.c
@@ -322,7 +322,7 @@ static int _cl5Str2OperationType (const char *str);
 static void _cl5WriteString (const char *str, char **buff);
 static void _cl5ReadString (char **str, char **buff);
 static void _cl5WriteMods (LDAPMod **mods, char **buff);
-static void _cl5WriteMod (LDAPMod *mod, char **buff);
+static int _cl5WriteMod (LDAPMod *mod, char **buff);
 static int _cl5ReadMods (LDAPMod ***mods, char **buff);
 static int _cl5ReadMod (Slapi_Mod *mod, char **buff);
 static int _cl5GetModsSize (LDAPMod **mods);
@@ -2474,7 +2474,7 @@ static void _cl5WriteMods (LDAPMod **mods, char **buff)
 {	
 	PRInt32 i;
 	char *mod_start;
-	PRInt32 count;
+	PRInt32 count = 0;
 
 	if (mods == NULL)
 		return;
@@ -2483,30 +2483,49 @@ static void _cl5WriteMods (LDAPMod **mods, char **buff)
 	mod_start = (*buff) + sizeof (count);
 
 	/* write mods*/
-	for (i=0; mods[i]; i++)
-	{
-		_cl5WriteMod (mods[i], &mod_start);
+	for (i = 0; mods[i]; i++) {
+		if (0 <= _cl5WriteMod (mods[i], &mod_start)) {
+			count++;
+		}
 	}
 
-	count = PR_htonl(i);
+	count = PR_htonl(count);
 	memcpy (*buff, &count, sizeof (count));	
 	
 	(*buff) = mod_start;
 }
 
-static void _cl5WriteMod (LDAPMod *mod, char **buff)
+/*
+ * return values:
+ *     positive: no need to encrypt && succeeded to write a mod
+ *            0: succeeded to encrypt && write a mod
+ *     netative: failed to encrypt && no write to the changelog
+ */
+static int
+_cl5WriteMod (LDAPMod *mod, char **buff)
 {
+	char *orig_pos;
 	char *pos;
 	PRInt32 count;
 	struct berval *bv;
 	struct berval *encbv;
 	struct berval *bv_to_use;
 	Slapi_Mod smod;
-	int rc = 0;
+	int rc = -1;
+
+	if (NULL == mod) {
+		return rc;
+	}
+	if (SLAPD_UNHASHED_PW_NOLOG == slapi_config_get_unhashed_pw_switch()) {
+		if (0 == strcasecmp(mod->mod_type, PSEUDO_ATTR_UNHASHEDUSERPASSWORD)) {
+			/* If nsslapd-unhashed-pw-switch == nolog, skip writing it to cl. */
+			return rc;
+		}
+	}
 
 	slapi_mod_init_byref(&smod, mod);
 
-	pos = *buff;
+	orig_pos = pos = *buff;
 	/* write mod op */
 	*pos = (PRUint8)slapi_mod_get_operation (&smod);
 	pos ++;
@@ -2516,7 +2535,7 @@ static void _cl5WriteMod (LDAPMod *mod, char **buff)
 	/* write value count */
 	count = PR_htonl(slapi_mod_get_num_values(&smod));
 	memcpy (pos, &count, sizeof (count));
-	pos += sizeof (PRInt32);	
+	pos += sizeof (PRInt32);
 
 	bv = slapi_mod_get_first_value (&smod);
 	while (bv)
@@ -2536,6 +2555,8 @@ static void _cl5WriteMod (LDAPMod *mod, char **buff)
 						"_cl5WriteMod: encrypting \"%s: %s\" failed\n",
 						slapi_mod_get_type(&smod), bv->bv_val);
 			bv_to_use = NULL;
+			rc = -1;
+			break;
 		}
 		if (bv_to_use) {
 			_cl5WriteBerval (bv_to_use, &pos);
@@ -2544,9 +2565,14 @@ static void _cl5WriteMod (LDAPMod *mod, char **buff)
 		bv = slapi_mod_get_next_value (&smod);
 	}
 
-	(*buff) = pos;
+	if (rc < 0) {
+		(*buff) = orig_pos;
+	} else {
+		(*buff) = pos;
+	}
 
 	slapi_mod_done (&smod);
+	return rc;
 }
 
 /* mods format:
diff --git a/ldap/servers/plugins/retrocl/retrocl_po.c b/ldap/servers/plugins/retrocl/retrocl_po.c
index c3d1c41..3fdf887 100644
--- a/ldap/servers/plugins/retrocl/retrocl_po.c
+++ b/ldap/servers/plugins/retrocl/retrocl_po.c
@@ -101,6 +101,12 @@ static lenstr *make_changes_string(LDAPMod **ldm, const char **includeattrs)
 		continue;
 	    }
 	}
+	if (SLAPD_UNHASHED_PW_NOLOG == slapi_config_get_unhashed_pw_switch()) {
+		if (0 == strcasecmp(ldm[ i ]->mod_type, PSEUDO_ATTR_UNHASHEDUSERPASSWORD)) {
+			/* If nsslapd-unhashed-pw-switch == nolog, skip writing it to cl. */
+			continue;
+		}
+	}
 	switch ( ldm[ i ]->mod_op  & ~LDAP_MOD_BVALUES ) {
 	case LDAP_MOD_ADD:
 	    addlenstr( l, "add: " );
diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c
index f52f766..37060df 100644
--- a/ldap/servers/slapd/add.c
+++ b/ldap/servers/slapd/add.c
@@ -447,7 +447,6 @@ static void op_shared_add (Slapi_PBlock *pb)
 	int	err;
 	int internal_op, repl_op, legacy_op, lastmod;
 	char *pwdtype = NULL;
-	Slapi_Value **unhashed_password_vals = NULL;
 	Slapi_Attr *attr = NULL;
 	Slapi_Entry *referral;
 	char errorbuf[BUFSIZ];
@@ -545,6 +544,7 @@ static void op_shared_add (Slapi_PBlock *pb)
 		{
 			Slapi_Value **present_values;
 			present_values= attr_get_present_values(attr);
+			Slapi_Value **unhashed_password_vals = NULL;
 
 			/* Set the backend in the pblock.  The slapi_access_allowed function
 			 * needs this set to work properly. */
@@ -576,11 +576,13 @@ static void op_shared_add (Slapi_PBlock *pb)
 				add_password_attrs(pb, operation, e);
 				slapi_entry_attr_replace_sv(e, SLAPI_USERPWD_ATTR, vals);
 				valuearray_free(&vals);
-				
-				/* Add the unhashed password pseudo-attribute to the entry */
-				pwdtype = slapi_attr_syntax_normalize(PSEUDO_ATTR_UNHASHEDUSERPASSWORD);
-				slapi_entry_add_values_sv(e, pwdtype, unhashed_password_vals);
+				if (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch()) {
+					/* Add the unhashed password pseudo-attribute to the entry */
+					pwdtype = slapi_attr_syntax_normalize(PSEUDO_ATTR_UNHASHEDUSERPASSWORD);
+					slapi_entry_add_values_sv(e, pwdtype, unhashed_password_vals);
+				}
 			}
+			valuearray_free(&unhashed_password_vals);
 		}
 
        /* look for multiple backend local credentials or replication local credentials */
@@ -751,7 +753,6 @@ done:
 	slapi_ch_free((void **)&operation->o_params.p.p_add.parentuniqueid);
 	slapi_entry_free(e);
 	slapi_pblock_set(pb, SLAPI_ADD_ENTRY, NULL);
-	valuearray_free(&unhashed_password_vals);
 	slapi_ch_free((void**)&pwdtype);
 	slapi_ch_free_string(&proxydn);
 	slapi_ch_free_string(&proxystr);
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index 825dcee..dbb0fa8 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -121,7 +121,8 @@ typedef enum {
 	CONFIG_SPECIAL_ERRORLOGLEVEL, /* requires & with LDAP_DEBUG_ANY */
 	CONFIG_STRING_OR_EMPTY, /* use an empty string */
 	CONFIG_SPECIAL_ANON_ACCESS_SWITCH, /* maps strings to an enumeration */
-	CONFIG_SPECIAL_VALIDATE_CERT_SWITCH /* maps strings to an enumeration */
+	CONFIG_SPECIAL_VALIDATE_CERT_SWITCH, /* maps strings to an enumeration */
+	CONFIG_SPECIAL_UNHASHED_PW_SWITCH /* unhashed pw: on/off/nolog */
 } ConfigVarType;
 
 static int config_set_onoff( const char *attrname, char *value,
@@ -269,6 +270,7 @@ int init_mempool_switch;
 #define DEFAULT_SSLCLIENTAPTH "off"
 #define DEFAULT_ALLOW_ANON_ACCESS "on"
 #define DEFAULT_VALIDATE_CERT "warn"
+#define DEFAULT_UNHASHED_PW_SWITCH "on"
 
 static int
 isInt(ConfigVarType type)
@@ -1041,6 +1043,11 @@ static struct config_get_and_set {
 		NULL, 0,
 		(void**)&global_slapdFrontendConfig.ndn_cache_max_size,
 		CONFIG_INT, (ConfigGetFunc)config_get_ndn_cache_size},
+	{CONFIG_UNHASHED_PW_SWITCH_ATTRIBUTE, config_set_unhashed_pw_switch,
+		NULL, 0,
+		(void**)&global_slapdFrontendConfig.unhashed_pw_switch,
+		CONFIG_SPECIAL_UNHASHED_PW_SWITCH,
+		(ConfigGetFunc)config_get_unhashed_pw_switch}
 #ifdef MEMPOOL_EXPERIMENTAL
 	,{CONFIG_MEMPOOL_SWITCH_ATTRIBUTE, config_set_mempool_switch,
 		NULL, 0,
@@ -1459,6 +1466,7 @@ FrontendConfig_init () {
   cfg->disk_grace_period = 60; /* 1 hour */
   init_disk_logging_critical = cfg->disk_logging_critical = LDAP_OFF;
   cfg->sasl_max_bufsize = SLAPD_DEFAULT_SASL_MAXBUFSIZE;
+  cfg->unhashed_pw_switch = SLAPD_UNHASHED_PW_ON;
   init_listen_backlog_size = cfg->listen_backlog_size = DAEMON_LISTEN_SIZE;
   init_ignore_time_skew = cfg->ignore_time_skew = LDAP_OFF;
 
@@ -6552,7 +6560,6 @@ config_get_allowed_to_delete_attrs(void)
     return retVal;
 }
 
-
 int
 config_set_allowed_to_delete_attrs( const char *attrname, char *value,
                                     char *errorbuf, int apply )
@@ -6711,6 +6718,62 @@ config_initvalue_to_onoff(struct config_get_and_set *cgas, char *initvalbuf, siz
 	return retval;
 }
 
+int
+config_set_unhashed_pw_switch(const char *attrname, char *value,
+                              char *errorbuf, int apply)
+{
+    int retVal = LDAP_SUCCESS;
+    slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+    if (config_value_is_null(attrname, value, errorbuf, 0)) {
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    if ((strcasecmp(value, "on") != 0) && (strcasecmp(value, "off") != 0) &&
+        (strcasecmp(value, "nolog") != 0)) {
+        PR_snprintf(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+            "%s: invalid value \"%s\". Valid values are \"on\", "
+            "\"off\", or \"nolog\".", attrname, value);
+        retVal = LDAP_OPERATIONS_ERROR;
+    }
+
+    if (!apply) {
+        /* we can return now if we aren't applying the changes */
+        return retVal;
+    }
+
+    CFG_LOCK_WRITE(slapdFrontendConfig);
+
+    if (strcasecmp(value, "on") == 0 ) {
+        slapdFrontendConfig->unhashed_pw_switch = SLAPD_UNHASHED_PW_ON;
+    } else if (strcasecmp(value, "off") == 0 ) {
+        slapdFrontendConfig->unhashed_pw_switch = SLAPD_UNHASHED_PW_OFF;
+    } else if (strcasecmp(value, "nolog") == 0) {
+        slapdFrontendConfig->unhashed_pw_switch = SLAPD_UNHASHED_PW_NOLOG;
+    }
+
+    CFG_UNLOCK_WRITE(slapdFrontendConfig);
+    return retVal;
+}
+
+int
+slapi_config_get_unhashed_pw_switch()
+{
+    return config_get_unhashed_pw_switch();
+}
+
+int
+config_get_unhashed_pw_switch()
+{
+    int retVal = 0;
+    slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+    CFG_LOCK_READ(slapdFrontendConfig);
+    retVal = slapdFrontendConfig->unhashed_pw_switch;
+    CFG_UNLOCK_READ(slapdFrontendConfig);
+
+    return retVal;
+}
+
 /*
  * This function is intended to be used from the dse code modify callback.  It
  * is "optimized" for that case because it takes a berval** of values, which is
@@ -6931,6 +6994,23 @@ config_set_value(
         slapi_entry_attr_set_charptr(e, cgas->attr_name, sval);
         break;
 
+    case CONFIG_SPECIAL_UNHASHED_PW_SWITCH:
+        if (!value) {
+            slapi_entry_attr_set_charptr(e, cgas->attr_name, "on");
+            break;
+        }
+
+        if (*((int *)value) == SLAPD_UNHASHED_PW_OFF) {
+            sval = "off";
+        } else if (*((int *)value) == SLAPD_UNHASHED_PW_NOLOG) {
+            sval = "nolog";
+        } else {
+            sval = "on";
+        }
+        slapi_entry_attr_set_charptr(e, cgas->attr_name, sval);
+
+        break;
+
     case CONFIG_SPECIAL_VALIDATE_CERT_SWITCH:
         if (!value) {
             slapi_entry_attr_set_charptr(e, cgas->attr_name, "off");
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
index 9c6610f..c67ef14 100644
--- a/ldap/servers/slapd/modify.c
+++ b/ldap/servers/slapd/modify.c
@@ -894,13 +894,15 @@ static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw)
 						/*
 						 *  Finally, delete the unhashed userpassword
 						 */
-						bval.bv_val = password;
-						bval.bv_len = strlen(password);
-						bv[0] = &bval;
-						bv[1] = NULL;
-						valuearray_init_bervalarray(bv, &va);
-						slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
-						valuearray_free(&va);
+						if (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch()) {
+							bval.bv_val = password;
+							bval.bv_len = strlen(password);
+							bv[0] = &bval;
+							bv[1] = NULL;
+							valuearray_init_bervalarray(bv, &va);
+							slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
+							valuearray_free(&va);
+						}
 					} else {
 						/*
 						 *  Password is encoded, try and find a matching unhashed_password to delete
@@ -924,28 +926,31 @@ static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw)
 								bval.bv_len = strlen(unhashed_pwd);
 								bv[0] = &bval;
 								bv[1] = NULL;
-
 								/*
 								 *  Compare the clear text unhashed password, to the encoded password
 								 *  provided by the client.
 								 */
-								unhashed_pwsp = pw_val2scheme( unhashed_pwd, NULL, 1 );
+								unhashed_pwsp = pw_val2scheme( (char *)unhashed_pwd, NULL, 1 );
 								if(strcmp(unhashed_pwsp->pws_name, "CLEAR") == 0){
-									if((*(pwsp->pws_cmp))(unhashed_pwd , valpwd) == 0 ){
+									if((*(pwsp->pws_cmp))((char *)unhashed_pwd , valpwd) == 0 ){
 										/* match, add the delete mod for this particular unhashed userpassword */
-										valuearray_init_bervalarray(bv, &va);
-										slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
-										valuearray_free(&va);
-										free_pw_scheme( unhashed_pwsp );
+										if (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch()) {
+										    valuearray_init_bervalarray(bv, &va);
+										    slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
+										    valuearray_free(&va);
+										    free_pw_scheme( unhashed_pwsp );
+										}
 										break;
 									}
 								} else {
 									/*
 									 *  We have a hashed unhashed_userpassword!  We must delete it.
 									 */
-									valuearray_init_bervalarray(bv, &va);
-									slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
-									valuearray_free(&va);
+									if (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch()) {
+										valuearray_init_bervalarray(bv, &va);
+										slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
+										valuearray_free(&va);
+									}
 								}
 								free_pw_scheme( unhashed_pwsp );
 							}
@@ -958,13 +963,13 @@ static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw)
 				if (remove_unhashed_pw && !slapi_entry_attr_find(e, unhashed_pw_attr, &a)){
 					slapi_mods_add_mod_values(&smods, pw_mod->mod_op,unhashed_pw_attr, va);
 				}
-			} else {
-				/* add pseudo password attribute - only if it's value is clear text */
+			} else if (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch()) {
+				/* add pseudo password attribute */
 				valuearray_init_bervalarray_unhashed_only(pw_mod->mod_bvalues, &va);
 				if(va && va[0]){
 					slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
 				}
-                                valuearray_free(&va);
+				valuearray_free(&va);
 			}
 
 			/* Init new value array for hashed value */
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
index a7367a7..bef19d1 100644
--- a/ldap/servers/slapd/opshared.c
+++ b/ldap/servers/slapd/opshared.c
@@ -52,10 +52,7 @@
 static void compute_limits (Slapi_PBlock *pb);
 
 /* attributes that no clients are allowed to add or modify */
-/* 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 *protected_attrs_all [] = { PSEUDO_ATTR_UNHASHEDUSERPASSWORD, NULL };
 static char *pwpolicy_lock_attrs_all [] = { "passwordRetryCount",
                                             "retryCountResetTime",
                                             "accountUnlockTime",
@@ -70,30 +67,26 @@ int op_shared_is_allowed_attr (const char *attr_name, int replicated_op)
     int                 i;
     slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
 
-    /* check list of attributes that no client is allowed to specify */
-    for (i = 0; protected_attrs_all[i]; i ++)
-    {
-        if (strcasecmp (attr_name, protected_attrs_all[i]) == 0)
-        {
-            /* this attribute is not allowed */
-            return 0;
-        }
-    }
-
     /* ONREPL - should allow backends to plugin here to specify 
                 attributes that are not allowed */
 
-    if (!replicated_op)
-    {
-        /*
-         * check to see if attribute is marked as one clients can't modify
-         */
+    if (!replicated_op) {
         struct asyntaxinfo    *asi;
         int                    no_user_mod = 0;
 
+        /* check list of attributes that no client is allowed to specify */
+        for (i = 0; protected_attrs_all[i]; i ++) {
+            if (strcasecmp (attr_name, protected_attrs_all[i]) == 0) {
+                /* this attribute is not allowed */
+                return 0;
+            }
+        }
+        /*
+         * check to see if attribute is marked as one clients can't modify
+         */
         asi = attr_syntax_get_by_name( attr_name, 0 );
         if ( NULL != asi &&
-                0 != ( asi->asi_flags & SLAPI_ATTR_FLAG_NOUSERMOD ))
+             0 != ( asi->asi_flags & SLAPI_ATTR_FLAG_NOUSERMOD ))
         {
             /* this attribute is not allowed */
             no_user_mod = 1;
@@ -187,7 +180,7 @@ modify_update_last_modified_attr(Slapi_PBlock *pb, Slapi_Mods *smods)
             /* anonymous bind */
             bv.bv_val = "";
             bv.bv_len = strlen(bv.bv_val);
-   	    } else {
+        } else {
             bv.bv_val = binddn;
             bv.bv_len = strlen(bv.bv_val);
         }
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index da9c925..c497c14 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -403,6 +403,7 @@ int config_set_malloc_mmap_threshold(const char *attrname, char *value, char *er
 
 int config_set_ndn_cache_enabled(const char *attrname, char *value, char *errorbuf, int apply);
 int config_set_ndn_cache_max_size(const char *attrname, char *value, char *errorbuf, int apply);
+int config_set_unhashed_pw_switch(const char *attrname, char *value, char *errorbuf, int apply);
 
 
 #if !defined(_WIN32) && !defined(AIX)
@@ -572,6 +573,7 @@ int config_get_malloc_mmap_threshold();
 int config_get_ndn_cache_count();
 size_t config_get_ndn_cache_size();
 int config_get_ndn_cache_enabled();
+int config_get_unhashed_pw_switch();
 PLHashNumber hashNocaseString(const void *key);
 PRIntn hashNocaseCompare(const void *v1, const void *v2);
 
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 70e8a51..c298033 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -306,9 +306,6 @@ typedef void	(*VFPV)(); /* takes undefined arguments */
 
 #define ATTR_NETSCAPEMDSUFFIX "netscapemdsuffix"
 
-/* Used to make unhashed passwords available to plugins. */
-#define	PSEUDO_ATTR_UNHASHEDUSERPASSWORD	"unhashed#user#password"
-
 #define REFERRAL_REMOVE_CMD "remove"
 
 /* Filenames for DSE storage */
@@ -339,6 +336,8 @@ typedef void	(*VFPV)(); /* takes undefined arguments */
 #define SLAPD_VALIDATE_CERT_ON          1
 #define SLAPD_VALIDATE_CERT_WARN        2
 
+typedef int slapi_onoff_t;
+
 struct subfilt {
 	char	*sf_type;
 	char	*sf_initial;
@@ -1891,6 +1890,7 @@ typedef struct _slapdEntryPoints {
 #define CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-errorlog-logging-enabled"
 #define CONFIG_AUDITLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-auditlog-logging-enabled"
 #define CONFIG_AUDITLOG_LOGGING_HIDE_UNHASHED_PW "nsslapd-auditlog-logging-hide-unhashed-pw"
+#define CONFIG_UNHASHED_PW_SWITCH_ATTRIBUTE "nsslapd-unhashed-pw-switch"
 #define CONFIG_ROOTDN_ATTRIBUTE "nsslapd-rootdn"
 #define CONFIG_ROOTPW_ATTRIBUTE "nsslapd-rootpw"
 #define CONFIG_ROOTPWSTORAGESCHEME_ATTRIBUTE "nsslapd-rootpwstoragescheme"
@@ -2277,7 +2277,7 @@ typedef struct _slapdFrontendConfig {
   PRInt64 disk_threshold;
   int disk_grace_period;
   int disk_logging_critical;
-
+  slapi_onoff_t unhashed_pw_switch;	/* switch to on/off/nolog unhashed pw */
   int ignore_time_skew;
 #if defined(LINUX)
   int malloc_mxfast;            /* mallopt M_MXFAST */
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index e02127d..5c737ad 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -7057,6 +7057,14 @@ char **slapi_str2charray_ext( char *str, char *brkstr, int allow_dups );
 #endif
 #endif
 
+/* Used to make unhashed passwords available to plugins. */
+#define	PSEUDO_ATTR_UNHASHEDUSERPASSWORD	"unhashed#user#password"
+
+/* Unhashed password */
+#define SLAPD_UNHASHED_PW_OFF           0
+#define SLAPD_UNHASHED_PW_ON            1
+#define SLAPD_UNHASHED_PW_NOLOG         2
+
 /**
  * Set given "type: value" to the plugin default config entry
  * (cn=plugin default config,cn=config) unless the same "type: value" pair
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
index 18f0e94..9a4e339 100644
--- a/ldap/servers/slapd/slapi-private.h
+++ b/ldap/servers/slapd/slapi-private.h
@@ -816,6 +816,7 @@ int pw_rever_decode(char *cipher, char **plain, const char * attr_name);
 /* config routines */
 
 int slapi_config_get_readonly();
+int slapi_config_get_unhashed_pw_switch();
 
 /*
  * charray.c
diff --git a/ldap/servers/slapd/util.c b/ldap/servers/slapd/util.c
index 7a753f8..8c0b7ee 100644
--- a/ldap/servers/slapd/util.c
+++ b/ldap/servers/slapd/util.c
@@ -325,13 +325,15 @@ int slapi_mods2entry (Slapi_Entry **e, const char *idn, LDAPMod **iattrs)
     return rc;
 }
 
-int slapi_entry2mods (const Slapi_Entry *e, char **dn, LDAPMod ***attrs)
+int
+slapi_entry2mods (const Slapi_Entry *e, char **dn, LDAPMod ***attrs)
 {
 	Slapi_Mods smods;
 	Slapi_Attr *attr;
 	Slapi_Value **va;
 	char *type;
 	int rc;
+	int unhashed_pw_on = (SLAPD_UNHASHED_PW_ON == config_get_unhashed_pw_switch());
 
 	PR_ASSERT (e && attrs);
 
@@ -343,8 +345,11 @@ int slapi_entry2mods (const Slapi_Entry *e, char **dn, LDAPMod ***attrs)
 	while (rc == 0)
 	{
 		if ( NULL != ( va = attr_get_present_values( attr ))) {
-			slapi_attr_get_type(attr, &type);		
-			slapi_mods_add_mod_values(&smods, LDAP_MOD_ADD, type, va );
+			slapi_attr_get_type(attr, &type);
+			if (unhashed_pw_on || strcasecmp(type, PSEUDO_ATTR_UNHASHEDUSERPASSWORD)) {
+				/* SLAPD_UNHASHED_PW_ON or type is not unhashed pw */
+				slapi_mods_add_mod_values(&smods, LDAP_MOD_ADD, type, va );
+			}
 		}
 		rc = slapi_entry_next_attr(e, attr, &attr);
 	}
-- 
1.9.3