andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
Blob Blame History Raw
From ed46c6207742d6660a3034504f098d909b20cc71 Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Mon, 20 Jan 2014 14:36:43 -0500
Subject: [PATCH 155/225] Ticket 47678 - modify-delete userpassword

Description:  Needed to backport ticket 394 to 1.2.11.  Had to remove the password
              extension code from the original patch.

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

Reviewed by: nhosoi(Thanks!)
(cherry picked from commit a3b6e22cec1fb8cb5c55e8b848bec4a60f924849)
---
 ldap/servers/slapd/modify.c       | 168 +++++++++++++++++++++++++++++++++++---
 ldap/servers/slapd/slapi-plugin.h |  11 ---
 2 files changed, 158 insertions(+), 21 deletions(-)

diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
index 5e52f26..9db10c5 100644
--- a/ldap/servers/slapd/modify.c
+++ b/ldap/servers/slapd/modify.c
@@ -80,6 +80,7 @@ static void remove_mod (Slapi_Mods *smods, const char *type, Slapi_Mods *smod_un
 #endif
 static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod *mod, char **old_pw, Slapi_Mods *smods);
 static int hash_rootpw (LDAPMod **mods);
+static int valuearray_init_bervalarray_unhashed_only(struct berval **bvals, Slapi_Value ***cvals);
 
 #ifdef LDAP_DEBUG
 static const char*
@@ -833,19 +834,134 @@ static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw)
 			if (strcasecmp (pw_mod->mod_type, SLAPI_USERPWD_ATTR) != 0)
 				continue;
 
-			if (LDAP_MOD_DELETE == pw_mod->mod_op) {
+			if ( SLAPI_IS_MOD_DELETE(pw_mod->mod_op) ) {
 				Slapi_Attr *a = NULL;
-				/* delete pseudo password attribute if it exists in the entry */
-				if (!slapi_entry_attr_find(e, unhashed_pw_attr, &a)) {
-					slapi_mods_add_mod_values(&smods, pw_mod->mod_op,
-					                          unhashed_pw_attr, va);
+				struct pw_scheme *pwsp = NULL;
+				int remove_unhashed_pw = 1;
+				char *valpwd = NULL;
+
+				/* if there are mod values, we need to delete a specific userpassword */
+				for ( i = 0; pw_mod->mod_bvalues != NULL && pw_mod->mod_bvalues[i] != NULL; i++ ) {
+					char *password = slapi_ch_strdup(pw_mod->mod_bvalues[i]->bv_val);
+					pwsp = pw_val2scheme( password, &valpwd, 1 );
+					if(strcmp(pwsp->pws_name, "CLEAR") == 0){
+						/*
+						 *  CLEAR password
+						 *
+						 *  Ok, so now we to check the entry's userpassword values.
+						 *  First, find out the password encoding of the entry's pw.
+						 *  Then compare our clear text password to the encoded userpassword
+						 *  using the proper scheme.  If we have a match, we know which
+						 *  userpassword value to delete.
+						 */
+						Slapi_Attr *pw = NULL;
+						struct berval bval, *bv[2];
+
+						if(slapi_entry_attr_find(e, SLAPI_USERPWD_ATTR, &pw) == 0 && pw){
+							struct pw_scheme *pass_scheme = NULL;
+							Slapi_Value **present_values = NULL;
+							char *pval = NULL;
+							int ii;
+
+							present_values = attr_get_present_values(pw);
+							for(ii = 0; present_values && present_values[ii]; ii++){
+								const char *userpwd = slapi_value_get_string(present_values[ii]);
+
+								pass_scheme = pw_val2scheme( (char *)userpwd, &pval, 1 );
+								if(strcmp(pass_scheme->pws_name,"CLEAR")){
+									/* its encoded, so compare it */
+									if((*(pass_scheme->pws_cmp))( valpwd, pval ) == 0 ){
+										/*
+										 *  Match, replace the mod value with the encoded password
+										 */
+										slapi_ch_free_string(&pw_mod->mod_bvalues[i]->bv_val);
+										pw_mod->mod_bvalues[i]->bv_val = strdup(userpwd);
+										pw_mod->mod_bvalues[i]->bv_len = strlen(userpwd);
+										free_pw_scheme( pass_scheme );
+										break;
+									}
+								} else {
+									/* userpassword is already clear text, nothing to do */
+									free_pw_scheme( pass_scheme );
+									break;
+								}
+								free_pw_scheme( pass_scheme );
+							}
+						}
+						/*
+						 *  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);
+					} else {
+						/*
+						 *  Password is encoded, try and find a matching unhashed_password to delete
+						 */
+						char **vals;
+
+						/*
+						 *  Grab the current unhashed passwords from the entry.
+						 */
+						vals = slapi_entry_attr_get_charray(e, unhashed_pw_attr);
+						if(vals){
+							int ii;
+
+							for(ii = 0; vals && vals[ii]; ii++){
+								char *unhashed_pwd = vals[ii];
+								struct pw_scheme *unhashed_pwsp = NULL;
+								struct berval bval, *bv[2];
+
+								/* prepare the value to delete from the list of unhashed userpasswords */
+								bval.bv_val = unhashed_pwd;
+								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 );
+								if(strcmp(unhashed_pwsp->pws_name, "CLEAR") == 0){
+									if((*(pwsp->pws_cmp))(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 );
+										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);
+								}
+								free_pw_scheme( unhashed_pwsp );
+							}
+						}
+					}
+					remove_unhashed_pw = 0; /* mark that we already removed the unhashed userpassword */
+					slapi_ch_free_string(&password);
+					free_pw_scheme( pwsp );
+				}
+				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 */
-				valuearray_init_bervalarray(pw_mod->mod_bvalues, &va);
-				slapi_mods_add_mod_values(&smods, pw_mod->mod_op,
-				                          unhashed_pw_attr, va);
-				valuearray_free(&va);
+				/* add pseudo password attribute - only if it's value is clear text */
+				valuearray_init_bervalarray_unhashed_only(pw_mod->mod_bvalues, &va);
+				if(va){
+					slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
+					valuearray_free(&va);
+				}
 			}
 
 			/* Init new value array for hashed value */
@@ -1301,3 +1417,35 @@ hash_rootpw (LDAPMod **mods)
 	return 0;
 }
 
