From ae6b9163be0a5a8846e8dbf2e0da2c29221781b9 Mon Sep 17 00:00:00 2001
From: Petr Mikhalicin <pmikhalicin@rutoken.ru>
Date: Fri, 10 Nov 2023 15:24:48 +0600
Subject: [PATCH] pam_sss: fix passthrow of old authtok from another pam
 modules at PAM_PRELIM_CHECK

pam_sss ignored old authtoks passed from another pam modules

Resolves: https://github.com/SSSD/sssd/issues/7007
Resolves: https://github.com/SSSD/sssd/issues/5418

Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
---
 src/sss_client/pam_sss.c | 75 ++++++++++++++++++++++++----------------
 1 file changed, 45 insertions(+), 30 deletions(-)

diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
index a1c353604..47f3f6bd3 100644
--- a/src/sss_client/pam_sss.c
+++ b/src/sss_client/pam_sss.c
@@ -2728,42 +2728,57 @@ static int get_authtok_for_password_change(pam_handle_t *pamh,
         exp_data = NULL;
     }
 
-    /* we query for the old password during PAM_PRELIM_CHECK to make
-     * pam_sss work e.g. with pam_cracklib */
     if (pam_flags & PAM_PRELIM_CHECK) {
-        if ( (getuid() != 0 || exp_data ) && !(flags & PAM_CLI_FLAGS_USE_FIRST_PASS)) {
-            if (flags & PAM_CLI_FLAGS_USE_2FA
-                    || (pi->otp_vendor != NULL && pi->otp_token_id != NULL
-                            && pi->otp_challenge != NULL)) {
-                if (pi->password_prompting) {
-                    ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "),
-                                     _("Second Factor (optional): "));
-                } else {
-                    ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "),
-                                     _("Second Factor: "));
-                }
+        if (getuid() == 0 && !exp_data )
+            return PAM_SUCCESS;
+
+        if (flags & PAM_CLI_FLAGS_USE_2FA
+                || (pi->otp_vendor != NULL && pi->otp_token_id != NULL
+                        && pi->otp_challenge != NULL)) {
+            if (pi->password_prompting) {
+                ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "),
+                                 _("Second Factor (optional): "));
             } else {
-                ret = prompt_password(pamh, pi, _("Current Password: "));
+                ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "),
+                                 _("Second Factor: "));
             }
-            if (ret != PAM_SUCCESS) {
-                D(("failed to get credentials from user"));
-                return ret;
+        } else if ((flags & PAM_CLI_FLAGS_USE_FIRST_PASS)
+                       && check_authtok_data(pamh, pi) != 0) {
+            if (pi->pamstack_oldauthtok == NULL) {
+                pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY;
+                pi->pam_authtok = NULL;
+                pi->pam_authtok_size = 0;
+            } else {
+                pi->pam_authtok = strdup(pi->pamstack_oldauthtok);
+                if (pi->pam_authtok == NULL) {
+                    D(("strdup failed"));
+                    return PAM_BUF_ERR;
+                }
+                pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD;
+                pi->pam_authtok_size = strlen(pi->pam_authtok);
             }
+            ret = PAM_SUCCESS;
+        } else {
+            ret = prompt_password(pamh, pi, _("Current Password: "));
+        }
+        if (ret != PAM_SUCCESS) {
+            D(("failed to get credentials from user"));
+            return ret;
+        }
 
-            ret = pam_set_item(pamh, PAM_OLDAUTHTOK, pi->pam_authtok);
-            if (ret != PAM_SUCCESS) {
-                D(("Failed to set PAM_OLDAUTHTOK [%s], "
-                   "oldauthtok may not be available",
-                   pam_strerror(pamh,ret)));
-                   return ret;
-            }
+        ret = pam_set_item(pamh, PAM_OLDAUTHTOK, pi->pam_authtok);
+        if (ret != PAM_SUCCESS) {
+            D(("Failed to set PAM_OLDAUTHTOK [%s], "
+                "oldauthtok may not be available",
+               pam_strerror(pamh,ret)));
+               return ret;
+        }
 
-            if (pi->pam_authtok_type == SSS_AUTHTOK_TYPE_2FA) {
-                ret = keep_authtok_data(pamh, pi);
-                if (ret != 0) {
-                    D(("Failed to store authtok data to pam handle. Password "
-                       "change might fail."));
-                }
+        if (pi->pam_authtok_type == SSS_AUTHTOK_TYPE_2FA) {
+            ret = keep_authtok_data(pamh, pi);
+            if (ret != 0) {
+                D(("Failed to store authtok data to pam handle. Password "
+                   "change might fail."));
             }
         }
 
-- 
2.33.0

