>From f9ec9a62b8e386c7918b0b9ea628023ed9bd505e Mon Sep 17 00:00:00 2001
From: Nathan Kinder <nkinder@redhat.com>
Date: Tue, 1 Dec 2009 16:27:23 -0800
Subject: [PATCH] Bug 195302 - Allow fine-grained password storage scheme to be set

This patch makes the server use the password storage scheme set in
the appropriate fine-grained password policy (if it is set).  The
previous code was always using the global storage scheme.

This fix was based off of a fix contributed by Ulf Weltman of
Hewlett Packard.
---
 ldap/servers/slapd/add.c          |   10 +++-
 ldap/servers/slapd/modify.c       |   10 +++-
 ldap/servers/slapd/pw.c           |  100 +++++++++++++++++++++++++++---------
 ldap/servers/slapd/pw.h           |    9 +++-
 ldap/servers/slapd/slap.h         |    9 +++-
 ldap/servers/slapd/slapi-plugin.h |   11 ++++-
 6 files changed, 117 insertions(+), 32 deletions(-)

diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c
index df683a9..1a1f867 100644
--- a/ldap/servers/slapd/add.c
+++ b/ldap/servers/slapd/add.c
@@ -32,8 +32,14 @@
  * 
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
+ *
+ * Contributors:
+ *   Hewlett-Packard Development Company, L.P.
+ *     Bugfix for bug #195302
+ *
  * END COPYRIGHT BLOCK **/
 
 #ifdef HAVE_CONFIG_H
@@ -512,7 +518,7 @@ static void op_shared_add (Slapi_PBlock *pb)
 				Slapi_Value **vals= NULL;
 				valuearray_add_valuearray(&unhashed_password_vals, present_values, 0);
 				valuearray_add_valuearray(&vals, present_values, 0);
-				pw_encodevals(vals);			
+				pw_encodevals_ext(pb, slapi_entry_get_sdn (e), vals);
 				add_password_attrs(pb, operation, e);
 				slapi_entry_attr_replace_sv(e, SLAPI_USERPWD_ATTR, vals);
 				valuearray_free(&vals);
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
index 1eac848..40646b2 100644
--- a/ldap/servers/slapd/modify.c
+++ b/ldap/servers/slapd/modify.c
@@ -32,8 +32,14 @@
  * 
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
+ *
+ * Contributors:
+ *   Hewlett-Packard Development Company, L.P.
+ *     Bugfix for bug #195302
+ *
  * END COPYRIGHT BLOCK **/
 
 #ifdef HAVE_CONFIG_H
@@ -712,7 +718,7 @@ static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw)
 			valuearray_init_bervalarray(pw_mod->mod_bvalues, &va);
 
 			/* encode password */
-			pw_encodevals(va);
+			pw_encodevals_ext(pb, &sdn, va);
 
 			/* remove current clear value of userpassword */
 			ber_bvecfree(pw_mod->mod_bvalues);
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
index cafdfd6..09bb96c 100644
--- a/ldap/servers/slapd/pw.c
+++ b/ldap/servers/slapd/pw.c
@@ -32,8 +32,14 @@
  * 
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
+ *
+ * Contributors:
+ *   Hewlett-Packard Development Company, L.P.
+ *     Bugfix for bug #195302
+ *
  * END COPYRIGHT BLOCK **/
 
 #ifdef HAVE_CONFIG_H
@@ -177,17 +183,23 @@ int slapi_is_encoded (char *value)
 
 char* slapi_encode (char *value, char *alg)
 {
+	return( slapi_encode_ext( NULL, NULL, value, alg ) );
+}
+
+char* slapi_encode_ext (Slapi_PBlock *pb, const Slapi_DN *sdn, char *value, char *alg)
+{
 	struct pw_scheme *enc_scheme = NULL;
+	char *(*pws_enc) ( char *pwd ) = NULL;
 	char *hashedval = NULL;
-	int need_to_free = 0;
+	passwdPolicy *pwpolicy=NULL;
 
-	if (alg == NULL) /* use server encoding scheme */
+	if (alg == NULL) /* use local scheme, or global if we can't fetch local */
 	{
-		slapdFrontendConfig_t * slapdFrontendConfig = getFrontendConfig();
-		
-		enc_scheme = slapdFrontendConfig->pw_storagescheme;
+		pwpolicy = new_passwdPolicy(pb, (char*)slapi_sdn_get_ndn(sdn) );
+		pws_enc = pwpolicy->pw_storagescheme->pws_enc;
+		delete_passwdPolicy(&pwpolicy);
 
-		if (enc_scheme == NULL)
+		if (pws_enc == NULL)
 		{
 			slapi_log_error( SLAPI_LOG_FATAL, NULL, 
 							"slapi_encode: no server scheme\n" );
@@ -212,12 +224,11 @@ char* slapi_encode (char *value, char *alg)
 			}
 			return NULL;
 		}
-		need_to_free = 1;
+		pws_enc = enc_scheme->pws_enc;
+		free_pw_scheme(enc_scheme);
 	}
 	
