andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
dc8c34
From ed46c6207742d6660a3034504f098d909b20cc71 Mon Sep 17 00:00:00 2001
dc8c34
From: Mark Reynolds <mreynolds@redhat.com>
dc8c34
Date: Mon, 20 Jan 2014 14:36:43 -0500
dc8c34
Subject: [PATCH 155/225] Ticket 47678 - modify-delete userpassword
dc8c34
dc8c34
Description:  Needed to backport ticket 394 to 1.2.11.  Had to remove the password
dc8c34
              extension code from the original patch.
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/47678
dc8c34
dc8c34
Reviewed by: nhosoi(Thanks!)
dc8c34
(cherry picked from commit a3b6e22cec1fb8cb5c55e8b848bec4a60f924849)
dc8c34
---
dc8c34
 ldap/servers/slapd/modify.c       | 168 +++++++++++++++++++++++++++++++++++---
dc8c34
 ldap/servers/slapd/slapi-plugin.h |  11 ---
dc8c34
 2 files changed, 158 insertions(+), 21 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
dc8c34
index 5e52f26..9db10c5 100644
dc8c34
--- a/ldap/servers/slapd/modify.c
dc8c34
+++ b/ldap/servers/slapd/modify.c
dc8c34
@@ -80,6 +80,7 @@ static void remove_mod (Slapi_Mods *smods, const char *type, Slapi_Mods *smod_un
dc8c34
 #endif
dc8c34
 static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod *mod, char **old_pw, Slapi_Mods *smods);
dc8c34
 static int hash_rootpw (LDAPMod **mods);
dc8c34
+static int valuearray_init_bervalarray_unhashed_only(struct berval **bvals, Slapi_Value ***cvals);
dc8c34
 
dc8c34
 #ifdef LDAP_DEBUG
dc8c34
 static const char*
dc8c34
@@ -833,19 +834,134 @@ static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw)
dc8c34
 			if (strcasecmp (pw_mod->mod_type, SLAPI_USERPWD_ATTR) != 0)
dc8c34
 				continue;
dc8c34
 
