From ed46c6207742d6660a3034504f098d909b20cc71 Mon Sep 17 00:00:00 2001 From: Mark Reynolds 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