File 0008-Update-shadowLastChanged-attribute-during-LDAP-passw.patch of Package sssd.31867

From bb8bc1cc1060e0b6a1609b55e60ca468845eb87f Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 15 Jun 2022 09:07:33 +0200
Subject: [PATCH 1/4] ldap: allow password changes with shadow pwd policy
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Currently a password change is rejected if
"ldap_pwd_policy = shadow" is used because it was not clear if the
corresponding shadow LDAP attributes get updates as well. But with
commit c975031 SSSD can update the attribute on its own so there is no
need to reject the password change.

Since it is important for SSSD to know if the LDAP server can update the
shadow LDAP attribute automatically or not it is checked if the
ldap_chpass_update_last_change option is set explicitly in sssd.conf. If
not there will be a log message.

Resolves: https://github.com/SSSD/sssd/issues/6220

Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
Reviewed-by: Tomáš Halman <thalman@redhat.com>
(cherry picked from commit ce81747874bb003c78e95c4dcf6239b9251ceeaa)
---
 src/man/sssd-ldap.5.xml        |  10 +++
 src/providers/ldap/ldap_auth.c | 108 ++++++++++++++++++++++++++-------
 2 files changed, 96 insertions(+), 22 deletions(-)

diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index 1565341c4..1ae9dfdd6 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -1103,6 +1103,8 @@ host/*
                             <citerefentry><refentrytitle>shadow</refentrytitle>
                             <manvolnum>5</manvolnum></citerefentry> style
                             attributes to evaluate if the password has expired.
+                            Please see option "ldap_chpass_update_last_change"
+                            as well.
                         </para>
                         <para>
                             <emphasis>mit_kerberos</emphasis> - Use the attributes
@@ -1188,6 +1190,14 @@ host/*
                             days since the Epoch after a password change
                             operation.
                         </para>
+                        <para>
+                            It is recommend to set this option explicitly if
+                            "ldap_pwd_policy = shadow" is used to let SSSD
+                            know if the LDAP server will update
+                            shadowLastChange LDAP attribute automatically
+                            after a password change or if SSSD has to update
+                            it.
+                        </para>
                         <para>
                             Default: False
                         </para>
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
index 42ef962b4..c9d64f15b 100644
--- a/src/providers/ldap/ldap_auth.c
+++ b/src/providers/ldap/ldap_auth.c
@@ -1243,6 +1243,10 @@ struct sdap_pam_chpass_handler_state {
 };
 
 static void sdap_pam_chpass_handler_auth_done(struct tevent_req *subreq);
+static int
+sdap_pam_chpass_handler_change_step(struct sdap_pam_chpass_handler_state *state,
+                                    struct tevent_req *req,
+                                    enum pwexpire pw_expire_type);
 static void sdap_pam_chpass_handler_chpass_done(struct tevent_req *subreq);
 static void sdap_pam_chpass_handler_last_done(struct tevent_req *subreq);
 
@@ -1311,6 +1315,26 @@ immediately:
     return req;
 }
 
+static bool confdb_is_set_explicit(struct confdb_ctx *cdb, const char *section,
+                                   const char *attribute)
+{
+    int ret;
+    char **vals = NULL;
+    bool update_option_set_explictly = false;
+
+    ret = confdb_get_param(cdb, NULL, section, attribute, &vals);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "Failed to check if [%s] is set "
+              "explicitly in sssd.conf, assuming it is not set.\n",
+              attribute);
+    } else if (vals != NULL && vals[0] != NULL) {
+        update_option_set_explictly = true;
+    }
+    talloc_free(vals);
+
+    return update_option_set_explictly;
+}
+
 static void sdap_pam_chpass_handler_auth_done(struct tevent_req *subreq)
 {
     struct sdap_pam_chpass_handler_state *state;
@@ -1368,30 +1392,13 @@ static void sdap_pam_chpass_handler_auth_done(struct tevent_req *subreq)
         case ERR_PASSWORD_EXPIRED:
             DEBUG(SSSDBG_TRACE_LIBS,
                   "user [%s] successfully authenticated.\n", state->dn);
-            if (pw_expire_type == PWEXPIRE_SHADOW) {
-                /* TODO: implement async ldap modify request */
-                DEBUG(SSSDBG_CRIT_FAILURE,
-                      "Changing shadow password attributes not implemented.\n");
-                state->pd->pam_status = PAM_MODULE_UNKNOWN;
+            ret = sdap_pam_chpass_handler_change_step(state, req, pw_expire_type);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      "sdap_pam_chpass_handler_change_step() failed.\n");
                 goto done;
-            } else {
-                subreq = sdap_pam_change_password_send(state, state->ev,
-                                                       state->sh,
-                                                       state->auth_ctx->opts,
-                                                       state->pd,
-                                                       state->dn);
-                if (subreq == NULL) {
-                    DEBUG(SSSDBG_OP_FAILURE, "Failed to change password for "
-                          "%s\n", state->pd->user);
-                    state->pd->pam_status = PAM_SYSTEM_ERR;
-                    goto done;
-                }
-
-                tevent_req_set_callback(subreq,
-                                        sdap_pam_chpass_handler_chpass_done,
-                                        req);
-                return;
             }