dc8c34
-			if (LDAP_MOD_DELETE == pw_mod->mod_op) {
dc8c34
+			if ( SLAPI_IS_MOD_DELETE(pw_mod->mod_op) ) {
dc8c34
 				Slapi_Attr *a = NULL;
dc8c34
-				/* delete pseudo password attribute if it exists in the entry */
dc8c34
-				if (!slapi_entry_attr_find(e, unhashed_pw_attr, &a)) {
dc8c34
-					slapi_mods_add_mod_values(&smods, pw_mod->mod_op,
dc8c34
-					                          unhashed_pw_attr, va);
dc8c34
+				struct pw_scheme *pwsp = NULL;
dc8c34
+				int remove_unhashed_pw = 1;
dc8c34
+				char *valpwd = NULL;
dc8c34
+
dc8c34
+				/* if there are mod values, we need to delete a specific userpassword */
dc8c34
+				for ( i = 0; pw_mod->mod_bvalues != NULL && pw_mod->mod_bvalues[i] != NULL; i++ ) {
dc8c34
+					char *password = slapi_ch_strdup(pw_mod->mod_bvalues[i]->bv_val);
dc8c34
+					pwsp = pw_val2scheme( password, &valpwd, 1 );
dc8c34
+					if(strcmp(pwsp->pws_name, "CLEAR") == 0){
dc8c34
+						/*
dc8c34
+						 *  CLEAR password
dc8c34
+						 *
dc8c34
+						 *  Ok, so now we to check the entry's userpassword values.
dc8c34
+						 *  First, find out the password encoding of the entry's pw.
dc8c34
+						 *  Then compare our clear text password to the encoded userpassword
dc8c34
+						 *  using the proper scheme.  If we have a match, we know which
dc8c34
+						 *  userpassword value to delete.
dc8c34
+						 */
dc8c34
+						Slapi_Attr *pw = NULL;
dc8c34
+						struct berval bval, *bv[2];
dc8c34
+
dc8c34
+						if(slapi_entry_attr_find(e, SLAPI_USERPWD_ATTR, &pw) == 0 && pw){
dc8c34
+							struct pw_scheme *pass_scheme = NULL;
dc8c34
+							Slapi_Value **present_values = NULL;
dc8c34
+							char *pval = NULL;
dc8c34
+							int ii;
dc8c34
+
dc8c34
+							present_values = attr_get_present_values(pw);
dc8c34
+							for(ii = 0; present_values && present_values[ii]; ii++){
dc8c34
+								const char *userpwd = slapi_value_get_string(present_values[ii]);
dc8c34
+
dc8c34
+								pass_scheme = pw_val2scheme( (char *)userpwd, &pval, 1 );
dc8c34
+								if(strcmp(pass_scheme->pws_name,"CLEAR")){
dc8c34
+									/* its encoded, so compare it */
dc8c34
+									if((*(pass_scheme->pws_cmp))( valpwd, pval ) == 0 ){
dc8c34
+										/*
dc8c34
+										 *  Match, replace the mod value with the encoded password
dc8c34
+										 */
dc8c34
+										slapi_ch_free_string(&pw_mod->mod_bvalues[i]->bv_val);
dc8c34
+										pw_mod->mod_bvalues[i]->bv_val = strdup(userpwd);
dc8c34
+										pw_mod->mod_bvalues[i]->bv_len = strlen(userpwd);
dc8c34
+										free_pw_scheme( pass_scheme );
dc8c34
+										break;
dc8c34
+									}
dc8c34
+								} else {
dc8c34
+									/* userpassword is already clear text, nothing to do */
dc8c34
+									free_pw_scheme( pass_scheme );
dc8c34
+									break;
dc8c34
+								}
dc8c34
+								free_pw_scheme( pass_scheme );
dc8c34
+							}
dc8c34
+						}
dc8c34
+						/*
dc8c34
+						 *  Finally, delete the unhashed userpassword
dc8c34
+						 */
dc8c34
+						bval.bv_val = password;
dc8c34
+						bval.bv_len = strlen(password);
dc8c34
+						bv[0] = &bval;
dc8c34
+						bv[1] = NULL;
dc8c34
+						valuearray_init_bervalarray(bv, &va);
dc8c34
+						slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
dc8c34
+						valuearray_free(&va);
dc8c34
+					} else {
dc8c34
+						/*
dc8c34
+						 *  Password is encoded, try and find a matching unhashed_password to delete
dc8c34
+						 */
dc8c34
+						char **vals;
dc8c34
+
dc8c34
+						/*
dc8c34
+						 *  Grab the current unhashed passwords from the entry.
dc8c34
+						 */
dc8c34
+						vals = slapi_entry_attr_get_charray(e, unhashed_pw_attr);
dc8c34
+						if(vals){
dc8c34
+							int ii;
dc8c34
+
dc8c34
+							for(ii = 0; vals && vals[ii]; ii++){
dc8c34
+								char *unhashed_pwd = vals[ii];
dc8c34
+								struct pw_scheme *unhashed_pwsp = NULL;
dc8c34
+								struct berval bval, *bv[2];
dc8c34
+
dc8c34
+								/* prepare the value to delete from the list of unhashed userpasswords */
dc8c34
+								bval.bv_val = unhashed_pwd;
dc8c34
+								bval.bv_len = strlen(unhashed_pwd);
dc8c34
+								bv[0] = &bval;
dc8c34
+								bv[1] = NULL;
dc8c34
+
dc8c34
+								/*
dc8c34
+								 *  Compare the clear text unhashed password, to the encoded password
dc8c34
+								 *  provided by the client.
dc8c34
+								 */
dc8c34
+								unhashed_pwsp = pw_val2scheme( unhashed_pwd, NULL, 1 );
dc8c34
+								if(strcmp(unhashed_pwsp->pws_name, "CLEAR") == 0){
dc8c34
+									if((*(pwsp->pws_cmp))(unhashed_pwd , valpwd) == 0 ){
dc8c34
+										/* match, add the delete mod for this particular unhashed userpassword */
dc8c34
+										valuearray_init_bervalarray(bv, &va);
dc8c34
+										slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
dc8c34
+										valuearray_free(&va);
dc8c34
+										free_pw_scheme( unhashed_pwsp );
dc8c34
+										break;
dc8c34
+									}
dc8c34
+								} else {
dc8c34
+									/*
dc8c34
+									 *  We have a hashed unhashed_userpassword!  We must delete it.
dc8c34
+									 */
dc8c34
+									valuearray_init_bervalarray(bv, &va);
dc8c34
+									slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
dc8c34
+									valuearray_free(&va);
dc8c34
+								}
dc8c34
+								free_pw_scheme( unhashed_pwsp );
dc8c34
+							}
dc8c34
+						}
dc8c34
+					}
dc8c34
+					remove_unhashed_pw = 0; /* mark that we already removed the unhashed userpassword */
dc8c34
+					slapi_ch_free_string(&password);
dc8c34
+					free_pw_scheme( pwsp );
dc8c34
+				}
dc8c34
+				if (remove_unhashed_pw && !slapi_entry_attr_find(e, unhashed_pw_attr, &a)){
dc8c34
+					slapi_mods_add_mod_values(&smods, pw_mod->mod_op,unhashed_pw_attr, va);
dc8c34
 				}
dc8c34
 			} else {
dc8c34
-				/* add pseudo password attribute */
dc8c34
-				valuearray_init_bervalarray(pw_mod->mod_bvalues, &va);
dc8c34
-				slapi_mods_add_mod_values(&smods, pw_mod->mod_op,
dc8c34
-				                          unhashed_pw_attr, va);
dc8c34
-				valuearray_free(&va);
dc8c34
+				/* add pseudo password attribute - only if it's value is clear text */
dc8c34
+				valuearray_init_bervalarray_unhashed_only(pw_mod->mod_bvalues, &va);
dc8c34
+				if(va){
dc8c34
+					slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
dc8c34
+					valuearray_free(&va);
dc8c34
+				}
dc8c34
 			}
dc8c34
 
dc8c34
 			/* Init new value array for hashed value */
dc8c34
@@ -1301,3 +1417,35 @@ hash_rootpw (LDAPMod **mods)
dc8c34
 	return 0;
dc8c34
 }
dc8c34
 
dc8c34
+/*
dc8c34
+ *  Only add password mods that are in clear text.  The console likes to send two mods:
dc8c34
+ *    - Already encoded password
dc8c34
+ *    - Clear text password
dc8c34
+ *
dc8c34
+ *  We don't want to add the encoded value to the unhashed_userpassword attr
dc8c34
+ */
dc8c34
+static int
dc8c34
+valuearray_init_bervalarray_unhashed_only(struct berval **bvals, Slapi_Value ***cvals)
dc8c34
+{
dc8c34
+	int n;
dc8c34
+
dc8c34
+	for(n = 0; bvals != NULL && bvals[n] != NULL; n++);
dc8c34
+
dc8c34
+	if(n == 0){
dc8c34
+		*cvals = NULL;
dc8c34
+	} else {
dc8c34
+		struct pw_scheme *pwsp = NULL;
dc8c34
+		int i,p;
dc8c34
+
dc8c34
+		*cvals = (Slapi_Value **) slapi_ch_malloc((n + 1) * sizeof(Slapi_Value *));
dc8c34
+		for(i = 0, p = 0; i < n; i++){
dc8c34
+			pwsp = pw_val2scheme( bvals[i]->bv_val, NULL, 1 );
dc8c34
+			if(strcmp(pwsp->pws_name, "CLEAR") == 0){
dc8c34
+				(*cvals)[p++] = slapi_value_new_berval(bvals[i]);
dc8c34
+			}
dc8c34
+			free_pw_scheme( pwsp );
dc8c34
+		}
dc8c34
+		(*cvals)[p] = NULL;
dc8c34
+	}
dc8c34
+	return n;
dc8c34
+}
dc8c34
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
dc8c34
index eeac43e..58feaf3 100644
dc8c34
--- a/ldap/servers/slapd/slapi-plugin.h
dc8c34
+++ b/ldap/servers/slapd/slapi-plugin.h
dc8c34
@@ -7227,17 +7227,6 @@ void slapi_set_plugin_open_rootdn_bind(Slapi_PBlock *pb);
dc8c34
 #define SLAPI_EXT_SET_REPLACE 1
dc8c34
 
dc8c34
 /**
dc8c34
- * Get entry extension
dc8c34
- *
dc8c34
- * \param entry is the entry to retrieve the extension from
dc8c34
- * \param vals is the array of (Slapi_Value *), which directly refers the extension.  Caller must duplicate it to use it for other than referring.
dc8c34
- *
dc8c34
- * \return LDAP_SUCCESS if successful.
dc8c34
- * \return non-zero otherwise.
dc8c34
- */
dc8c34
-int slapi_pw_get_entry_ext(Slapi_Entry *entry, Slapi_Value ***vals);
dc8c34
-
dc8c34
-/**
dc8c34
  * Set entry extension
dc8c34
  *
dc8c34
  * \param entry is the entry to set the extension to
dc8c34
-- 
dc8c34
1.8.1.4
dc8c34