-	hashedval = enc_scheme->pws_enc(value);
-	if (need_to_free)
-		free_pw_scheme(enc_scheme);	
+	hashedval = (*pws_enc)(value);
 
 	return hashedval;
 }
@@ -318,18 +329,39 @@ pw_val2scheme( char *val, char **valpwdp, int first_is_default )
 int
 pw_encodevals( Slapi_Value **vals )
 {
+	return( pw_encodevals_ext( NULL, NULL, vals ) );
+}
+
+/*
+ * Same as pw_encodevals, except if a pb and sdn are passed in, we will try
+ * to check the password scheme specified by local password policy.
+ */
+int
+pw_encodevals_ext( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals )
+{
 	int	i;
-	slapdFrontendConfig_t * slapdFrontendConfig = getFrontendConfig();
+	passwdPolicy *pwpolicy=NULL;
+	char *dn;
+	char *(*pws_enc) ( char *pwd ) = NULL;
 
+	if ( vals == NULL ) {
+		return( 0 );
+	}
+ 
+	/* new_passwdPolicy gives us a local policy if sdn and pb are set and
+	   can be used to find a local policy, else we get the global policy */
+   	pwpolicy = new_passwdPolicy(pb, (char*)slapi_sdn_get_ndn(sdn) );
+	pws_enc = pwpolicy->pw_storagescheme->pws_enc;
+	delete_passwdPolicy(&pwpolicy);
 
-	if ( vals == NULL || slapdFrontendConfig->pw_storagescheme == NULL ||
-	   slapdFrontendConfig->pw_storagescheme->pws_enc == NULL ) {
+	/* Password scheme encryption function was not found */
+	if ( pws_enc == NULL ) {
 		return( 0 );
 	}
 
 	for ( i = 0; vals[ i ] != NULL; ++i ) {
-		struct pw_scheme    *pwsp;
-		char	*enc = NULL;
+		struct pw_scheme *pwsp = NULL;
+		char *enc = NULL;
 		if ( (pwsp=pw_val2scheme( (char*)slapi_value_get_string(vals[ i ]), NULL, 0)) != NULL ) { /* JCM Innards */
 			/* If the value already specifies clear storage, call the
 			 * clear storage plug-in */
@@ -340,14 +372,14 @@ pw_encodevals( Slapi_Value **vals )
 				continue;	/* don't touch pre-encoded values */
 			}
 		}
-		if ((!enc) && (( enc = (*slapdFrontendConfig->pw_storagescheme->pws_enc)( (char*)slapi_value_get_string(vals[ i ]) )) /* JCM Innards */
-		    == NULL )) {
-			free_pw_scheme( pwsp );
+		free_pw_scheme( pwsp );
+
+		if ((!enc) && (( enc = (*pws_enc)( (char*)slapi_value_get_string(vals[ i ]) )) == NULL )) {
 			return( -1 );
 		}
+
                 slapi_value_free(&vals[ i ]);
                 vals[ i ] = slapi_value_new_string_passin(enc);
-		free_pw_scheme( pwsp );
 	}
 
 	return( 0 );
@@ -1460,6 +1492,7 @@ new_passwdPolicy(Slapi_PBlock *pb, char *dn)
 	int attr_free_flags = 0;
 	int rc=0;
 	passwdPolicy *pwdpolicy = NULL;
+	struct pw_scheme *pwdscheme = NULL;
 	Slapi_Attr *attr;
 	char *attr_name;
 	Slapi_Value **sval;
@@ -1471,10 +1504,12 @@ new_passwdPolicy(Slapi_PBlock *pb, char *dn)
 	slapdFrontendConfig = getFrontendConfig();
 	pwdpolicy = (passwdPolicy *)slapi_ch_calloc(1, sizeof(passwdPolicy));
 
-	slapi_pblock_get( pb, SLAPI_OPERATION, &op);
-	slapi_pblock_get( pb, SLAPI_OPERATION_TYPE, &optype );
+	if (pb) {
+		slapi_pblock_get( pb, SLAPI_OPERATION, &op);
+		slapi_pblock_get( pb, SLAPI_OPERATION_TYPE, &optype );
+	}
 
-	if (dn && (slapdFrontendConfig->pwpolicy_local == 1)) {
+	if (pb && dn && (slapdFrontendConfig->pwpolicy_local == 1)) {
 		/*  If we're doing an add, COS does not apply yet so we check
 			parents for the pwdpolicysubentry.  We look only for virtual
 			attributes, because real ones are for single-target policy. */
@@ -1701,13 +1736,20 @@ new_passwdPolicy(Slapi_PBlock *pb, char *dn)
 						pwdpolicy->pw_gracelimit = slapi_value_get_int(*sval);
 					}
 				}
+				else
+				if (!strcasecmp(attr_name, "passwordstoragescheme")) {
+					if ((sval = attr_get_present_values(attr))) {
+						pwdpolicy->pw_storagescheme =
+						pw_name2scheme((char*)slapi_value_get_string(*sval));
+					}
+				}
                         
 			} /* end of for() loop */
 			if (pw_entry) {
 				slapi_entry_free(pw_entry);
 			}
 			return pwdpolicy;
-		} else if ( e ) {
+		} else if ( e ) { 
 			slapi_entry_free( e );
 		}
 	}
