Skip to content

Commit

Permalink
Issue 5834 - AccountPolicyPlugin erroring for some users (#5866)
Browse files Browse the repository at this point in the history
Bug Description: With the account policy plugin enabled and
lastloginhistory size set to non 0 an issue occurs during
simultaneous binds of the same user. In this case the timestamp
to be stored in the lastloginHistory attribute already exists from
a previous bind, and generates an error message.

A side effect of lastloginHistory feature is that the modifytimestamp
value is updated after a successful bind, even when the feature is
disabled.

Fix Description: Before a timestamp is added to the lastloginHistory
attribute a check is performed to make sure it doesnt already exist.

Ensure the entry is not modified when this feature is disabled.

Fixes:	#5834
Relates:#5752

Reviewed by: @progier389, @tbordaz  (Thank you)
  • Loading branch information
jchapma committed Aug 8, 2023
1 parent ed0093d commit ea04a04
Showing 1 changed file with 69 additions and 43 deletions.
112 changes: 69 additions & 43 deletions ldap/servers/plugins/acctpolicy/acct_plugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ acct_update_login_history(const char *dn, char *timestr)
void *plugin_id = NULL;
int rc = -1;
int num_entries = 0;
int mod_required = 0;
size_t i = 0;
char **login_hist = NULL;
Slapi_PBlock *entry_pb = NULL;
Expand All @@ -208,75 +209,100 @@ acct_update_login_history(const char *dn, char *timestr)
LDAPMod attribute;
LDAPMod *list_of_mods[2];

plugin_id = get_identity();
/* nothing to do if timestr is empty */
if (!timestr) {
return (rc);
}

plugin_id = get_identity();
sdn = slapi_sdn_new_normdn_byref(dn);
slapi_search_get_entry(&entry_pb, sdn, NULL, &e, plugin_id);
slapi_sdn_free(&sdn);

if (!timestr) {
/* if the entry doesn't exist, just return */
if (e == NULL) {
return (rc);
}

config_rd_lock();
cfg = get_config();

/* does this value already exist in the entry */
Slapi_Value *timestr_val = slapi_value_new();
slapi_value_set_string(timestr_val, timestr);
if (slapi_entry_attr_has_syntax_value(e, cfg->login_history_attr, timestr_val)) {
slapi_search_get_entry_done(&entry_pb);
slapi_value_free(&timestr_val);
config_unlock();
return 0;
}
slapi_value_free(&timestr_val);

/* history size of zero disables login history */
if (cfg->login_history_size) {
/* get login history */
login_hist = slapi_entry_attr_get_charray_ext(e, cfg->login_history_attr, &num_entries);

/* first time round */
if (!login_hist || !num_entries) {
login_hist = (char **)slapi_ch_calloc(2, sizeof(char *));
}

/* Do we need to resize login_hist array */
/* now we have an entry that doesnt contain the current timestr */
login_hist = slapi_entry_attr_get_charray_ext(e, cfg->login_history_attr, &num_entries);
if (login_hist && num_entries) {
/* do we need to trim the array */
if (num_entries >= cfg->login_history_size) {
/* free values we dont want */
int diff = (num_entries - cfg->login_history_size);
/* free times we dont need */
for (i = 0; i <= diff; i++) {
slapi_ch_free_string(&login_hist[i]);
}
/* remap array*/
for (i = 0; i < (cfg->login_history_size - 1); i++) {
login_hist[i] = login_hist[(diff + 1) + i];
/* remap array if it exists */
for (i = 0; i < cfg->login_history_size; i++) {
login_hist[i] = login_hist[diff + (i + 1)];
}
if (cfg->login_history_size != 0) {
/* append latest value */
login_hist[i - 1] = slapi_ch_smprintf("%s", timestr);
login_hist[i] = NULL;
mod_required = 1;
} else {
/* size is 0 and array has been trimmed, we need a mod */
mod_required = 1;
}
/* expand array and add current time string at the end */
login_hist = (char **)slapi_ch_realloc((char *)login_hist, sizeof(char *) * (cfg->login_history_size + 1));
login_hist[i] = slapi_ch_smprintf("%s", timestr);
login_hist[i + 1] = NULL;
} else {
/* expand array and add current time string at the end */
login_hist = (char **)slapi_ch_realloc((char *)login_hist, sizeof(char *) * (num_entries + 2));
login_hist[num_entries] = slapi_ch_smprintf("%s", timestr);
login_hist[num_entries + 1] = NULL;
if (cfg->login_history_size != 0) {
/* realloc and append latest value */
login_hist = (char **)slapi_ch_realloc((char *)login_hist, sizeof(char *) * (num_entries + 2));
login_hist[num_entries] = slapi_ch_smprintf("%s", timestr);
login_hist[num_entries + 1] = NULL;
mod_required = 1;
}
}
/* first time round */
} else if (cfg->login_history_size > 0) {
login_hist = (char **)slapi_ch_calloc(2, sizeof(char *));
/* alloc new array and append latest value */
login_hist = (char **)slapi_ch_realloc((char *)login_hist, sizeof(char *) * (num_entries + 2));
login_hist[num_entries] = slapi_ch_smprintf("%s", timestr);
login_hist[num_entries + 1] = NULL;
mod_required = 1;
}

/* modify the attribute */
attribute.mod_type = cfg->login_history_attr;
attribute.mod_op = LDAP_MOD_REPLACE;
attribute.mod_values = login_hist;

list_of_mods[0] = &attribute;
list_of_mods[1] = NULL;

mod_pb = slapi_pblock_new();
slapi_modify_internal_set_pb(mod_pb, dn, list_of_mods, NULL, NULL, plugin_id, 0);
slapi_modify_internal_pb(mod_pb);
slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
if (rc != LDAP_SUCCESS) {
slapi_log_err(SLAPI_LOG_ERR, "acct_update_login_history", "Modify error %d on entry '%s'\n", rc, dn);
if (mod_required) {
/* modify the attribute */
attribute.mod_type = cfg->login_history_attr;
attribute.mod_op = LDAP_MOD_REPLACE;
attribute.mod_values = login_hist;

list_of_mods[0] = &attribute;
list_of_mods[1] = NULL;

mod_pb = slapi_pblock_new();
slapi_modify_internal_set_pb(mod_pb, dn, list_of_mods, NULL, NULL, plugin_id, 0);
slapi_modify_internal_pb(mod_pb);
slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
if (rc != LDAP_SUCCESS) {
slapi_log_err(SLAPI_LOG_ERR, "acct_update_login_history", "Modify error %d on entry '%s'\n", rc, dn);
}
slapi_pblock_destroy(mod_pb);
}

config_unlock();

slapi_ch_array_free(login_hist);
slapi_search_get_entry_done(&entry_pb);
slapi_sdn_free(&sdn);
slapi_pblock_destroy(mod_pb);
slapi_pblock_destroy(entry_pb);
slapi_value_free(&timestr_val);

return (rc);
}
Expand Down

0 comments on commit ea04a04

Please sign in to comment.