From 1be3c55232b03284a632955b40397e9c4bbc390c Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nhosoi@totoro.usersys.redhat.com>
Date: Tue, 19 Feb 2013 13:38:23 -0800
Subject: [PATCH 1/2] Ticket #561 - disable writing unhashed#user#password to
 changelog

Fix description: unhashed password was introduced to give an
opportunity to get the unhashed password to plugins.  But it
is not always needed.  If it is not, it is preferable to
disable the functionality.

1) Ticket #402 "unhashed#user#password in entry extension"
   switched the way how the unhashed password is stored.
   It used to be put in the attribute list in the entry.
   The patch changed it to store in the entry extension.
   To provide the migration period, it has been stored in
   the both places.  This patch is disabling the old
   attribute list method.
2) 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.
3) As reported in the ticket #577 "Attribute name unhashed#user
   #password is not valid per RFC 4512", the pseudo attribute
   type is violating the RFC.  Once, disabling to store it in
   the attribute list in the entry, the OID is not needed in
   the schema any more.  Thus, the pseudo attribute type is
   eliminated from the schema.
---
 configure.ac                               |    2 +-
 ldap/servers/plugins/replication/cl5_api.c |   48 +++++++++++++----
 ldap/servers/slapd/add.c                   |    3 +-
 ldap/servers/slapd/entry.c                 |    6 +--
 ldap/servers/slapd/libglobs.c              |   79 +++++++++++++++++++++++++++-
 ldap/servers/slapd/modify.c                |    6 +-
 ldap/servers/slapd/opshared.c              |   35 +++++--------
 ldap/servers/slapd/proto-slap.h            |    2 +
 ldap/servers/slapd/pw_mgmt.c               |    3 +-
 ldap/servers/slapd/slap.h                  |    8 ++--
 ldap/servers/slapd/slapi-plugin.h          |    8 +++
 ldap/servers/slapd/util.c                  |   22 +++++---
 12 files changed, 163 insertions(+), 59 deletions(-)

diff --git a/configure.ac b/configure.ac
index 975961c..c6edbfa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -686,7 +686,7 @@ AC_SUBST(brand)
 AC_SUBST(capbrand)
 AC_SUBST(vendor)
 
-AC_DEFINE([USE_OLD_UNHASHED], [1], [Use old unhashed code])
+# AC_DEFINE([USE_OLD_UNHASHED], [], [Use old unhashed code])
 AC_DEFINE([LDAP_DEBUG], [1], [LDAP debug flag])
 AC_DEFINE([LDAP_DONT_USE_SMARTHEAP], [1], [Don't use smartheap])
 
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
index 175eb80..934761b 100644
--- a/ldap/servers/plugins/replication/cl5_api.c
+++ b/ldap/servers/plugins/replication/cl5_api.c
@@ -323,7 +323,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);
@@ -2475,7 +2475,7 @@ static void _cl5WriteMods (LDAPMod **mods, char **buff)
 {	
 	PRInt32 i;
 	char *mod_start;
-	PRInt32 count;
+	PRInt32 count = 0;
 
 	if (mods == NULL)
 		return;
@@ -2484,30 +2484,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 == 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 ++;
@@ -2517,7 +2536,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)
@@ -2537,6 +2556,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);
@@ -2545,9 +2566,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/slapd/add.c b/ldap/servers/slapd/add.c
index 2a70f64..b2319fa 100644
--- a/ldap/servers/slapd/add.c
+++ b/ldap/servers/slapd/add.c
@@ -600,7 +600,8 @@ static void op_shared_add (Slapi_PBlock *pb)
 #endif
 			}
 		}