@@ -1718,6 +1760,11 @@ done:
 	 */
 
 	*pwdpolicy = slapdFrontendConfig->pw_policy;
+	pwdscheme = (struct pw_scheme *)slapi_ch_calloc(1, sizeof(struct pw_scheme));
+	*pwdscheme = *slapdFrontendConfig->pw_storagescheme;
+	pwdscheme->pws_name = strdup( slapdFrontendConfig->pw_storagescheme->pws_name );
+	pwdpolicy->pw_storagescheme = pwdscheme;
+
 	return pwdpolicy;
 
 } /* End of new_passwdPolicy() */
@@ -1725,7 +1772,10 @@ done:
 void
 delete_passwdPolicy( passwdPolicy **pwpolicy)
 {
-	slapi_ch_free((void **)pwpolicy);
+	if (pwpolicy && *pwpolicy) {
+		free_pw_scheme( (*(*pwpolicy)).pw_storagescheme );
+		slapi_ch_free((void **)pwpolicy);
+	}
 }
 
 /*
diff --git a/ldap/servers/slapd/pw.h b/ldap/servers/slapd/pw.h
index 5f5eb1b..38c7faf 100644
--- a/ldap/servers/slapd/pw.h
+++ b/ldap/servers/slapd/pw.h
@@ -32,8 +32,14 @@
  * 
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
+ *
+ * Contributors:
+ *   Hewlett-Packard Development Company, L.P.
+ *     Bugfix for bug #195302
+ *
  * END COPYRIGHT BLOCK **/
 
 #ifdef HAVE_CONFIG_H
@@ -76,6 +82,7 @@ struct pw_scheme {
 struct pw_scheme *pw_name2scheme( char *name );
 struct pw_scheme *pw_val2scheme( char *val, char **valpwdp, int first_is_default );
 int pw_encodevals( Slapi_Value **vals );
+int pw_encodevals_ext( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals );
 int checkPrefix(char *cipher, char *schemaName, char **encrypt);
 struct passwordpolicyarray *new_passwdPolicy ( Slapi_PBlock *pb, char *dn );
 void delete_passwdPolicy( struct passwordpolicyarray **pwpolicy);
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 5860350..0e37c85 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -32,8 +32,14 @@
  * 
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
+ *
+ * Contributors:
+ *   Hewlett-Packard Development Company, L.P.
+ *     Bugfix for bug #195302
+ *
  * END COPYRIGHT BLOCK **/
 
 #ifdef HAVE_CONFIG_H
@@ -1874,6 +1880,7 @@ typedef struct passwordpolicyarray {
   long pw_lockduration;
   long pw_resetfailurecount;
   int pw_gracelimit;
+  struct pw_scheme *pw_storagescheme;
 } passwdPolicy;
 
 typedef struct _slapdFrontendConfig {
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 1d545a0..09f18e7 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -32,8 +32,14 @@
  * 
  * 
  * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  * All rights reserved.
+ *
+ * Contributors:
+ *   Hewlett-Packard Development Company, L.P.
+ *     Bugfix for bug #195302
+ *
  * END COPYRIGHT BLOCK */
 
 #ifdef HAVE_CONFIG_H
@@ -2274,6 +2280,9 @@ int slapi_pw_find_sv( Slapi_Value **vals, const Slapi_Value *v );
 int slapi_is_encoded(char *value); 
 /* encode value with the specified algorithm */
 char* slapi_encode(char *value, char *alg);
+/* encode value with the specified algorithm, or with local algorithm if pb
+ * and sdn are specified instead, or global algorithm if pb and sdn are null */
+char* slapi_encode_ext(Slapi_PBlock *pb, const Slapi_DN *sdn, char *value, char *alg);
 
 
 /* UTF8 related */
-- 
1.6.2.5

