[SSSD] [PATCH] Two enhancements for PAM client

Sumit Bose sbose at redhat.com
Thu Apr 22 10:08:46 UTC 2010


Hi,

the two patches attached should fix #446 and #417 respectively.

For #417 a different solution, where the message is generated by SSSD
and send to the client, would be possilbe. But I decided against it,
because with the attached patch it is possilbe to support localized
messages.

bye,
Sumit
-------------- next part --------------
From 1776ba3f543c8c7ce1adfc77555d5ff8c48a37e6 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Wed, 21 Apr 2010 10:46:01 +0200
Subject: [PATCH 1/2] Unset authentication tokens if password change fails

---
 src/sss_client/pam_sss.c |   79 ++++++++++++++++++++++++++++++----------------
 1 files changed, 52 insertions(+), 27 deletions(-)

diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
index 4208faa..77dec19 100644
--- a/src/sss_client/pam_sss.c
+++ b/src/sss_client/pam_sss.c
@@ -1201,37 +1201,62 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
 
     ret = send_and_receive(pamh, &pi, task);
 
-/* We allow sssd to send the return code PAM_NEW_AUTHTOK_REQD during
- * authentication, see sss_cli.h for details */
-    if (ret == PAM_NEW_AUTHTOK_REQD && task == SSS_PAM_AUTHENTICATE) {
-        D(("Authtoken expired, trying to change it"));
-
-        exp_data = malloc(sizeof(int));
-        if (exp_data == NULL) {
-            D(("malloc failed."));
-            return PAM_BUF_ERR;
-        }
-        *exp_data = 1;
-        ret = pam_set_data(pamh, PWEXP_FLAG, exp_data, free_exp_data);
-        if (ret != PAM_SUCCESS) {
-            D(("pam_set_data failed."));
-            return ret;
-        }
-
-        return PAM_SUCCESS;
-    }
+    switch (task) {
+        case SSS_PAM_AUTHENTICATE:
+            /* We allow sssd to send the return code PAM_NEW_AUTHTOK_REQD during
+             * authentication, see sss_cli.h for details */
+            if (ret == PAM_NEW_AUTHTOK_REQD) {
+                D(("Authtoken expired, trying to change it"));
+
+                exp_data = malloc(sizeof(int));
+                if (exp_data == NULL) {
+                    D(("malloc failed."));
+                    return PAM_BUF_ERR;
+                }
+                *exp_data = 1;
+                ret = pam_set_data(pamh, PWEXP_FLAG, exp_data, free_exp_data);
+                if (ret != PAM_SUCCESS) {
+                    D(("pam_set_data failed."));
+                    return ret;
+                }
 
-    if (ret == PAM_SUCCESS && task == SSS_PAM_ACCT_MGMT &&
-        pam_get_data(pamh, PWEXP_FLAG, (const void **) &exp_data) ==
+                return PAM_SUCCESS;
+            }
+            break;
+        case SSS_PAM_ACCT_MGMT:
+            if (ret == PAM_SUCCESS &&
+                pam_get_data(pamh, PWEXP_FLAG, (const void **) &exp_data) ==
                                                                   PAM_SUCCESS) {
-        ret = do_pam_conversation(pamh, PAM_TEXT_INFO,
-                _("Password expired. Change your password now."), NULL, NULL);
-        if (ret != PAM_SUCCESS) {
-            D(("do_pam_conversation failed."));
-        }
-        return PAM_NEW_AUTHTOK_REQD;
+                ret = do_pam_conversation(pamh, PAM_TEXT_INFO,
+                               _("Password expired. Change your password now."),
+                               NULL, NULL);
+                if (ret != PAM_SUCCESS) {
+                    D(("do_pam_conversation failed."));
+                }
+                return PAM_NEW_AUTHTOK_REQD;
+            }
+            break;
+        case SSS_PAM_CHAUTHTOK:
+            if (ret != PAM_SUCCESS && ret != PAM_USER_UNKNOWN) {
+                ret = pam_set_item(pamh, PAM_AUTHTOK, NULL);
+                if (ret != PAM_SUCCESS) {
+                    D(("Failed to unset PAM_AUTHTOK [%s]",
+                       pam_strerror(pamh,ret)));
+                }
+                ret = pam_set_item(pamh, PAM_OLDAUTHTOK, NULL);
+                if (ret != PAM_SUCCESS) {
+                    D(("Failed to unset PAM_OLDAUTHTOK [%s]",
+                       pam_strerror(pamh,ret)));
+                }
+            }
+            break;
+        default:
+            /* nothing to do */
+            break;
     }
 
+
+
     overwrite_and_free_authtoks(&pi);
 
     return ret;
-- 
1.6.6.1

-------------- next part --------------
From 5fd82f47118e3b692c5a0d95a5ac7d0cf0c3e9b8 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Wed, 21 Apr 2010 14:42:34 +0200
Subject: [PATCH 2/2] Display a message if a password reset by root fails

---
 src/man/pam_sss.8.xml          |   15 ++++
 src/providers/krb5/krb5_auth.c |    7 ++
 src/providers/ldap/ldap_auth.c |    8 ++
 src/sss_client/pam_sss.c       |  145 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 175 insertions(+), 0 deletions(-)

diff --git a/src/man/pam_sss.8.xml b/src/man/pam_sss.8.xml
index f6ac9f4..290c887 100644
--- a/src/man/pam_sss.8.xml
+++ b/src/man/pam_sss.8.xml
@@ -85,6 +85,21 @@
         </para>
     </refsect1>
 
+    <refsect1 id='files'>
+        <title>FILES</title>
+        <para>If a password reset by root fails, because the corresponding SSSD
+        provider does not support password resets, an individual message can be
+        displayed. This message can e.g. contain instructions about how to reset
+        a password.</para>
+        <para>The message is read from the file
+        <filename>pam_sss_pw_reset_message.LOC</filename> where LOC stands for a
+        locale string returned by <citerefentry>
+        <refentrytitle>setlocale</refentrytitle><manvolnum>3</manvolnum>
+        </citerefentry>. If there is no matching file the content of
+        <filename>pam_sss_pw_reset_message.txt</filename> is displayed. If this
+        file is also not present a generic message is displayed.</para>
+    </refsect1>
+
     <refsect1 id='see_also'>
         <title>SEE ALSO</title>
         <para>
diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
index 6a57fe5..e1aaebf 100644
--- a/src/providers/krb5/krb5_auth.c
+++ b/src/providers/krb5/krb5_auth.c
@@ -635,7 +635,14 @@ void krb5_pam_handler(struct be_req *be_req)
     switch (pd->cmd) {
         case SSS_PAM_AUTHENTICATE:
         case SSS_PAM_CHAUTHTOK:
+            break;
         case SSS_PAM_CHAUTHTOK_PRELIM:
+            if (pd->priv == 1 && pd->authtok_size == 0) {
+                DEBUG(4, ("Password reset by root is not supported.\n"));
+                pam_status = PAM_PERM_DENIED;
+                dp_err = DP_ERR_OK;
+                goto done;
+            }
             break;
         case SSS_PAM_ACCT_MGMT:
         case SSS_PAM_SETCRED:
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
index e0935da..95931ac 100644
--- a/src/providers/ldap/ldap_auth.c
+++ b/src/providers/ldap/ldap_auth.c
@@ -636,6 +636,14 @@ void sdap_pam_chpass_handler(struct be_req *breq)
         goto done;
     }
 
+    if (pd->priv == 1 && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM &&
+        pd->authtok_size == 0) {
+        DEBUG(4, ("Password reset by root is not supported.\n"));
+        pd->pam_status = PAM_PERM_DENIED;
+        dp_err = DP_ERR_OK;
+        goto done;
+    }
+
     DEBUG(2, ("starting password change request for user [%s].\n", pd->user));
 
     pd->pam_status = PAM_SYSTEM_ERR;
diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
index 77dec19..144aaea 100644
--- a/src/sss_client/pam_sss.c
+++ b/src/sss_client/pam_sss.c
@@ -35,6 +35,10 @@
 #include <stdio.h>
 #include <syslog.h>
 #include <time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <locale.h>
 
 #include <security/pam_modules.h>
 #include <security/pam_ext.h>
@@ -53,6 +57,9 @@
 
 #define PWEXP_FLAG "pam_sss:password_expired_flag"
 
+#define PW_RESET_MSG_FILENAME_BASE SSSD_CONF_DIR"/pam_sss_pw_reset_message"
+#define PW_RESET_MSG_MAX_SIZE 4096
+
 struct pam_items {
     const char* pam_service;
     const char* pam_user;
@@ -389,6 +396,133 @@ static int do_pam_conversation(pam_handle_t *pamh, const int msg_style,
     return PAM_SUCCESS;
 }
 
+static errno_t display_pw_reset_message(pam_handle_t *pamh, const char *suffix)
+{
+    int ret;
+    struct stat stat_buf;
+    char *msg_buf = NULL;
+    int fd = -1;
+    size_t size;
+    size_t total_len;
+    char *filename = NULL;
+
+    if (strchr(suffix, '/') != NULL) {
+        D(("Suffix contains illegal character."));
+        return EINVAL;
+    }
+
+    size = sizeof(PW_RESET_MSG_FILENAME_BASE) + 1 + strlen(suffix);
+    filename = malloc(size);
+    if (filename == NULL) {
+        D(("malloc failed."));
+        ret = ENOMEM;
+        goto done;
+    }
+    ret = snprintf(filename, size, "%s.%s", PW_RESET_MSG_FILENAME_BASE, suffix);
+    if (ret != (size - 1)) {
+        D(("snprintf failed."));
+        ret = EFAULT;
+        goto done;
+    }
+
+    ret = stat(filename, &stat_buf);
+    if (ret == -1) {
+        ret = errno;
+        D(("stat failed [%d][%s].\n", ret, strerror(ret)));
+        goto done;
+    }
+
+    if (!S_ISREG(stat_buf.st_mode)) {
+        logger(pamh, LOG_ERR,
+               "Password reset message file is not a regular file.");
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (stat_buf.st_size > PW_RESET_MSG_MAX_SIZE) {
+        logger(pamh, LOG_ERR, "Password reset message file is too large.");
+        ret = EFBIG;
+        goto done;
+    }
+
+    msg_buf = malloc(stat_buf.st_size + 1);
+    if (msg_buf == NULL) {
+        D(("malloc failed."));
+        ret = ENOMEM;
+        goto done;
+    }
+
+    fd = open(filename, O_RDONLY);
+    if (fd == -1) {
+        ret = errno;
+        D(("open failed [%d][%s].\n", ret, strerror(ret)));
+        goto done;
+    }
+
+    total_len = 0;
+    while (total_len < stat_buf.st_size) {
+        ret = read(fd, msg_buf + total_len, stat_buf.st_size - total_len);
+        if (ret == -1) {
+            if (errno == EINTR) continue;
+            ret = errno;
+            D(("open failed [%d][%s].\n", ret, strerror(ret)));
+            goto done;
+        }
+        total_len += ret;
+    }
+
+    ret = close(fd);
+    fd = -1;
+    if (ret == -1) {
+        ret = errno;
+        D(("close failed [%d][%s].\n", ret, strerror(ret)));
+    }
+
+    msg_buf[stat_buf.st_size] = '\0';
+
+    ret = do_pam_conversation(pamh, PAM_TEXT_INFO, msg_buf, NULL, NULL);
+    if (ret != PAM_SUCCESS) {
+        D(("do_pam_conversation failed."));
+    }
+
+done:
+    if (fd != -1) {
+        close(fd);
+    }
+    free(msg_buf);
+    free(filename);
+
+    return ret;
+}
+
+static errno_t select_pw_reset_message(pam_handle_t *pamh)
+{
+    int ret;
+    char *locale;
+
+    locale = setlocale(LC_MESSAGES, NULL);
+
+    ret = -1;
+    if (locale != NULL) {
+        ret = display_pw_reset_message(pamh, locale);
+    }
+
+    if (ret != 0) {
+        ret = display_pw_reset_message(pamh, "txt");
+    }
+
+    if (ret != 0) {
+        ret = do_pam_conversation(pamh, PAM_TEXT_INFO,
+                      _("Password reset by root is not supported."),
+                      NULL, NULL);
+        if (ret != PAM_SUCCESS) {
+            D(("do_pam_conversation failed."));
+        }
+    }
+
+    return ret;
+}
+
 static int user_info_offline_auth(pam_handle_t *pamh, size_t buflen,
                                   uint8_t *buf)
 {
@@ -1250,6 +1384,17 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
                 }
             }
             break;
+        case SSS_PAM_CHAUTHTOK_PRELIM:
+            if (ret == PAM_PERM_DENIED && pi.pam_authtok_size == 0 &&
+                getuid() == 0 &&
+                pam_get_data(pamh, PWEXP_FLAG, (const void **) &exp_data) !=
+                                                                  PAM_SUCCESS) {
+
+                ret = select_pw_reset_message(pamh);
+                if (ret != 0) {
+                }
+                ret = PAM_PERM_DENIED;
+            }
         default:
             /* nothing to do */
             break;
-- 
1.6.6.1



More information about the sssd-devel mailing list