summaryrefslogtreecommitdiffstats
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
parent94cafd6f5b63aac3ad084d14fa3be24213374021 (diff)
downloadsssd-7343ee3d775303845e2528c676c59ef3582d6b27.tar.gz
sssd-7343ee3d775303845e2528c676c59ef3582d6b27.tar.xz
sssd-7343ee3d775303845e2528c676c59ef3582d6b27.zip
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.
-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