summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSumit Bose <sbose@redhat.com>2010-02-22 09:10:32 +0100
committerStephen Gallagher <sgallagh@redhat.com>2010-02-23 16:16:24 -0500
commit7343ee3d775303845e2528c676c59ef3582d6b27 (patch)
tree430a3aff0b029462db53a40272811b3733bbe7b7 /src
parent94cafd6f5b63aac3ad084d14fa3be24213374021 (diff)
Handle expired passwords like other PAM modules
So far we handled expired password during authentication. Other PAM modules typically detect expired password during account management and return PAM_NEW_AUTHTOK_REQD if the password is expired and should be changed. The PAM library then calls the change password routines. To meet these standards pam_sss is change accordingly. As a result it is now possible to update an expired password via ssh if sssd is running with PasswordAuthentication=yes. One drawback due to limitations of PAM is that the user now has to type his current password again before setting a new one.
Diffstat (limited to 'src')
-rw-r--r--src/providers/krb5/krb5_child.c2
-rw-r--r--src/providers/ldap/ldap_auth.c2
-rw-r--r--src/sss_client/pam_sss.c49
-rw-r--r--src/sss_client/sss_cli.h21
4 files changed, 53 insertions, 21 deletions
diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
index d1cc53fd4..08df59845 100644
--- a/src/providers/krb5/krb5_child.c
+++ b/src/providers/krb5/krb5_child.c
@@ -688,7 +688,7 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr)
pam_status = PAM_AUTHINFO_UNAVAIL;
break;
case KRB5KDC_ERR_KEY_EXP:
- pam_status = PAM_AUTHTOK_EXPIRED;
+ pam_status = PAM_NEW_AUTHTOK_REQD;
break;
case KRB5KDC_ERR_PREAUTH_FAILED:
pam_status = PAM_CRED_ERR;
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
index cfe8adb97..ba1136bdd 100644
--- a/src/providers/ldap/ldap_auth.c
+++ b/src/providers/ldap/ldap_auth.c
@@ -983,7 +983,7 @@ static void sdap_pam_auth_done(struct tevent_req *req)
state->pd->pam_status = PAM_ACCT_EXPIRED;
break;
case SDAP_AUTH_PW_EXPIRED:
- state->pd->pam_status = PAM_AUTHTOK_EXPIRED;
+ state->pd->pam_status = PAM_NEW_AUTHTOK_REQD;
break;
default:
state->pd->pam_status = PAM_SYSTEM_ERR;
diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
index a13563d36..010ca4ef6 100644
--- a/src/sss_client/pam_sss.c
+++ b/src/sss_client/pam_sss.c
@@ -46,6 +46,8 @@
#define FLAGS_FORWARD_PASS (1 << 1)
#define FLAGS_USE_AUTHTOK (1 << 2)
+#define PWEXP_FLAG "pam_sss:password_expired_flag"
+
struct pam_items {
const char* pam_service;
const char* pam_user;
@@ -101,6 +103,11 @@ static void logger(pam_handle_t *pamh, int level, const char *fmt, ...) {
va_end(ap);
}
+static void free_exp_data(pam_handle_t *pamh, void *ptr, int err)
+{
+ free(ptr);
+ ptr = NULL;
+}
static size_t add_authtok_item(enum pam_item_type type,
enum sss_authtok_type authtok_type,
@@ -847,13 +854,13 @@ done:
return pam_status;
}
-static int prompt_password(pam_handle_t *pamh, struct pam_items *pi)
+static int prompt_password(pam_handle_t *pamh, struct pam_items *pi,
+ const char *prompt)
{
int ret;
char *answer = NULL;
- ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, _("Password: "),
- NULL, &answer);
+ ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt, NULL, &answer);
if (ret != PAM_SUCCESS) {
D(("do_pam_conversation failed."));
return ret;
@@ -943,7 +950,7 @@ static int get_authtok_for_authentication(pam_handle_t *pamh,
}
pi->pam_authtok_size = strlen(pi->pam_authtok);
} else {
- ret = prompt_password(pamh, pi);
+ ret = prompt_password(pamh, pi, _("Password: "));
if (ret != PAM_SUCCESS) {
D(("failed to get password from user"));
return ret;
@@ -973,7 +980,7 @@ static int get_authtok_for_password_change(pam_handle_t *pamh,
* pam_sss work e.g. with pam_cracklib */
if (pam_flags & PAM_PRELIM_CHECK) {
if (getuid() != 0 && !(flags & FLAGS_USE_FIRST_PASS)) {
- ret = prompt_password(pamh, pi);
+ ret = prompt_password(pamh, pi, _("Current Password: "));
if (ret != PAM_SUCCESS) {
D(("failed to get password from user"));
return ret;
@@ -1040,6 +1047,7 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
int ret;
struct pam_items pi;
uint32_t flags = 0;
+ int *exp_data;
bindtextdomain(PACKAGE, LOCALEDIR);
@@ -1053,7 +1061,6 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
return ret;
}
-
switch(task) {
case SSS_PAM_AUTHENTICATE:
ret = get_authtok_for_authentication(pamh, &pi, flags);
@@ -1086,24 +1093,30 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
ret = send_and_receive(pamh, &pi, task);
- if (ret == PAM_AUTHTOK_EXPIRED && task == 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 && task == SSS_PAM_AUTHENTICATE) {
D(("Authtoken expired, trying to change it"));
- ret = do_pam_conversation(pamh, PAM_ERROR_MSG,
- _("Password has expired."), NULL, NULL);
- if (ret != PAM_SUCCESS) {
- D(("do_pam_conversation failed."));
- return PAM_SYSTEM_ERR;
- }
- pi.pamstack_oldauthtok = pi.pam_authtok;
- ret = get_authtok_for_password_change(pamh, &pi, flags, pam_flags);
+ 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(("failed to get tokens for password change: %s",
- pam_strerror(pamh, ret)));
+ D(("pam_set_data failed."));
return ret;
}
- ret = send_and_receive(pamh, &pi, SSS_PAM_CHAUTHTOK);
+ return PAM_SUCCESS;
+ }
+
+ if (ret == PAM_SUCCESS && task == SSS_PAM_ACCT_MGMT &&
+ pam_get_data(pamh, PWEXP_FLAG, (const void **) &exp_data) ==
+ PAM_SUCCESS) {
+ return PAM_NEW_AUTHTOK_REQD;
}
overwrite_and_free_authtoks(&pi);
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
index 522e0792a..1953db2f4 100644
--- a/src/sss_client/sss_cli.h
+++ b/src/sss_client/sss_cli.h
@@ -144,7 +144,26 @@ enum sss_cli_command {
/* PAM related calls */
SSS_PAM_AUTHENTICATE = 0x00F1, /**< see pam_sm_authenticate(3) for
- * details */
+ * details.
+ *
+ * Additionally we allow sssd to send
+ * the return code PAM_NEW_AUTHTOK_REQD
+ * during authentication if the
+ * authentication was successful but
+ * the authentication token is expired.
+ * To meet the standards of libpam we
+ * return PAM_SUCCESS for
+ * authentication and set a flag so
+ * that the account management module
+ * can return PAM_NEW_AUTHTOK_REQD if
+ * sssd return success for account
+ * management. We do this to reduce the
+ * communication with external servers,
+ * because there are cases, e.g.
+ * Kerberos authentication, where the
+ * information that the password is
+ * expired is already available during
+ * authentication. */
SSS_PAM_SETCRED = 0x00F2, /**< see pam_sm_setcred(3) for
* details */
SSS_PAM_ACCT_MGMT = 0x00F3, /**< see pam_sm_acct_mgmt(3) for