[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