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