+/*
+ *  Only add password mods that are in clear text.  The console likes to send two mods:
+ *    - Already encoded password
+ *    - Clear text password
+ *
+ *  We don't want to add the encoded value to the unhashed_userpassword attr
+ */
+static int
+valuearray_init_bervalarray_unhashed_only(struct berval **bvals, Slapi_Value ***cvals)
+{
+	int n;
+
+	for(n = 0; bvals != NULL && bvals[n] != NULL; n++);
+
+	if(n == 0){
+		*cvals = NULL;
+	} else {
+		struct pw_scheme *pwsp = NULL;
+		int i,p;
+
+		*cvals = (Slapi_Value **) slapi_ch_malloc((n + 1) * sizeof(Slapi_Value *));
+		for(i = 0, p = 0; i < n; i++){
+			pwsp = pw_val2scheme( bvals[i]->bv_val, NULL, 1 );
+			if(strcmp(pwsp->pws_name, "CLEAR") == 0){
+				(*cvals)[p++] = slapi_value_new_berval(bvals[i]);
+			}
+			free_pw_scheme( pwsp );
+		}
+		(*cvals)[p] = NULL;
+	}
+	return n;
+}
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index eeac43e..58feaf3 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -7227,17 +7227,6 @@ void slapi_set_plugin_open_rootdn_bind(Slapi_PBlock *pb);
 #define SLAPI_EXT_SET_REPLACE 1
 
 /**
- * Get entry extension
- *
- * \param entry is the entry to retrieve the extension from
- * \param vals is the array of (Slapi_Value *), which directly refers the extension.  Caller must duplicate it to use it for other than referring.
- *
- * \return LDAP_SUCCESS if successful.
- * \return non-zero otherwise.
- */
-int slapi_pw_get_entry_ext(Slapi_Entry *entry, Slapi_Value ***vals);
-
-/**
  * Set entry extension
  *
  * \param entry is the entry to set the extension to
-- 
1.8.1.4