+            return;
             break;
         case ERR_AUTH_DENIED:
         case ERR_AUTH_FAILED:
@@ -1424,6 +1431,63 @@ done:
     tevent_req_done(req);
 }
 
+static int
+sdap_pam_chpass_handler_change_step(struct sdap_pam_chpass_handler_state *state,
+                                    struct tevent_req *req,
+                                    enum pwexpire pw_expire_type)
+{
+    int ret;
+    struct tevent_req *subreq;
+    bool update_option_set_explictly = false;
+
+    if (pw_expire_type == PWEXPIRE_SHADOW) {
+
+        update_option_set_explictly = confdb_is_set_explicit(
+                   state->be_ctx->cdb, state->be_ctx->conf_path,
+                   state->auth_ctx->opts->basic[SDAP_CHPASS_UPDATE_LAST_CHANGE].opt_name);
+
+        if (!dp_opt_get_bool(state->auth_ctx->opts->basic,
+                             SDAP_CHPASS_UPDATE_LAST_CHANGE)
+                    && !update_option_set_explictly) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+               "Shadow password policy is selected but "
+               "ldap_chpass_update_last_change is not set, please "
+               "make sure your LDAP server can update the [%s] "
+               "attribute automatically. Otherwise SSSD might "
+               "consider your password as expired.\n",
+               state->auth_ctx->opts->user_map[SDAP_AT_SP_LSTCHG].name);
+        }
+        ret = sysdb_invalidate_cache_entry(state->be_ctx->domain,
+                                           state->pd->user, true);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+               "Failed to invalidate cache entry for user [%s] with error code "
+               "[%d][%s]. The last changed attribute [%s] might not get "
+               "refreshed after the password and the password might still be "
+               "considered as expired. Call sss_cache for this user "
+               "to expire the entry manually in this case.\n",
+               state->pd->user, ret, sss_strerror(ret),
+               state->auth_ctx->opts->user_map[SDAP_AT_SP_LSTCHG].name);
+        }
+    }
+    subreq = sdap_pam_change_password_send(state, state->ev,
+                                           state->sh,
+                                           state->auth_ctx->opts,
+                                           state->pd,
+                                           state->dn);
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "Failed to change password for "
+              "%s\n", state->pd->user);
+        state->pd->pam_status = PAM_SYSTEM_ERR;
+        return ENOMEM;
+    }
+
+    tevent_req_set_callback(subreq,
+                            sdap_pam_chpass_handler_chpass_done,
+                            req);
+    return EOK;
+}
+
 static void sdap_pam_chpass_handler_chpass_done(struct tevent_req *subreq)
 {
     struct sdap_pam_chpass_handler_state *state;
-- 
2.43.0


From 70f51a603ea22950064e705ab94819f7aeb3c2f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20L=C3=B3pez?= <allopez@redhat.com>
Date: Thu, 24 Nov 2022 11:22:55 +0100
Subject: [PATCH 2/4] PAM: Warn that the password has expired when using ssh
 keys
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When using ssh keys and the LDAP_ACCESS_EXPIRE_POLICY_WARN flag,
the user is notified is the password is about to expire, but
nothing was said if the password had already expired.
This patch introduces a message when the password has expired.

Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Tomáš Halman <thalman@redhat.com>
(cherry picked from commit be84d6ee83e5c0f8ff6e0fd988f5cf344b25efe5)
---
 src/man/sssd-ldap.5.xml        |  4 ----
 src/providers/ldap/ldap_auth.c | 10 ++++++++++
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index 1ae9dfdd6..753b2f21f 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -1376,10 +1376,6 @@ ldap_access_filter = (employeeType=admin)
                             pwd_expire_policy_renew - user is prompted to change
                             his password immediately.
                         </para>
-                        <para>
-                            Note If user password is expired no explicit message
-                            is prompted by SSSD.
-                        </para>
                         <para>
                             Please note that 'access_provider = ldap' must
                             be set for this feature to work. Also 'ldap_pwd_policy'
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
index c9d64f15b..98529aa58 100644
--- a/src/providers/ldap/ldap_auth.c
+++ b/src/providers/ldap/ldap_auth.c
@@ -103,6 +103,12 @@ static errno_t check_pwexpire_kerberos(const char *expire_date, time_t now,
 
     if (difftime(now, expire_time) > 0.0) {
         DEBUG(SSSDBG_CONF_SETTINGS, "Kerberos password expired.\n");
+        if (pd != NULL) {
+            ret = add_expired_warning(pd, 0);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_CRIT_FAILURE, "add_expired_warning failed.\n");
+            }
+        }
         ret = ERR_PASSWORD_EXPIRED;
     } else {
         if (pwd_exp_warning >= 0) {
@@ -156,6 +162,10 @@ static errno_t check_pwexpire_shadow(struct spwd *spwd, time_t now,
 
     if (spwd->sp_max != -1 && password_age > spwd->sp_max) {
         DEBUG(SSSDBG_CONF_SETTINGS, "Password expired.\n");
+        ret = add_expired_warning(pd, 0);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "add_expired_warning failed.\n");
+        }
         return ERR_PASSWORD_EXPIRED;
     }
 
-- 
2.43.0


From 406ba1df11f35d69c2848acc02b9aa1c25b591df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20L=C3=B3pez?= <allopez@redhat.com>
Date: Tue, 30 May 2023 16:49:06 +0200
Subject: [PATCH 3/4] PAM: Fix a possible segmentation fault

Calls to add_expired_warning(struct pam_data *pd, long exp_time) must
provide a non-NULL pd. In one of the cases this function is called
without checking that pd is not NULL. We here fix that.

Reviewed-by: Alexey Tikhonov <atikhono@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
(cherry-picked from commit 7f28816479c694ff95939e3becfbcd43423a5744)
---
 src/providers/ldap/ldap_auth.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
index 98529aa58..cdd24c2bf 100644
--- a/src/providers/ldap/ldap_auth.c
+++ b/src/providers/ldap/ldap_auth.c
@@ -162,9 +162,11 @@ static errno_t check_pwexpire_shadow(struct spwd *spwd, time_t now,
 
     if (spwd->sp_max != -1 && password_age > spwd->sp_max) {
         DEBUG(SSSDBG_CONF_SETTINGS, "Password expired.\n");
-        ret = add_expired_warning(pd, 0);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "add_expired_warning failed.\n");
+        if (pd != NULL) {
+            ret = add_expired_warning(pd, 0);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_CRIT_FAILURE, "add_expired_warning failed.\n");
+            }
         }
         return ERR_PASSWORD_EXPIRED;
     }