-		if (unhashed_password_vals) {
+		if (unhashed_password_vals &&
+		    (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch())) {
 			/* unhashed_password_vals is consumed if successful. */
 			err = slapi_pw_set_entry_ext(e, unhashed_password_vals,
 			                             SLAPI_EXT_SET_ADD);
diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c
index 14befbd..a9db945 100644
--- a/ldap/servers/slapd/entry.c
+++ b/ldap/servers/slapd/entry.c
@@ -66,16 +66,12 @@ static int _entry_set_tombstone_rdn(Slapi_Entry *e, const char *normdn);
 
 /* protected attributes which are not included in the flattened entry,
  * which will be stored in the db. */
-#if defined(USE_OLD_UNHASHED)
 static char *protected_attrs_all [] = {PSEUDO_ATTR_UNHASHEDUSERPASSWORD,
                                        SLAPI_ATTR_ENTRYDN,
                                        NULL};
-
+#if defined(USE_OLD_UNHASHED)
 static char *forbidden_attrs [] = {PSEUDO_ATTR_UNHASHEDUSERPASSWORD,
                                    NULL};
-#else
-static char *protected_attrs_all [] = {SLAPI_ATTR_ENTRYDN,
-                                       NULL};
 #endif
 /* Attributes which are put into the entry extension */
 struct attrs_in_extension attrs_in_extension[] =
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index 4737131..7a50720 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -117,7 +117,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,
@@ -259,6 +260,7 @@ slapi_onoff_t 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)
@@ -1020,6 +1022,12 @@ static struct config_get_and_set {
 		NULL, 0,
 		(void**)&global_slapdFrontendConfig.ignore_vattrs,
 		CONFIG_STRING, (ConfigGetFunc)config_get_ignore_vattrs, DEFAULT_ALLOWED_TO_DELETE_ATTRS},
+	{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, 
+		DEFAULT_UNHASHED_PW_SWITCH},
 #ifdef MEMPOOL_EXPERIMENTAL
 	,{CONFIG_MEMPOOL_SWITCH_ATTRIBUTE, config_set_mempool_switch,
 		NULL, 0,
@@ -1449,6 +1457,7 @@ FrontendConfig_init () {
   cfg->ignore_vattrs = slapi_counter_new();
   cfg->sasl_mapping_fallback = slapi_counter_new();
   init_sasl_mapping_fallback = LDAP_OFF;
+  cfg->unhashed_pw_switch = SLAPD_UNHASHED_PW_ON;
 
 #ifdef MEMPOOL_EXPERIMENTAL
   init_mempool_switch = cfg->mempool_switch = LDAP_ON;
@@ -6585,7 +6594,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 )
@@ -6748,6 +6756,56 @@ config_set_default_naming_context(const char *attrname,
     return LDAP_SUCCESS;
 }
 
+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
+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
@@ -6962,6 +7020,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 867e391..49f2324 100644
--- a/ldap/servers/slapd/modify.c
+++ b/ldap/servers/slapd/modify.c
@@ -825,9 +825,9 @@ static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw)
 	 * before calling the preop plugins
 	 */
 
-	if (pw_change && !repl_op)
-	{
-		Slapi_Value **va= NULL;
+	if (pw_change && !repl_op &&
+	    (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch())) {
+		Slapi_Value **va = NULL;
 
 		unhashed_pw_attr = slapi_attr_syntax_normalize(PSEUDO_ATTR_UNHASHEDUSERPASSWORD);
 
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
index cadf3b7..1f94a57 100644
--- a/ldap/servers/slapd/opshared.c
+++ b/ldap/servers/slapd/opshared.c
@@ -52,12 +52,7 @@
 static void compute_limits (Slapi_PBlock *pb);
 
 /* attributes that no clients are allowed to add or modify */
-#if defined(USE_OLD_UNHASHED)
-/* 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)*/
-#endif
-static char *protected_attrs_all [] = { NULL };
+static char *protected_attrs_all [] = { PSEUDO_ATTR_UNHASHEDUSERPASSWORD };
 static char *pwpolicy_lock_attrs_all [] = { "passwordRetryCount",
                                             "retryCountResetTime",
                                             "accountUnlockTime",
@@ -72,31 +67,27 @@ 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)
-    {
+    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
          */
-        struct asyntaxinfo    *asi;
-        int                    no_user_mod = 0;
 
         asi = attr_syntax_get_by_name( attr_name );
         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;
         }
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 169feb3..0a07a29 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -393,6 +393,7 @@ int config_set_disk_logging_critical( const char *attrname, char *value, char *e
 int config_set_auditlog_unhashed_pw(const char *attrname, char *value, char *errorbuf, int apply);
 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)
 int config_set_maxdescriptors( const char *attrname, char *value, char *errorbuf, int apply );
@@ -558,6 +559,7 @@ int config_set_ignore_vattrs(const char *attrname, char *value, char *errorbuf,
 int config_get_ignore_vattrs();
 int config_set_sasl_mapping_fallback(const char *attrname, char *value, char *errorbuf, int apply);
 int config_get_sasl_mapping_fallback();
+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/pw_mgmt.c b/ldap/servers/slapd/pw_mgmt.c
index 05ecae1..8e8d850 100644
--- a/ldap/servers/slapd/pw_mgmt.c
+++ b/ldap/servers/slapd/pw_mgmt.c
@@ -299,7 +299,7 @@ pw_init ( void )
 	slapdFrontendConfig = getFrontendConfig();
 	pw_mod_allowchange_aci (!slapdFrontendConfig->pw_policy.pw_change && 
                             !slapdFrontendConfig->pw_policy.pw_must_change);
-
+#if defined(USE_OLD_UNHASHED)
 	slapi_add_internal_attr_syntax( PSEUDO_ATTR_UNHASHEDUSERPASSWORD,
 	                                PSEUDO_ATTR_UNHASHEDUSERPASSWORD_OID,
 	                                OCTETSTRING_SYNTAX_OID, 0, 
@@ -307,6 +307,7 @@ pw_init ( void )
 	                                 * PSEUDO_ATTR_UNHASHEDUSERPASSWORD */
 	                                SLAPI_ATTR_FLAG_NOUSERMOD|
 	                                SLAPI_ATTR_FLAG_NOEXPOSE);
+#endif
 }
 
 
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 1b1bc37..a44bced 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 */
@@ -1938,6 +1935,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"
@@ -2306,6 +2304,7 @@ typedef struct _slapdFrontendConfig {
   /* atomic settings */
   Slapi_Counter *ignore_vattrs;
   Slapi_Counter *sasl_mapping_fallback;
+  slapi_onoff_t unhashed_pw_switch;	/* switch to on/off/nolog unhashed pw */
 } slapdFrontendConfig_t;
 
 /* possible values for slapdFrontendConfig_t.schemareplace */
@@ -2411,8 +2410,9 @@ extern char	*attr_dataversion;
 
 #define MTN_CONTROL_USE_ONE_BACKEND_OID	"2.16.840.1.113730.3.4.14"
 #define MTN_CONTROL_USE_ONE_BACKEND_EXT_OID	"2.16.840.1.113730.3.4.20"
-
+#if defined(USE_OLD_UNHASHED)
 #define PSEUDO_ATTR_UNHASHEDUSERPASSWORD_OID "2.16.840.1.113730.3.1.2110"
+#endif
 
 /* virtualListViewError is a relatively new concept that was added long 
  * after we implemented VLV. Until added to LDAP SDK, we define 
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 73ae477..127cbcd 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -7020,6 +7020,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/util.c b/ldap/servers/slapd/util.c
index bdff366..3c715ec 100644
--- a/ldap/servers/slapd/util.c
+++ b/ldap/servers/slapd/util.c
@@ -616,7 +616,8 @@ 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;
@@ -634,20 +635,23 @@ 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_attr_get_type(attr, &type);
 			slapi_mods_add_mod_values(&smods, LDAP_MOD_ADD, type, va );
 		}
 		rc = slapi_entry_next_attr(e, attr, &attr);
 	}
 
 #if !defined(USE_OLD_UNHASHED)
-	/* In case USE_OLD_UNHASHED, unhashed pw is already in mods */
-	/* add extension to mods */
-	rc = slapi_pw_get_entry_ext((Slapi_Entry *)e, &va);
-	if (LDAP_SUCCESS == rc) {
-		/* va is copied and set to smods */
-		slapi_mods_add_mod_values(&smods, LDAP_MOD_ADD,
-		                          PSEUDO_ATTR_UNHASHEDUSERPASSWORD, va);
+	if (SLAPD_UNHASHED_PW_ON == config_get_unhashed_pw_switch()) {
+		/* store unhashed passwd is enabled */
+		/* In case USE_OLD_UNHASHED, unhashed pw is already in mods */
+		/* add extension to mods */
+		rc = slapi_pw_get_entry_ext((Slapi_Entry *)e, &va);
+		if (LDAP_SUCCESS == rc) {
+			/* va is copied and set to smods */
+			slapi_mods_add_mod_values(&smods, LDAP_MOD_ADD,
+			                          PSEUDO_ATTR_UNHASHEDUSERPASSWORD, va);
+		}
 	}
 #endif
 
-- 
1.7.7.6

