summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/man/sssd-ldap.5.xml2
-rw-r--r--src/providers/ipa/ipa_common.c1
-rw-r--r--src/providers/ipa/ipa_common.h2
-rw-r--r--src/providers/ldap/ldap_auth.c46
-rw-r--r--src/providers/ldap/ldap_common.c1
-rw-r--r--src/providers/ldap/sdap.h1
-rw-r--r--src/providers/ldap/sdap_async.c132
-rw-r--r--src/providers/ldap/sdap_async.h9
8 files changed, 191 insertions, 3 deletions
diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index 0d4885d24..a145e388f 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -1407,8 +1407,6 @@
<citerefentry><refentrytitle>shadow</refentrytitle>
<manvolnum>5</manvolnum></citerefentry> style
attributes to evaluate if the password has expired.
- Note that the current version of sssd cannot
- update this attribute during a password change.
</para>
<para>
<emphasis>mit_kerberos</emphasis> - Use the attributes
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index 02485b801..615cdcaa1 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -102,6 +102,7 @@ struct dp_option ipa_def_ldap_opts[] = {
{ "ldap_access_order", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_chpass_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_chpass_dns_service_name", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "ldap_chpass_update_last_change", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
{ "ldap_enumeration_search_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER },
/* Do not include ldap_auth_disable_tls_never_use_in_production in the
* manpages or SSSDConfig API
diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index 6be972966..3c32b1783 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -35,7 +35,7 @@ struct ipa_service {
/* the following defines are used to keep track of the options in the ldap
* module, so that if they change and ipa is not updated correspondingly
* this will trigger a runtime abort error */
-#define IPA_OPTS_BASIC_TEST 60
+#define IPA_OPTS_BASIC_TEST 61
#define IPA_OPTS_SVC_TEST 5
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
index f58d52fee..170a34b94 100644
--- a/src/providers/ldap/ldap_auth.c
+++ b/src/providers/ldap/ldap_auth.c
@@ -45,6 +45,7 @@
#include "db/sysdb.h"
#include "providers/ldap/ldap_common.h"
#include "providers/ldap/sdap_async.h"
+#include "providers/ldap/sdap_async_private.h"
/* MIT Kerberos has the same hardcoded warning interval of 7 days. Due to the
* fact that using the expiration time of a Kerberos password with LDAP
@@ -705,6 +706,8 @@ struct sdap_pam_chpass_state {
char *password;
char *new_password;
struct sdap_handle *sh;
+
+ struct sdap_auth_ctx *ctx;
};
static void sdap_auth4chpass_done(struct tevent_req *req);
@@ -754,6 +757,7 @@ void sdap_pam_chpass_handler(struct be_req *breq)
state->breq = breq;
state->pd = pd;
state->username = pd->user;
+ state->ctx = ctx;
state->password = talloc_strndup(state,
(char *)pd->authtok, pd->authtok_size);
if (!state->password) goto done;
@@ -782,6 +786,7 @@ done:
sdap_pam_auth_reply(breq, dp_err, pd->pam_status);
}
+static void sdap_lastchange_done(struct tevent_req *req);
static void sdap_auth4chpass_done(struct tevent_req *req)
{
struct sdap_pam_chpass_state *state =
@@ -898,6 +903,8 @@ static void sdap_pam_chpass_done(struct tevent_req *req)
int dp_err = DP_ERR_FATAL;
int ret;
char *user_error_message = NULL;
+ char *lastchanged_name;
+ struct tevent_req *subreq;
size_t msg_len;
uint8_t *msg;
@@ -935,9 +942,48 @@ static void sdap_pam_chpass_done(struct tevent_req *req)
}
}
+ if (dp_opt_get_bool(state->ctx->opts->basic,
+ SDAP_CHPASS_UPDATE_LAST_CHANGE)) {
+ lastchanged_name = state->ctx->opts->user_map[SDAP_AT_SP_LSTCHG].name;
+
+ subreq = sdap_modify_shadow_lastchange_send(state,
+ state->breq->be_ctx->ev,
+ state->sh,
+ state->dn,
+ lastchanged_name);
+ if (subreq == NULL) {
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, sdap_lastchange_done, state);
+ return;
+ }
+
+done:
+ sdap_pam_auth_reply(state->breq, dp_err, state->pd->pam_status);
+}
+
+static void sdap_lastchange_done(struct tevent_req *req)
+{
+ struct sdap_pam_chpass_state *state =
+ tevent_req_callback_data(req, struct sdap_pam_chpass_state);
+ int dp_err = DP_ERR_FATAL;
+ errno_t ret;
+
+ ret = sdap_modify_shadow_lastchange_recv(req);
+ if (ret != EOK) {
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ dp_err = DP_ERR_OK;
+ state->pd->pam_status = PAM_SUCCESS;
+
done:
sdap_pam_auth_reply(state->breq, dp_err, state->pd->pam_status);
}
+
/* ==Perform-User-Authentication-and-Password-Caching===================== */
struct sdap_pam_auth_state {
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 3b8e0eeb5..ce8848384 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -91,6 +91,7 @@ struct dp_option default_basic_opts[] = {
{ "ldap_access_order", DP_OPT_STRING, { "filter" }, NULL_STRING },
{ "ldap_chpass_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_chpass_dns_service_name", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "ldap_chpass_update_last_change", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
{ "ldap_enumeration_search_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER },
/* Do not include ldap_auth_disable_tls_never_use_in_production in the
* manpages or SSSDConfig API
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 19d9ed9ad..2a63ea830 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -202,6 +202,7 @@ enum sdap_basic_opt {
SDAP_ACCESS_ORDER,
SDAP_CHPASS_URI,
SDAP_CHPASS_DNS_SERVICE_NAME,
+ SDAP_CHPASS_UPDATE_LAST_CHANGE,
SDAP_ENUM_SEARCH_TIMEOUT,
SDAP_DISABLE_AUTH_TLS,
SDAP_PAGE_SIZE,
diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
index c2f616bef..996a6716c 100644
--- a/src/providers/ldap/sdap_async.c
+++ b/src/providers/ldap/sdap_async.c
@@ -691,6 +691,138 @@ int sdap_exop_modify_passwd_recv(struct tevent_req *req,
return EOK;
}
+/* ==Update-passwordLastChanged-attribute====================== */
+struct update_last_changed_state {
+ struct tevent_context *ev;
+ struct sdap_handle *sh;
+ struct sdap_op *op;
+
+ const char *dn;
+ LDAPMod **mods;
+};
+
+static void sdap_modify_shadow_lastchange_done(struct sdap_op *op,
+ struct sdap_msg *reply,
+ int error, void *pvt);
+
+struct tevent_req *
+sdap_modify_shadow_lastchange_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sdap_handle *sh,
+ const char *dn,
+ char *lastchanged_name)
+{
+ struct tevent_req *req;
+ struct update_last_changed_state *state;
+ char **values;
+ errno_t ret;
+ int msgid;
+
+ req = tevent_req_create(mem_ctx, &state, struct update_last_changed_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->sh = sh;
+ state->dn = dn;
+ state->mods = talloc_zero_array(state, LDAPMod *, 2);
+ if (state->mods == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ state->mods[0] = talloc_zero(state->mods, LDAPMod);
+ state->mods[1] = talloc_zero(state->mods, LDAPMod);
+ if (!state->mods[0] || !state->mods[1]) {
+ ret = ENOMEM;
+ goto done;
+ }
+ values = talloc_zero_array(state->mods[0], char *, 2);
+ if (values == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ values[0] = talloc_asprintf(values, "%ld", (long)time(NULL));
+ if (values[0] == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ state->mods[0]->mod_op = LDAP_MOD_REPLACE;
+ state->mods[0]->mod_type = lastchanged_name;
+ state->mods[0]->mod_vals.modv_strvals = values;
+ state->mods[1] = NULL;
+
+ ret = ldap_modify_ext(state->sh->ldap, state->dn, state->mods,
+ NULL, NULL, &msgid);
+ if (ret) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to send operation!\n"));
+ goto done;
+ }
+
+ ret = sdap_op_add(state, state->ev, state->sh, msgid,
+ sdap_modify_shadow_lastchange_done, req, 5, &state->op);
+ if (ret) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to set up operation!\n"));
+ goto done;
+ }
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void sdap_modify_shadow_lastchange_done(struct sdap_op *op,
+ struct sdap_msg *reply,
+ int error, void *pvt)
+{
+ struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
+ struct update_last_changed_state *state;
+ state = tevent_req_data(req, struct update_last_changed_state);
+ char *errmsg;
+ int result;
+ errno_t ret = EOK;
+ int lret;
+
+ if (error) {
+ tevent_req_error(req, error);
+ return;
+ }
+
+ lret = ldap_parse_result(state->sh->ldap, reply->msg,
+ &result, NULL, &errmsg, NULL,
+ NULL, 0);
+ if (lret != LDAP_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, ("ldap_parse_result failed (%d)\n",
+ state->op->msgid));
+ ret = EIO;
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_LIBS, ("Updating lastPwdChange result: %s(%d), %s\n",
+ sss_ldap_err2string(result),
+ result, errmsg));
+
+done:
+ ldap_memfree(errmsg);
+
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+}
+
+errno_t sdap_modify_shadow_lastchange_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
+
/* ==Fetch-RootDSE============================================= */
struct sdap_get_rootdse_state {
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 8f8af47d5..47d101492 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -132,6 +132,15 @@ int sdap_exop_modify_passwd_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
enum sdap_result *result,
char **user_error_msg);
+struct tevent_req *
+sdap_modify_shadow_lastchange_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sdap_handle *sh,
+ const char *dn,
+ char *lastchanged_name);
+
+errno_t sdap_modify_shadow_lastchange_recv(struct tevent_req *req);
+
enum connect_tls {
CON_TLS_DFL,
CON_TLS_ON,