summaryrefslogtreecommitdiffstats
path: root/daemons/ipa-slapi-plugins
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2011-07-01 13:32:57 -0400
committerSimo Sorce <ssorce@redhat.com>2011-08-26 08:24:50 -0400
commit7ea0b5d56e2b157d7bcc15610d076e44f02beeda (patch)
tree404725ca27f85f162308d09a71ccc61cb6bb33d0 /daemons/ipa-slapi-plugins
parenta1637d47c0ccd596305567f925ee611c00dfa899 (diff)
downloadfreeipa-7ea0b5d56e2b157d7bcc15610d076e44f02beeda.tar.gz
freeipa-7ea0b5d56e2b157d7bcc15610d076e44f02beeda.tar.xz
freeipa-7ea0b5d56e2b157d7bcc15610d076e44f02beeda.zip
ipa-pwd-extop: Use common password policy code
Diffstat (limited to 'daemons/ipa-slapi-plugins')
-rw-r--r--daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am3
-rw-r--r--daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c27
-rw-r--r--daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h9
-rw-r--r--daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_common.c536
4 files changed, 127 insertions, 448 deletions
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am
index cc041aa4f..bdc583566 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am
@@ -2,7 +2,8 @@ NULL =
PLUGIN_COMMON_DIR=../common
KRB5_UTIL_DIR= ../../../util
-KRB5_UTIL_SRCS = $(KRB5_UTIL_DIR)/ipa_krb5.c
+KRB5_UTIL_SRCS = $(KRB5_UTIL_DIR)/ipa_krb5.c \
+ $(KRB5_UTIL_DIR)/ipa_pwd.c
INCLUDES = \
-I. \
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
index 68d1703b5..91ef0208c 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
@@ -120,6 +120,24 @@ static int filter_keys(struct ipapwd_krbcfg *krbcfg,
return 0;
}
+static int ipapwd_to_ldap_pwpolicy_error(int ipapwderr)
+{
+ switch (ipapwderr) {
+ case IPAPWD_POLICY_ACCOUNT_EXPIRED:
+ return LDAP_PWPOLICY_PWDMODNOTALLOWED;
+ case IPAPWD_POLICY_PWD_TOO_YOUNG:
+ return LDAP_PWPOLICY_PWDTOOYOUNG;
+ case IPAPWD_POLICY_PWD_TOO_SHORT:
+ return LDAP_PWPOLICY_PWDTOOSHORT;
+ case IPAPWD_POLICY_PWD_IN_HISTORY:
+ return LDAP_PWPOLICY_PWDINHISTORY;
+ case IPAPWD_POLICY_PWD_COMPLEXITY:
+ return LDAP_PWPOLICY_INVALIDPWDSYNTAX;
+ }
+ /* in case of unhandled error return access denied */
+ return LDAP_PWPOLICY_PWDMODNOTALLOWED;
+}
+
static int ipapwd_chpwop(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg)
{
@@ -374,12 +392,13 @@ parse_req_done:
ret = ipapwd_CheckPolicy(&pwdata);
if (ret) {
errMesg = "Password Fails to meet minimum strength criteria";
- if (ret & IPAPWD_POLICY_ERROR) {
- slapi_pwpolicy_make_response_control(pb, -1, -1, ret & IPAPWD_POLICY_MASK);
- rc = LDAP_CONSTRAINT_VIOLATION;
- } else {
+ if (ret == IPAPWD_POLICY_ERROR) {
errMesg = "Internal error";
rc = ret;
+ } else {
+ ret = ipapwd_to_ldap_pwpolicy_error(ret);
+ slapi_pwpolicy_make_response_control(pb, -1, -1, ret);
+ rc = LDAP_CONSTRAINT_VIOLATION;
}
goto free_and_return;
}
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h
index 7d81bda3d..e430db73d 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h
@@ -61,6 +61,7 @@
#include <openssl/md4.h>
#include "ipa_krb5.h"
+#include "ipa_pwd.h"
#define IPAPWD_PLUGIN_NAME "ipa-pwd-extop"
#define IPAPWD_FEATURE_DESC "IPA Password Manager"
@@ -80,10 +81,9 @@ struct ipapwd_data {
char *dn;
char *password;
time_t timeNow;
- time_t lastPwChange;
time_t expireTime;
int changetype;
- int pwHistoryLen;
+ struct ipapwd_policy policy;
};
struct ipapwd_operation {
@@ -94,11 +94,6 @@ struct ipapwd_operation {
#define GENERALIZED_TIME_LENGTH 15
-#define IPAPWD_POLICY_MASK 0x0FF
-#define IPAPWD_POLICY_ERROR 0x100
-#define IPAPWD_POLICY_OK 0
-
-
/* from ipapwd_common.c */
struct ipapwd_krbcfg {
krb5_context krbctx;
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_common.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_common.c
index f36fc774b..c111eb1b3 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_common.c
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_common.c
@@ -329,8 +329,9 @@ static int ipapwd_rdn_count(const char *dn)
return rdnc;
}
-static int ipapwd_getPolicy(const char *dn,
- Slapi_Entry *target, Slapi_Entry **e)
+int ipapwd_getPolicy(const char *dn,
+ Slapi_Entry *target,
+ struct ipapwd_policy *policy)
{
const char *krbPwdPolicyReference;
const char *pdn;
@@ -347,6 +348,7 @@ static int ipapwd_getPolicy(const char *dn,
int buffer_flags=0;
Slapi_ValueSet* results = NULL;
char* actual_type_name = NULL;
+ int tmpint;
LOG_TRACE("Searching policy for [%s]\n", dn);
@@ -379,8 +381,6 @@ static int ipapwd_getPolicy(const char *dn,
scope = LDAP_SCOPE_SUBTREE;
}
- *e = NULL;
-
pb = slapi_pblock_new();
slapi_search_internal_set_pb(pb,
pdn, scope,
@@ -413,10 +413,8 @@ static int ipapwd_getPolicy(const char *dn,
/* if there is only one, return that */
if (i == 1) {
- *e = slapi_entry_dup(es[0]);
-
- ret = 0;
- goto done;
+ pe = es[0];
+ goto fill;
}
/* count number of RDNs in DN */
@@ -463,8 +461,27 @@ static int ipapwd_getPolicy(const char *dn,
goto done;
}
- *e = slapi_entry_dup(pe);
+fill:
+ policy->min_pwd_life = slapi_entry_attr_get_int(pe, "krbMinPwdLife");
+
+ tmpint = slapi_entry_attr_get_int(pe, "krbMaxPwdLife");
+ if (tmpint != 0) {
+ policy->max_pwd_life = tmpint;
+ }
+
+ tmpint = slapi_entry_attr_get_int(pe, "krbPwdMinLength");
+ if (tmpint != 0) {
+ policy->min_pwd_length = tmpint;
+ }
+
+ policy->history_length = slapi_entry_attr_get_int(pe,
+ "krbPwdHistoryLength");
+
+ policy->min_complexity = slapi_entry_attr_get_int(pe,
+ "krbPwdMinDiffChars");
+
ret = 0;
+
done:
if (results) {
pwd_values_free(&results, &actual_type_name, buffer_flags);
@@ -477,24 +494,6 @@ done:
return ret;
}
-static Slapi_Value *ipapwd_strip_pw_date(Slapi_Value *pw)
-{
- const char *pwstr;
-
- pwstr = slapi_value_get_string(pw);
- return slapi_value_new_string(&pwstr[GENERALIZED_TIME_LENGTH]);
-}
-
-/* searches the directory and finds the policy closest to the DN */
-/* return 0 on success, -1 on error or if no policy is found */
-static int ipapwd_sv_pw_cmp(const void *pv1, const void *pv2)
-{
- const char *pw1 = slapi_value_get_string(*((Slapi_Value **)pv1));
- const char *pw2 = slapi_value_get_string(*((Slapi_Value **)pv2));
-
- return strncmp(pw1, pw2, GENERALIZED_TIME_LENGTH);
-}
-
/*==Common-public-functions=============================================*/
@@ -620,62 +619,19 @@ done:
return rc;
}
-/* 90 days default pwd max lifetime */
-#define IPAPWD_DEFAULT_PWDLIFE (90 * 24 *3600)
-#define IPAPWD_DEFAULT_MINLEN 0
-
/* check password strenght and history */
int ipapwd_CheckPolicy(struct ipapwd_data *data)
{
- char *krbPrincipalExpiration = NULL;
- char *krbLastPwdChange = NULL;
- char *krbPasswordExpiration = NULL;
- int krbMaxPwdLife = IPAPWD_DEFAULT_PWDLIFE;
- int krbPwdMinLength = IPAPWD_DEFAULT_MINLEN;
- int krbPwdMinDiffChars = 0;
- int krbMinPwdLife = 0;
- int pwdCharLen = 0;
- Slapi_Entry *policy = NULL;
- Slapi_Attr *passwordHistory = NULL;
- struct tm tm;
- int tmp, ret;
- char *old_pw;
-
- /* check account is not expired. Ignore unixtime = 0 (Jan 1 1970) */
- krbPrincipalExpiration =
- slapi_entry_attr_get_charptr(data->target, "krbPrincipalExpiration");
- if (krbPrincipalExpiration &&
- (strcasecmp("19700101000000Z", krbPrincipalExpiration) != 0)) {
- /* if expiration date is set check it */
- memset(&tm, 0, sizeof(struct tm));
- ret = sscanf(krbPrincipalExpiration,
- "%04u%02u%02u%02u%02u%02u",
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
- &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
-
- if (ret == 6) {
- tm.tm_year -= 1900;
- tm.tm_mon -= 1;
-
- if (data->timeNow > timegm(&tm)) {
- LOG_TRACE("Account Expired");
- return IPAPWD_POLICY_ERROR | LDAP_PWPOLICY_PWDMODNOTALLOWED;
- }
- }
- /* FIXME: else error out ? */
- }
- slapi_ch_free_string(&krbPrincipalExpiration);
-
- /* find the entry with the password policy */
- ret = ipapwd_getPolicy(data->dn, data->target, &policy);
- if (ret) {
- LOG_TRACE("No password policy");
- goto no_policy;
- }
+ struct ipapwd_policy pol = {0};
+ time_t acct_expiration;
+ time_t pwd_expiration;
+ time_t last_pwd_change;
+ char **pwd_history;
+ char *tmpstr;
+ int ret;
- /* Retrieve Max History Len */
- data->pwHistoryLen =
- slapi_entry_attr_get_int(policy, "krbPwdHistoryLength");
+ pol.max_pwd_life = IPAPWD_DEFAULT_PWDLIFE;
+ pol.min_pwd_length = IPAPWD_DEFAULT_MINLEN;
if (data->changetype != IPA_CHANGETYPE_NORMAL) {
/* We must skip policy checks (Admin change) but
@@ -685,279 +641,51 @@ int ipapwd_CheckPolicy(struct ipapwd_data *data)
data->expireTime = data->timeNow;
}
- /* skip policy checks */
- slapi_entry_free(policy);
- goto no_policy;
- }
-
- /* first of all check current password, if any */
- old_pw = slapi_entry_attr_get_charptr(data->target, "userPassword");
- if (old_pw) {
- Slapi_Value *cpw[2] = {NULL, NULL};
- Slapi_Value *pw;
-
- cpw[0] = slapi_value_new_string(old_pw);
- pw = slapi_value_new_string(data->password);
- if (!pw) {
- LOG_OOM();
- slapi_entry_free(policy);
- slapi_ch_free_string(&old_pw);
- slapi_value_free(&cpw[0]);
- slapi_value_free(&pw);
- return LDAP_OPERATIONS_ERROR;
- }
-
- ret = slapi_pw_find_sv(cpw, pw);
- slapi_ch_free_string(&old_pw);
- slapi_value_free(&cpw[0]);
- slapi_value_free(&pw);
-
- if (ret == 0) {
- LOG_TRACE("Password in history\n");
- slapi_entry_free(policy);
- return IPAPWD_POLICY_ERROR | LDAP_PWPOLICY_PWDINHISTORY;
- }
- }
-
- krbPasswordExpiration =
- slapi_entry_attr_get_charptr(data->target, "krbPasswordExpiration");
- krbLastPwdChange =
- slapi_entry_attr_get_charptr(data->target, "krbLastPwdChange");
- /* if no previous change, it means this is probably a new account
- * or imported, log and just ignore */
- if (krbLastPwdChange) {
-
- memset(&tm, 0, sizeof(struct tm));
- ret = sscanf(krbLastPwdChange,
- "%04u%02u%02u%02u%02u%02u",
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
- &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
-
- if (ret == 6) {
- tm.tm_year -= 1900;
- tm.tm_mon -= 1;
- data->lastPwChange = timegm(&tm);
- }
- /* FIXME: *else* report an error ? */
+ /* do not load policies */
} else {
- LOG_TRACE("Warning: Last Password Change Time is not available\n");
- }
-
- /* Check min age */
- krbMinPwdLife = slapi_entry_attr_get_int(policy, "krbMinPwdLife");
- /* if no default then treat it as no limit */
- if (krbMinPwdLife != 0) {
-
- /* check for reset cases */
- if (krbLastPwdChange == NULL ||
- ((krbPasswordExpiration != NULL) &&
- strcmp(krbPasswordExpiration, krbLastPwdChange) == 0)) {
- /* Expiration and last change time are the same or
- * missing this happens only when a password is reset
- * by an admin or the account is new or no expiration
- * policy is set, PASS */
- LOG_TRACE("Ignore krbMinPwdLife Expiration, not enough info\n");
-
- } else if (data->timeNow < data->lastPwChange + krbMinPwdLife) {
- LOG_TRACE("Too soon to change password\n");
- slapi_entry_free(policy);
- slapi_ch_free_string(&krbPasswordExpiration);
- slapi_ch_free_string(&krbLastPwdChange);
- return IPAPWD_POLICY_ERROR | LDAP_PWPOLICY_PWDTOOYOUNG;
- }
- }
-
- /* free strings or we leak them */
- slapi_ch_free_string(&krbPasswordExpiration);
- slapi_ch_free_string(&krbLastPwdChange);
-
- /* Retrieve min length */
- tmp = slapi_entry_attr_get_int(policy, "krbPwdMinLength");
- if (tmp != 0) {
- krbPwdMinLength = tmp;
- }
-
- /* check complexity */
- /* FIXME: this code is partially based on Directory Server code,
- * the plan is to merge this code later making it available
- * trough a pulic DS API for slapi plugins */
- krbPwdMinDiffChars =
- slapi_entry_attr_get_int(policy, "krbPwdMinDiffChars");
- if (krbPwdMinDiffChars != 0) {
- int num_digits = 0;
- int num_alphas = 0;
- int num_uppers = 0;
- int num_lowers = 0;
- int num_specials = 0;
- int num_8bit = 0;
- int num_repeated = 0;
- int max_repeated = 0;
- int num_categories = 0;
- char *p, *pwd;
-
- pwd = strdup(data->password);
-
- /* check character types */
- p = pwd;
- while (p && *p) {
- if (ldap_utf8isdigit(p)) {
- num_digits++;
- } else if (ldap_utf8isalpha(p)) {
- num_alphas++;
- if (slapi_utf8isLower((unsigned char *)p)) {
- num_lowers++;
- } else {
- num_uppers++;
- }
- } else {
- /* check if this is an 8-bit char */
- if (*p & 128) {
- num_8bit++;
- } else {
- num_specials++;
- }
- }
-
- /* check for repeating characters. If this is the
- first char of the password, no need to check */
- if (pwd != p) {
- int len = ldap_utf8len(p);
- char *prev_p = ldap_utf8prev(p);
-
- if (len == ldap_utf8len(prev_p)) {
- if (memcmp(p, prev_p, len) == 0) {
- num_repeated++;
- if (max_repeated < num_repeated) {
- max_repeated = num_repeated;
- }
- } else {
- num_repeated = 0;
- }
- } else {
- num_repeated = 0;
- }
- }
-
- p = ldap_utf8next(p);
- }
-
- free(pwd);
- p = pwd = NULL;
- /* tally up the number of character categories */
- if (num_digits > 0) ++num_categories;
- if (num_uppers > 0) ++num_categories;
- if (num_lowers > 0) ++num_categories;
- if (num_specials > 0) ++num_categories;
- if (num_8bit > 0) ++num_categories;
-
- /* FIXME: the kerberos plicy schema does not define separated
- * threshold values, so just treat anything as a category,
- * we will fix this when we merge with DS policies */
-
- if (max_repeated > 1) --num_categories;
-
- if (num_categories < krbPwdMinDiffChars) {
- LOG_TRACE("Password not complex enough\n");
- slapi_entry_free(policy);
- return IPAPWD_POLICY_ERROR | LDAP_PWPOLICY_INVALIDPWDSYNTAX;
+ /* find the entry with the password policy */
+ ret = ipapwd_getPolicy(data->dn, data->target, &pol);
+ if (ret) {
+ LOG_TRACE("No password policy, use defaults");
}
}
- /* Check password history */
- ret = slapi_entry_attr_find(data->target,
- "passwordHistory", &passwordHistory);
- if (ret == 0) {
- int err, hint, count, i, j;
- const char *pwstr;
- Slapi_Value **pH;
- Slapi_Value *pw;
-
- hint = 0;
- count = 0;
- err = slapi_attr_get_numvalues(passwordHistory, &count);
- /* check history only if we have one */
- if (count > 0 && data->pwHistoryLen > 0) {
- pH = calloc(count + 2, sizeof(Slapi_Value *));
- if (!pH) {
- LOG_OOM();
- slapi_entry_free(policy);
- return LDAP_OPERATIONS_ERROR;
- }
-
- i = 0;
- hint = slapi_attr_first_value(passwordHistory, &pw);
- while (hint != -1) {
- pwstr = slapi_value_get_string(pw);
- /* if shorter than GENERALIZED_TIME_LENGTH, it
- * is garbage, we never set timeless entries */
- if (pwstr &&
- (strlen(pwstr) > GENERALIZED_TIME_LENGTH)) {
- pH[i] = pw;
- i++;
- }
- hint = slapi_attr_next_value(passwordHistory, hint, &pw);
- }
-
- qsort(pH, i, sizeof(Slapi_Value *), ipapwd_sv_pw_cmp);
+ tmpstr = slapi_entry_attr_get_charptr(data->target,
+ "krbPrincipalExpiration");
+ acct_expiration = ipapwd_gentime_to_time_t(tmpstr);
+ slapi_ch_free_string(&tmpstr);
- if (i > data->pwHistoryLen) {
- i = data->pwHistoryLen;
- pH[i] = NULL;
- }
+ tmpstr = slapi_entry_attr_get_charptr(data->target,
+ "krbPasswordExpiration");
+ pwd_expiration = ipapwd_gentime_to_time_t(tmpstr);
+ slapi_ch_free_string(&tmpstr);
- for (j = 0; pH[j]; j++) {
- pH[j] = ipapwd_strip_pw_date(pH[j]);
- }
+ tmpstr = slapi_entry_attr_get_charptr(data->target,
+ "krbLastPwdChange");
+ last_pwd_change = ipapwd_gentime_to_time_t(tmpstr);
+ slapi_ch_free_string(&tmpstr);
- pw = slapi_value_new_string(data->password);
- if (!pw) {
- LOG_OOM();
- slapi_entry_free(policy);
- free(pH);
- return LDAP_OPERATIONS_ERROR;
- }
+ pwd_history = slapi_entry_attr_get_charray(data->target,
+ "passwordHistory");
- err = slapi_pw_find_sv(pH, pw);
+ /* check policy */
+ ret = ipapwd_check_policy(&pol, data->password,
+ data->timeNow,
+ acct_expiration,
+ pwd_expiration,
+ last_pwd_change,
+ pwd_history);
- for (j = 0; pH[j]; j++) {
- slapi_value_free(&pH[j]);
- }
- slapi_value_free(&pw);
- free(pH);
-
- if (err == 0) {
- LOG_TRACE("Password in history\n");
- slapi_entry_free(policy);
- return IPAPWD_POLICY_ERROR | LDAP_PWPOLICY_PWDINHISTORY;
- }
- }
- }
-
- /* Calculate max age */
- tmp = slapi_entry_attr_get_int(policy, "krbMaxPwdLife");
- if (tmp != 0) {
- krbMaxPwdLife = tmp;
- }
-
- slapi_entry_free(policy);
-
-no_policy:
-
- /* check min lenght */
- pwdCharLen = ldap_utf8characters(data->password);
-
- if (pwdCharLen < krbPwdMinLength) {
- LOG_TRACE("Password too short (%d < %d)\n",
- pwdCharLen, krbPwdMinLength);
- return IPAPWD_POLICY_ERROR | LDAP_PWPOLICY_PWDTOOSHORT;
- }
+ slapi_ch_array_free(pwd_history);
if (data->expireTime == 0) {
- data->expireTime = data->timeNow + krbMaxPwdLife;
+ data->expireTime = data->timeNow + pol.max_pwd_life;
}
- return IPAPWD_POLICY_OK;
+ data->policy = pol;
+
+ return ret;
}
/* Searches the dn in directory,
@@ -1154,10 +882,12 @@ int ipapwd_SetPassword(struct ipapwd_krbcfg *krbcfg,
"userPassword", data->password);
/* set password history */
- pwvals = ipapwd_setPasswordHistory(smods, data);
- if (pwvals) {
- slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
- "passwordHistory", pwvals);
+ if (data->policy.history_length > 0) {
+ pwvals = ipapwd_setPasswordHistory(smods, data);
+ if (pwvals) {
+ slapi_mods_add_mod_values(smods, LDAP_MOD_REPLACE,
+ "passwordHistory", pwvals);
+ }
}
/* FIXME:
@@ -1186,111 +916,45 @@ Slapi_Value **ipapwd_setPasswordHistory(Slapi_Mods *smods,
struct ipapwd_data *data)
{
Slapi_Value **pH = NULL;
- Slapi_Attr *passwordHistory = NULL;
- char timestr[GENERALIZED_TIME_LENGTH+1];
- char *histr, *old_pw;
- struct tm utctime;
- int ret, pc;
+ char **pwd_history = NULL;
+ char **new_pwd_history = NULL;
+ int n = 0;
+ int ret;
+ int i;
- old_pw = slapi_entry_attr_get_charptr(data->target, "userPassword");
- if (!old_pw) {
- /* no old password to store, just return */
- return NULL;
- }
+ pwd_history = slapi_entry_attr_get_charray(data->target,
+ "passwordHistory");
- if (!gmtime_r(&(data->timeNow), &utctime)) {
- LOG_FATAL("failed to retrieve current date (buggy gmtime_r ?)\n");
- return NULL;
- }
- strftime(timestr, GENERALIZED_TIME_LENGTH+1, "%Y%m%d%H%M%SZ", &utctime);
+ ret = ipapwd_generate_new_history(data->password, data->timeNow,
+ data->policy.history_length,
+ pwd_history, &new_pwd_history, &n);
- histr = slapi_ch_smprintf("%s%s", timestr, old_pw);
- if (!histr) {
- LOG_OOM();
- return NULL;
+ if (ret) {
+ LOG_FATAL("failed to generate new password history!\n");
+ goto done;
}
- /* retrieve current history */
- ret = slapi_entry_attr_find(data->target,
- "passwordHistory", &passwordHistory);
- if (ret == 0) {
- int err, hint, count, i, j;
- const char *pwstr;
- Slapi_Value *pw;
-
- hint = 0;
- count = 0;
- err = slapi_attr_get_numvalues(passwordHistory, &count);
- /* if we have one */
- if (err == 0 && count > 0 && data->pwHistoryLen > 0) {
- pH = calloc(count + 2, sizeof(Slapi_Value *));
- if (!pH) {
- LOG_OOM();
- free(histr);
- return NULL;
- }
-
- i = 0;
- hint = slapi_attr_first_value(passwordHistory, &pw);
- while (hint != -1) {
- pwstr = slapi_value_get_string(pw);
- /* if shorter than GENERALIZED_TIME_LENGTH, it
- * is garbage, we never set timeless entries */
- if (pwstr &&
- (strlen(pwstr) > GENERALIZED_TIME_LENGTH)) {
- pH[i] = pw;
- i++;
- }
- hint = slapi_attr_next_value(passwordHistory, hint, &pw);
- }
-
- qsort(pH, i, sizeof(Slapi_Value *), ipapwd_sv_pw_cmp);
-
- if (i >= data->pwHistoryLen) {
- /* need to rotate out the first entry */
- for (j = 0; j < data->pwHistoryLen; j++) {
- pH[j] = pH[j + 1];
- }
-
- i = data->pwHistoryLen;
- pH[i] = NULL;
- i--;
- }
-
- pc = i;
-
- /* copy only interesting entries */
- for (i = 0; i < pc; i++) {
- pH[i] = slapi_value_dup(pH[i]);
- if (pH[i] == NULL) {
- LOG_OOM();
- while (i) {
- i--;
- slapi_value_free(&pH[i]);
- }
- free(pH);
- free(histr);
- return NULL;
- }
- }
- }
+ pH = (Slapi_Value **)slapi_ch_calloc(n + 1, sizeof(Slapi_Value *));
+ if (!pH) {
+ LOG_OOM();
+ goto done;
}
- if (pH == NULL) {
- pH = calloc(2, sizeof(Slapi_Value *));
- if (!pH) {
+ for (i = 0; i < n; i++) {
+ pH[i] = slapi_value_new_string(new_pwd_history[i]);
+ if (!pH[i]) {
+ ipapwd_free_slapi_value_array(&pH);
LOG_OOM();
- free(histr);
- return NULL;
+ goto done;
}
- pc = 0;
}
- /* add new history value */
- pH[pc] = slapi_value_new_string(histr);
-
- free(histr);
-
+done:
+ slapi_ch_array_free(pwd_history);
+ for (i = 0; i < n; i++) {
+ free(new_pwd_history[i]);
+ }
+ free(new_pwd_history);
return pH;
}