From 72a7fd0ded236a16b00bb4e26221f7e23b702a53 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Fri, 13 Sep 2024 15:45:59 +0200 Subject: [PATCH] ldap: add 'exop_force' value for ldap_pwmodify_mode In case the LDAP server allows to run the extended operation to change a password even if an authenticated bind fails due to missing grace logins the new option 'exop_force' can be used to run the extended operation to change the password anyways. :config: Added `exop_force` value for configuration option `ldap_pwmodify_mode`. This can be used to force a password change even if no grace logins are left. Depending on the configuration of the LDAP server it might be expected that the password change will fail. --- src/man/sssd-ldap.5.xml | 11 +++++++++ src/providers/ipa/ipa_auth.c | 3 ++- src/providers/ldap/ldap_auth.c | 5 +++- src/providers/ldap/ldap_options.c | 2 ++ src/providers/ldap/sdap.h | 5 ++-- src/providers/ldap/sdap_async.h | 3 ++- src/providers/ldap/sdap_async_connection.c | 27 +++++++++++++++++----- 7 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml index a6f9b1c97b9..d50aa65b2c1 100644 --- a/src/man/sssd-ldap.5.xml +++ b/src/man/sssd-ldap.5.xml @@ -234,6 +234,17 @@ userPassword (not recommended). + + + exop_force - Try Password Modify + Extended Operation (RFC 3062) even if + there are no grace logins left. + Depending on the type and configuration + of the LDAP server the password change + might fail because an authenticated bind + is not possible. + + diff --git a/src/providers/ipa/ipa_auth.c b/src/providers/ipa/ipa_auth.c index e238d0623de..db1cd6ad39f 100644 --- a/src/providers/ipa/ipa_auth.c +++ b/src/providers/ipa/ipa_auth.c @@ -397,7 +397,8 @@ static void ipa_pam_auth_handler_connect_done(struct tevent_req *subreq) SDAP_USE_PPOLICY); subreq = sdap_auth_send(state, state->ev, sh, NULL, NULL, dn, - state->pd->authtok, timeout, use_ppolicy); + state->pd->authtok, timeout, use_ppolicy, + state->auth_ctx->sdap_auth_ctx->opts->pwmodify_mode); if (subreq == NULL) { goto done; } diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c index 9ccbdabdbee..370cdf17188 100644 --- a/src/providers/ldap/ldap_auth.c +++ b/src/providers/ldap/ldap_auth.c @@ -914,7 +914,8 @@ static void auth_do_bind(struct tevent_req *req) subreq = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, state->dn, state->authtok, - timeout, use_ppolicy); + timeout, use_ppolicy, + state->ctx->opts->pwmodify_mode); if (!subreq) { tevent_req_error(req, ENOMEM); return; @@ -1208,6 +1209,7 @@ sdap_pam_change_password_send(TALLOC_CTX *mem_ctx, switch (opts->pwmodify_mode) { case SDAP_PWMODIFY_EXOP: + case SDAP_PWMODIFY_EXOP_FORCE: use_ppolicy = dp_opt_get_bool(opts->basic, SDAP_USE_PPOLICY); subreq = sdap_exop_modify_passwd_send(state, ev, sh, user_dn, password, new_password, @@ -1252,6 +1254,7 @@ static void sdap_pam_change_password_done(struct tevent_req *subreq) switch (state->mode) { case SDAP_PWMODIFY_EXOP: + case SDAP_PWMODIFY_EXOP_FORCE: ret = sdap_exop_modify_passwd_recv(subreq, state, &state->user_error_message); break; diff --git a/src/providers/ldap/ldap_options.c b/src/providers/ldap/ldap_options.c index 277bcb529fe..72a95300d74 100644 --- a/src/providers/ldap/ldap_options.c +++ b/src/providers/ldap/ldap_options.c @@ -294,6 +294,8 @@ int ldap_get_options(TALLOC_CTX *memctx, opts->pwmodify_mode = SDAP_PWMODIFY_EXOP; } else if (strcasecmp(pwmodify, "ldap_modify") == 0) { opts->pwmodify_mode = SDAP_PWMODIFY_LDAP; + } else if (strcasecmp(pwmodify, "exop_force") == 0) { + opts->pwmodify_mode = SDAP_PWMODIFY_EXOP_FORCE; } else { DEBUG(SSSDBG_FATAL_FAILURE, "Unrecognized pwmodify mode: %s\n", pwmodify); ret = EINVAL; diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h index d66ca156afe..35a4d5e1c96 100644 --- a/src/providers/ldap/sdap.h +++ b/src/providers/ldap/sdap.h @@ -550,8 +550,9 @@ struct sdap_options { /* password modify mode */ enum pwmodify_mode { - SDAP_PWMODIFY_EXOP = 1, /* pwmodify extended operation */ - SDAP_PWMODIFY_LDAP = 2 /* ldap_modify of userPassword */ + SDAP_PWMODIFY_EXOP = 1, /* pwmodify extended operation */ + SDAP_PWMODIFY_LDAP = 2, /* ldap_modify of userPassword */ + SDAP_PWMODIFY_EXOP_FORCE = 3 /* forced pwmodify extended operation */ } pwmodify_mode; /* The search bases for the domain or its subdomain */ diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h index a78a1157ccc..700cd6f9c44 100644 --- a/src/providers/ldap/sdap_async.h +++ b/src/providers/ldap/sdap_async.h @@ -147,7 +147,8 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *user_dn, struct sss_auth_token *authtok, int simple_bind_timeout, - bool use_ppolicy); + bool use_ppolicy, + enum pwmodify_mode pwmodify_mode); errno_t sdap_auth_recv(struct tevent_req *req, TALLOC_CTX *memctx, diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c index a6d4ee4438b..67c09835b79 100644 --- a/src/providers/ldap/sdap_async_connection.c +++ b/src/providers/ldap/sdap_async_connection.c @@ -646,6 +646,7 @@ struct simple_bind_state { struct tevent_context *ev; struct sdap_handle *sh; const char *user_dn; + enum pwmodify_mode pwmodify_mode; struct sdap_op *op; @@ -663,7 +664,8 @@ static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, int timeout, const char *user_dn, struct berval *pw, - bool use_ppolicy) + bool use_ppolicy, + enum pwmodify_mode pwmodify_mode) { struct tevent_req *req; struct simple_bind_state *state; @@ -686,6 +688,7 @@ static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, state->ev = ev; state->sh = sh; state->user_dn = user_dn; + state->pwmodify_mode = pwmodify_mode; if (use_ppolicy) { ret = sss_ldap_control_create(LDAP_CONTROL_PASSWORDPOLICYREQUEST, @@ -872,7 +875,12 @@ static void simple_bind_done(struct sdap_op *op, * Grace Authentications". */ DEBUG(SSSDBG_TRACE_LIBS, "Password expired, grace logins exhausted.\n"); - ret = ERR_AUTH_FAILED; + if (state->pwmodify_mode == SDAP_PWMODIFY_EXOP_FORCE) { + DEBUG(SSSDBG_TRACE_LIBS, "Password change forced.\n"); + ret = ERR_PASSWORD_EXPIRED; + } else { + ret = ERR_AUTH_FAILED; + } } } else if (strcmp(response_controls[c]->ldctl_oid, LDAP_CONTROL_PWEXPIRED) == 0) { @@ -885,7 +893,12 @@ static void simple_bind_done(struct sdap_op *op, if (result == LDAP_INVALID_CREDENTIALS) { DEBUG(SSSDBG_TRACE_LIBS, "Password expired, grace logins exhausted.\n"); - ret = ERR_AUTH_FAILED; + if (state->pwmodify_mode == SDAP_PWMODIFY_EXOP_FORCE) { + DEBUG(SSSDBG_TRACE_LIBS, "Password change forced.\n"); + ret = ERR_PASSWORD_EXPIRED; + } else { + ret = ERR_AUTH_FAILED; + } } else { DEBUG(SSSDBG_TRACE_LIBS, "Password expired, user must set a new password.\n"); @@ -1365,7 +1378,8 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, const char *user_dn, struct sss_auth_token *authtok, int simple_bind_timeout, - bool use_ppolicy) + bool use_ppolicy, + enum pwmodify_mode pwmodify_mode) { struct tevent_req *req, *subreq; struct sdap_auth_state *state; @@ -1404,7 +1418,7 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, pw.bv_len = pwlen; state->is_sasl = false; - subreq = simple_bind_send(state, ev, sh, simple_bind_timeout, user_dn, &pw, use_ppolicy); + subreq = simple_bind_send(state, ev, sh, simple_bind_timeout, user_dn, &pw, use_ppolicy, pwmodify_mode); if (!subreq) { tevent_req_error(req, ENOMEM); return tevent_req_post(req, ev); @@ -1981,7 +1995,8 @@ static void sdap_cli_auth_step(struct tevent_req *req) dp_opt_get_int(state->opts->basic, SDAP_OPT_TIMEOUT), dp_opt_get_bool(state->opts->basic, - SDAP_USE_PPOLICY)); + SDAP_USE_PPOLICY), + state->opts->pwmodify_mode); talloc_free(authtok); if (!subreq) { tevent_req_error(req, ENOMEM);