-- 
2.43.0


From 99007ca569fac16cb484d60fbc76161208c2d303 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20L=C3=B3pez?= <allopez@redhat.com>
Date: Mon, 25 Jul 2022 18:40:33 +0200
Subject: [PATCH 4/4] PAM: Localize some forgotten words.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The units (days, hours, minutes) were not localized although they were
used in a localized sentence.

Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Tomáš Halman <thalman@redhat.com>
(cherry picked from commit 11dab864e1dcf8ec362610263010e920556f6b93)
---
 src/sss_client/pam_sss.c | 34 ++++++++++++++++++++++------------
 1 file changed, 22 insertions(+), 12 deletions(-)

diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
index 106e30103..7afd6f00e 100644
--- a/src/sss_client/pam_sss.c
+++ b/src/sss_client/pam_sss.c
@@ -52,6 +52,7 @@
 
 #include <libintl.h>
 #define _(STRING) dgettext (PACKAGE, STRING)
+#define _n(SINGULAR, PLURAL, VALUE) dngettext(PACKAGE, SINGULAR, PLURAL, VALUE)
 
 #define PWEXP_FLAG "pam_sss:password_expired_flag"
 #define FD_DESTRUCTOR "pam_sss:fd_destructor"
@@ -587,26 +588,35 @@ static int user_info_expire_warn(pam_handle_t *pamh,
     int ret;
     uint32_t expire;
     char user_msg[256];
-    const char* unit="second(s)";
+    const char* unit;
 
     if (buflen != 2* sizeof(uint32_t)) {
         D(("User info response data has the wrong size"));
         return PAM_BUF_ERR;
     }
     memcpy(&expire, buf + sizeof(uint32_t), sizeof(uint32_t));
-    if (expire >= DAYSEC) {
-        expire /= DAYSEC;
-        unit = "day(s)";
-    } else if (expire >= HOURSEC) {
-        expire /= HOURSEC;
-        unit = "hour(s)";
-    } else if (expire >= MINSEC) {
-        expire /= MINSEC;
-        unit = "minute(s)";
+    /* expire == 0 indicates the password expired */
+    if (expire != 0) {
+        if (expire >= DAYSEC) {
+            expire /= DAYSEC;
+            unit = _n("day", "days", expire);
+        } else if (expire >= HOURSEC) {
+            expire /= HOURSEC;
+            unit = _n("hour", "hours", expire);
+        } else if (expire >= MINSEC) {
+            expire /= MINSEC;
+            unit = _n("minute", "minutes", expire);
+        } else {
+            unit = _n("second", "seconds", expire);
+        }
+
+        ret = snprintf(user_msg, sizeof(user_msg),
+                       _("Your password will expire in %1$d %2$s."), expire, unit);
+    } else {
+        ret = snprintf(user_msg, sizeof(user_msg),
+                       _("Your password has expired."));
     }
 
-    ret = snprintf(user_msg, sizeof(user_msg),
-                   _("Your password will expire in %1$d %2$s."), expire, unit);
     if (ret < 0 || ret >= sizeof(user_msg)) {
         D(("snprintf failed."));
         return PAM_SYSTEM_ERR;
-- 
2.43.0

openSUSE Build Service is sponsored by