From 1c1693ee1a74f27caaef416d9dce5c14b0ad53f9 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Tue, 18 Mar 2014 16:48:11 +0100 Subject: KRB5: Do not attempt to get a TGT after a password change using OTP https://fedorahosted.org/sssd/ticket/2271 The current krb5_child code attempts to get a TGT for the convenience of the user using the new password after a password change operation. However, an OTP should never be used twice, which means we can't perform the kinit operation after chpass is finished. Instead, we only print a PAM information instructing the user to log out and back in manually. Reviewed-by: Alexander Bokovoy --- src/providers/krb5/krb5_auth.c | 21 ++++++++++++++++++--- src/providers/krb5/krb5_child.c | 12 ++++++++++++ src/sss_client/pam_sss.c | 19 +++++++++++++++++++ src/sss_client/sss_cli.h | 3 +++ 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index ce461f5ad..48c0746ef 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -815,6 +815,7 @@ static void krb5_auth_done(struct tevent_req *subreq) char *renew_interval_str; time_t renew_interval_time = 0; bool use_enterprise_principal; + uint32_t user_info_type; ret = handle_child_recv(subreq, pd, &buf, &len); talloc_zfree(subreq); @@ -1062,9 +1063,23 @@ static void krb5_auth_done(struct tevent_req *subreq) ret = sss_krb5_check_ccache_princ(kr->uid, kr->gid, kr->ccname, kr->upn); if (ret) { - DEBUG(SSSDBG_CRIT_FAILURE, - ("No ccache for %s in %s?\n", kr->upn, kr->ccname)); - goto done; + if (res->otp == true && pd->cmd == SSS_PAM_CHAUTHTOK) { + DEBUG(SSSDBG_IMPORTANT_INFO, + ("Password change succeeded but currently " + "post-chpass kinit is not implemented\n")); + + user_info_type = SSS_PAM_USER_INFO_OTP_CHPASS; + ret = pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t), + (const uint8_t *) &user_info_type); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("pam_add_response failed.\n")); + /* Not fatal */ + } + } else { + DEBUG(SSSDBG_CRIT_FAILURE, + ("No ccache for %s in %s?\n", kr->upn, kr->ccname)); + goto done; + } } if (kr->old_ccname) { diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index d000d7016..3ee49e467 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -45,6 +45,7 @@ struct krb5_req { krb5_principal princ; char* name; krb5_creds *creds; + bool otp; krb5_get_init_creds_opt *options; struct pam_data *pd; @@ -370,6 +371,8 @@ static krb5_error_code answer_otp(krb5_context ctx, goto done; } + kr->otp = true; + /* Validate our assumptions about the contents of authtok. */ ret = sss_authtok_get_password(kr->pd->authtok, &pwd, &len); if (ret != EOK) @@ -694,6 +697,8 @@ static errno_t k5c_send_data(struct krb5_req *kr, int fd, errno_t error) size_t len; int ret; + DEBUG(SSSDBG_FUNC_DATA, ("Received error code %d\n", error)); + ret = pack_response_packet(kr, error, kr->pd->resp_list, &buf, &len); if (ret != EOK) { DEBUG(1, ("pack_response_packet failed.\n")); @@ -1110,6 +1115,8 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim) prompter, kr, 0, SSSD_KRB5_CHANGEPW_PRINCIPAL, kr->options); + DEBUG(SSSDBG_TRACE_INTERNAL, + ("chpass is%s using OTP\n", kr->otp ? "" : " not")); if (kerr != 0) { ret = pack_user_info_chpass_error(kr->pd, "Old password not accepted.", &msg_len, &msg); @@ -1205,6 +1212,11 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim) krb5_free_cred_contents(kr->ctx, kr->creds); + if (kr->otp == true) { + sss_authtok_set_empty(kr->pd->newauthtok); + return map_krb5_error(kerr); + } + /* We changed some of the gic options for the password change, now we have * to change them back to get a fresh TGT. */ revert_changepw_options(kr->options); diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c index 4ff38f299..e629fc19b 100644 --- a/src/sss_client/pam_sss.c +++ b/src/sss_client/pam_sss.c @@ -771,6 +771,22 @@ static int user_info_offline_chpass(pam_handle_t *pamh) return PAM_SUCCESS; } +static int user_info_otp_chpass(pam_handle_t *pamh) +{ + int ret; + + ret = do_pam_conversation(pamh, PAM_TEXT_INFO, + _("After changing the OTP password, you need to " + "log out and back in order to acquire a ticket"), + NULL, NULL); + if (ret != PAM_SUCCESS) { + D(("do_pam_conversation failed.")); + return PAM_SYSTEM_ERR; + } + + return PAM_SUCCESS; +} + static int user_info_chpass_error(pam_handle_t *pamh, size_t buflen, uint8_t *buf) { @@ -856,6 +872,9 @@ static int eval_user_info_response(pam_handle_t *pamh, size_t buflen, case SSS_PAM_USER_INFO_OFFLINE_CHPASS: ret = user_info_offline_chpass(pamh); break; + case SSS_PAM_USER_INFO_OTP_CHPASS: + ret = user_info_otp_chpass(pamh); + break; case SSS_PAM_USER_INFO_CHPASS_ERROR: ret = user_info_chpass_error(pamh, buflen, buf); break; diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h index 285a2979a..16a08e186 100644 --- a/src/sss_client/sss_cli.h +++ b/src/sss_client/sss_cli.h @@ -451,6 +451,9 @@ enum user_info_type { * possible to change the password while * the system is offline. This message * is generated by the PAM responder. */ + SSS_PAM_USER_INFO_OTP_CHPASS, /**< Tell the user that he needs to kinit + * or login and logout to get a TGT after + * an OTP password change */ SSS_PAM_USER_INFO_CHPASS_ERROR, /**< Tell the user that a password change * failed and optionally give a reason. * @param Size of the message as unsigned -- cgit