On Mon, Oct 05, 2009 at 06:48:14AM -0400, Simo Sorce wrote: > On Mon, 2009-10-05 at 10:45 +0200, Sumit Bose wrote: > > - currently PAM_AUTHTOK_EXPIRED is returned if the password is expired > > regardless of the supplied password is correct or not. Would it be > > better to return a different error if the password is wrong? > > We should return an auth error if the password is wrong I guess > (assuming we know at the same that the password is wrong and the real > password is expired). > > We shouldn't expose to the casual attacker that the password is expired.
This is fixed in the new version of 0001 by trying to get a change password ticket. > > > - currently the pam_sss only asks the new password, because the > > current/old password is already known. Typically pam modules are > > asking for the current password for a second time (because the > > password is not know anymore) and the for the new one. I think this > > behaviour if often irritation people. Which version shall we use? > > Not sure, but as long as wee keep password change requests within the > auth module we can avoid asking for the current password once again, the > user just provided it, asking for it again adds nothing to the security > of the operation. > > I have a questions though (haven't looked at the patch yet). Do you send > back any message to the user before asking for the new password ? > Now a message is send to the user in the new version of 0003. 0002 is unchanged. > Simo. > bye, Sumit
>From 19ef4a95e16bca78abe49d71cdc78bf55e335fb3 Mon Sep 17 00:00:00 2001 From: Sumit Bose <sb...@redhat.com> Date: Fri, 2 Oct 2009 13:50:20 +0200 Subject: [PATCH 1/3] handle expired password during authentication --- server/providers/krb5/krb5_child.c | 27 +++++++++++++++++++++++++-- 1 files changed, 25 insertions(+), 2 deletions(-) diff --git a/server/providers/krb5/krb5_child.c b/server/providers/krb5/krb5_child.c index 6f69840..7649406 100644 --- a/server/providers/krb5/krb5_child.c +++ b/server/providers/krb5/krb5_child.c @@ -359,14 +359,37 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) } kerr = get_and_save_tgt(kr, pass_str); + + /* If the password is expired the KDC will always return + KRB5KDC_ERR_KEY_EXP regardless if the supplied password is correct or + not. In general the password can still be used to get a changepw ticket. + So we validate the password by trying to get a changepw ticket. */ + if (kerr == KRB5KDC_ERR_KEY_EXP) { + kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, + pass_str, NULL, NULL, 0, + kr->krb5_ctx->changepw_principle, + kr->options); + krb5_free_cred_contents(kr->ctx, kr->creds); + if (kerr == 0) { + kerr = KRB5KDC_ERR_KEY_EXP; + } + } + memset(pass_str, 0, kr->pd->authtok_size); talloc_zfree(pass_str); memset(kr->pd->authtok, 0, kr->pd->authtok_size); if (kerr != 0) { KRB5_DEBUG(1, kerr); - if (kerr == KRB5_KDC_UNREACH) { - pam_status = PAM_AUTHINFO_UNAVAIL; + switch (kerr) { + case KRB5_KDC_UNREACH: + pam_status = PAM_AUTHINFO_UNAVAIL; + break; + case KRB5KDC_ERR_KEY_EXP: + pam_status = PAM_AUTHTOK_EXPIRED; + break; + default: + pam_status = PAM_SYSTEM_ERR; } } -- 1.6.2.5
>From 24b40cd4036ae32c7f2edc0d8615c9d13ba6ce1d Mon Sep 17 00:00:00 2001 From: Sumit Bose <sb...@redhat.com> Date: Fri, 2 Oct 2009 16:03:02 +0200 Subject: [PATCH 2/3] move password handling into subroutines --- sss_client/pam_sss.c | 188 +++++++++++++++++++++++++++++++------------------- 1 files changed, 117 insertions(+), 71 deletions(-) diff --git a/sss_client/pam_sss.c b/sss_client/pam_sss.c index 9a1d441..eec25ab 100644 --- a/sss_client/pam_sss.c +++ b/sss_client/pam_sss.c @@ -651,6 +651,111 @@ static void eval_argv(pam_handle_t *pamh, int argc, const char **argv, return; } +static int get_authtok_for_authentication(pam_handle_t *pamh, + struct pam_items *pi, + uint32_t flags) +{ + int ret; + + if (flags & FLAGS_USE_FIRST_PASS) { + pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD; + pi->pam_authtok = strdup(pi->pamstack_authtok); + if (pi->pam_authtok == NULL) { + D(("option use_first_pass set, but no password found")); + return PAM_BUF_ERR; + } + pi->pam_authtok_size = strlen(pi->pam_authtok); + } else { + ret = prompt_password(pamh, pi); + if (ret != PAM_SUCCESS) { + D(("failed to get password from user")); + return ret; + } + + if (flags & FLAGS_FORWARD_PASS) { + ret = pam_set_item(pamh, PAM_AUTHTOK, pi->pam_authtok); + if (ret != PAM_SUCCESS) { + D(("Failed to set PAM_AUTHTOK [%s], " + "authtok may not be available for other modules", + pam_strerror(pamh,ret))); + } + } + } + + return PAM_SUCCESS; +} + +static int get_authtok_for_password_change(pam_handle_t *pamh, + struct pam_items *pi, + uint32_t flags, + int pam_flags) +{ + int ret; + + /* 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 && !(flags & FLAGS_USE_FIRST_PASS)) { + ret = prompt_password(pamh, pi); + if (ret != PAM_SUCCESS) { + D(("failed to get password 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; + } + } + + return PAM_SUCCESS; + } + + if (getuid() != 0) { + pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD; + pi->pam_authtok = strdup(pi->pamstack_oldauthtok); + if (pi->pam_authtok == NULL) { + D(("no password found for chauthtok")); + return PAM_BUF_ERR; + } + pi->pam_authtok_size = strlen(pi->pam_authtok); + } else { + pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY; + pi->pam_authtok = NULL; + pi->pam_authtok_size = 0; + } + + if (flags & FLAGS_USE_AUTHTOK) { + pi->pam_newauthtok_type = SSS_AUTHTOK_TYPE_PASSWORD; + pi->pam_newauthtok = strdup(pi->pamstack_authtok); + if (pi->pam_newauthtok == NULL) { + D(("option use_authtok set, but no new password found")); + return PAM_BUF_ERR; + } + pi->pam_newauthtok_size = strlen(pi->pam_newauthtok); + } else { + ret = prompt_new_password(pamh, pi); + if (ret != PAM_SUCCESS) { + D(("failed to get new password from user")); + return ret; + } + + if (flags & FLAGS_FORWARD_PASS) { + ret = pam_set_item(pamh, PAM_AUTHTOK, pi->pam_newauthtok); + if (ret != PAM_SUCCESS) { + D(("Failed to set PAM_AUTHTOK [%s], " + "oldauthtok may not be available", + pam_strerror(pamh,ret))); + } + } + } + + return PAM_SUCCESS; +} + static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh, int pam_flags, int argc, const char **argv) { @@ -673,82 +778,23 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh, switch(task) { case SSS_PAM_AUTHENTICATE: - if (flags & FLAGS_USE_FIRST_PASS) { - pi.pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD; - pi.pam_authtok = strdup(pi.pamstack_authtok); - if (pi.pam_authtok == NULL) { - D(("option use_first_pass set, but no password found")); - return PAM_BUF_ERR; - } - pi.pam_authtok_size = strlen(pi.pam_authtok); - } else { - prompt_password(pamh, &pi); - - if (flags & FLAGS_FORWARD_PASS) { - ret = pam_set_item(pamh, PAM_AUTHTOK, pi.pam_authtok); - if (ret != PAM_SUCCESS) { - D(("Failed to set PAM_AUTHTOK [%s], " - "authtok may not be available for other modules", - pam_strerror(pamh,ret))); - } - } + ret = get_authtok_for_authentication(pamh, &pi, flags); + if (ret != PAM_SUCCESS) { + D(("failed to get authentication token: %s", + pam_strerror(pamh, ret))); + return ret; } - break; case SSS_PAM_CHAUTHTOK: - /* 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 && !(flags & FLAGS_USE_FIRST_PASS)) { - prompt_password(pamh, &pi); - - 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; - } - } - - return PAM_SUCCESS; - } - - if (getuid() != 0) { - pi.pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD; - pi.pam_authtok = strdup(pi.pamstack_oldauthtok); - if (pi.pam_authtok == NULL) { - D(("no password found for chauthtok")); - return PAM_BUF_ERR; - } - pi.pam_authtok_size = strlen(pi.pam_authtok); - } else { - pi.pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY; - pi.pam_authtok = NULL; - pi.pam_authtok_size = 0; + ret = get_authtok_for_password_change(pamh, &pi, flags, pam_flags); + if (ret != PAM_SUCCESS) { + D(("failed to get tokens for password change: %s", + pam_strerror(pamh, ret))); + return ret; } - - if (flags & FLAGS_USE_AUTHTOK) { - pi.pam_newauthtok_type = SSS_AUTHTOK_TYPE_PASSWORD; - pi.pam_newauthtok = strdup(pi.pamstack_authtok); - if (pi.pam_newauthtok == NULL) { - D(("option use_authtok set, but no new password found")); - return PAM_BUF_ERR; - } - pi.pam_newauthtok_size = strlen(pi.pam_newauthtok); - } else { - prompt_new_password(pamh, &pi); - - if (flags & FLAGS_FORWARD_PASS) { - ret = pam_set_item(pamh, PAM_AUTHTOK, pi.pam_newauthtok); - if (ret != PAM_SUCCESS) { - D(("Failed to set PAM_AUTHTOK [%s], " - "oldauthtok may not be available", - pam_strerror(pamh,ret))); - } - } + if (pam_flags & PAM_PRELIM_CHECK) { + return ret; } - break; case SSS_PAM_ACCT_MGMT: case SSS_PAM_SETCRED: -- 1.6.2.5
>From 16fee9a04ed985fd9e7fe97416b2745c28094501 Mon Sep 17 00:00:00 2001 From: Sumit Bose <sb...@redhat.com> Date: Mon, 5 Oct 2009 10:23:38 +0200 Subject: [PATCH 3/3] ask for new password if password is expired --- sss_client/pam_sss.c | 47 ++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 40 insertions(+), 7 deletions(-) diff --git a/sss_client/pam_sss.c b/sss_client/pam_sss.c index eec25ab..5ac9e2f 100644 --- a/sss_client/pam_sss.c +++ b/sss_client/pam_sss.c @@ -158,6 +158,21 @@ static size_t add_string_item(enum pam_item_type type, const char *str, return rp; } +static void overwrite_and_free_authtoks(struct pam_items *pi) +{ + if (pi->pam_authtok != NULL) { + _pam_overwrite_n((void *)pi->pam_authtok, pi->pam_authtok_size); + free((void *)pi->pam_authtok); + pi->pam_authtok = NULL; + } + + if (pi->pam_newauthtok != NULL) { + _pam_overwrite_n((void *)pi->pam_newauthtok, pi->pam_newauthtok_size); + free((void *)pi->pam_newauthtok); + pi->pam_newauthtok = NULL; + } +} + static int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer) { int len; @@ -210,16 +225,10 @@ static int pack_message_v3(struct pam_items *pi, size_t *size, rp += add_authtok_item(PAM_ITEM_AUTHTOK, pi->pam_authtok_type, pi->pam_authtok, pi->pam_authtok_size, &buf[rp]); - _pam_overwrite_n((void *)pi->pam_authtok, pi->pam_authtok_size); - free((void *)pi->pam_authtok); - pi->pam_authtok = NULL; rp += add_authtok_item(PAM_ITEM_NEWAUTHTOK, pi->pam_newauthtok_type, pi->pam_newauthtok, pi->pam_newauthtok_size, &buf[rp]); - _pam_overwrite_n((void *)pi->pam_newauthtok, pi->pam_newauthtok_size); - free((void *)pi->pam_newauthtok); - pi->pam_newauthtok = NULL; ((uint32_t *)(&buf[rp]))[0] = END_OF_PAM_REQUEST; rp += sizeof(uint32_t); @@ -806,7 +815,31 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh, return PAM_SYSTEM_ERR; } - return send_and_receive(pamh, &pi, task); + ret = send_and_receive(pamh, &pi, task); + + if (ret == PAM_AUTHTOK_EXPIRED && 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); + if (ret != PAM_SUCCESS) { + D(("failed to get tokens for password change: %s", + pam_strerror(pamh, ret))); + return ret; + } + + ret = send_and_receive(pamh, &pi, SSS_PAM_CHAUTHTOK); + } + + overwrite_and_free_authtoks(&pi); + + return ret; } PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, -- 1.6.2.5
_______________________________________________ sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://fedorahosted.org/mailman/listinfo/sssd-devel