From 8d9ae754b50dffafef719ad3fa44e5dd1dde47b3 Mon Sep 17 00:00:00 2001 From: Justin Stephenson Date: Fri, 1 Mar 2024 14:31:25 -0500 Subject: [PATCH 7/7] krb5: Add fallback password change support handle password changes for IPA users with multiple auth types set (passkey, password) Reviewed-by: Alexey Tikhonov Reviewed-by: Iker Pedrosa (cherry picked from commit 6c1272edf174eb4bdf236dc1ffd4287b71a43392) --- src/krb5_plugin/passkey/passkey_clpreauth.c | 5 ++ src/providers/ipa/ipa_auth.c | 13 +++++ src/providers/krb5/krb5_auth.c | 12 +++++ src/providers/krb5/krb5_auth.h | 3 ++ src/providers/krb5/krb5_child.c | 5 ++ src/providers/krb5/krb5_child_handler.c | 53 +++++++++++++++++++++ src/responder/pam/pamsrv_cmd.c | 10 ++++ 7 files changed, 101 insertions(+) diff --git a/src/krb5_plugin/passkey/passkey_clpreauth.c b/src/krb5_plugin/passkey/passkey_clpreauth.c index d2dfe6fe1..35b6a3fed 100644 --- a/src/krb5_plugin/passkey/passkey_clpreauth.c +++ b/src/krb5_plugin/passkey/passkey_clpreauth.c @@ -279,6 +279,11 @@ sss_passkeycl_process(krb5_context context, goto done; } + if (prompter == NULL) { + ret = EINVAL; + goto done; + } + /* Get FAST armor key. */ as_key = cb->fast_armor(context, rock); if (as_key == NULL) { diff --git a/src/providers/ipa/ipa_auth.c b/src/providers/ipa/ipa_auth.c index 1d61a1052..e5e1bf30c 100644 --- a/src/providers/ipa/ipa_auth.c +++ b/src/providers/ipa/ipa_auth.c @@ -258,6 +258,19 @@ static void ipa_pam_auth_handler_krb5_done(struct tevent_req *subreq) if (dp_err != DP_ERR_OK) { goto done; } + if (state->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM + && state->pd->pam_status == PAM_TRY_AGAIN) { + /* Reset this to fork a new krb5_child in handle_child_send() */ + state->pd->child_pid = 0; + subreq = krb5_auth_queue_send(state, state->ev, state->be_ctx, state->pd, + state->auth_ctx->krb5_auth_ctx); + if (subreq == NULL) { + goto done; + } + + tevent_req_set_callback(subreq, ipa_pam_auth_handler_retry_done, req); + return; + } if (state->pd->cmd == SSS_PAM_AUTHENTICATE && state->pd->pam_status == PAM_CRED_ERR diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index be34880b4..e34943b82 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -532,6 +532,18 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, ret = EOK; goto done; } + + /* If krb5_child is still running from SSS_PAM_PREAUTH, + * terminate the waiting krb5_child and send the + * CHAUTHTOK_PRELIM request again */ + if (pd->child_pid != 0) { + soft_terminate_krb5_child(state, pd, krb5_ctx); + state->pam_status = PAM_TRY_AGAIN; + state->dp_err = DP_ERR_OK; + ret = EOK; + goto done; + } + break; case SSS_CMD_RENEW: if (authtok_type != SSS_AUTHTOK_TYPE_CCFILE) { diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h index bbdbf61fc..783292bc0 100644 --- a/src/providers/krb5/krb5_auth.h +++ b/src/providers/krb5/krb5_auth.h @@ -135,6 +135,9 @@ errno_t init_renew_tgt(struct krb5_ctx *krb5_ctx, struct be_ctx *be_ctx, errno_t add_tgt_to_renew_table(struct krb5_ctx *krb5_ctx, const char *ccfile, struct tgt_times *tgtt, struct pam_data *pd, const char *upn); +errno_t soft_terminate_krb5_child(TALLOC_CTX *mem_ctx, + struct pam_data *pd, + struct krb5_ctx *krb5_ctx); /* krb5_access.c */ struct tevent_req *krb5_access_send(TALLOC_CTX *mem_ctx, diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index 26b0090b4..b8acae7d7 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -1259,6 +1259,11 @@ static krb5_error_code sss_krb5_responder(krb5_context ctx, } else if (strcmp(question_list[c], SSSD_IDP_OAUTH2_QUESTION) == 0) { kerr = answer_idp_oauth2(ctx, kr, rctx); } else if (strcmp(question_list[c], SSSD_PASSKEY_QUESTION) == 0) { + /* Skip answer_passkey for expired password changes, e.g. user with auth types + * passkey AND password set */ + if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM || kr->pd->cmd == SSS_PAM_CHAUTHTOK) { + continue; + } kerr = answer_passkey(ctx, kr, rctx); } else { DEBUG(SSSDBG_MINOR_FAILURE, "Unknown question type [%s]\n", question_list[c]); diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c index 54088e4d6..cab84b37d 100644 --- a/src/providers/krb5/krb5_child_handler.c +++ b/src/providers/krb5/krb5_child_handler.c @@ -1020,3 +1020,56 @@ parse_krb5_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t len, *_res = res; return EOK; } + +/* Closes the write end of waiting krb5_child */ +errno_t soft_terminate_krb5_child(TALLOC_CTX *mem_ctx, + struct pam_data *pd, + struct krb5_ctx *krb5_ctx) +{ + char *io_key; + struct child_io_fds *io; + TALLOC_CTX *tmp_ctx; + int ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + if (pd->child_pid == 0) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Expected waiting krb5_child.\n"); + ret = EINVAL; + goto done; + } + + io_key = talloc_asprintf(tmp_ctx, "%d", pd->child_pid); + if (io_key == NULL) { + ret = ENOMEM; + goto done; + } + + io = sss_ptr_hash_lookup(krb5_ctx->io_table, io_key, + struct child_io_fds); + if (io == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "PTR hash lookup failed.\n"); + ret = ENOMEM; + goto done; + } + + if (io->write_to_child_fd != -1) { + ret = close(io->write_to_child_fd); + io->write_to_child_fd = -1; + if (ret != EOK) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "close failed [%d][%s].\n", ret, strerror(ret)); + } + } + + ret = EOK; +done: + talloc_free(tmp_ctx); + return ret; +} diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index a7c181733..de408ced8 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -1418,6 +1418,15 @@ void pam_reply(struct pam_auth_req *preq) goto done; } +#if BUILD_PASSKEY + if(pd->cmd == SSS_PAM_AUTHENTICATE && + pd->pam_status == PAM_NEW_AUTHTOK_REQD && + sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_PASSKEY_REPLY) { + DEBUG(SSSDBG_TRACE_FUNC, "Passkey authentication reply, ignoring " + "new authtok required status\n"); + pd->pam_status = PAM_SUCCESS; + } + /* Passkey auth user notification if no TGT is granted */ if (pd->cmd == SSS_PAM_AUTHENTICATE && pd->pam_status == PAM_SUCCESS && @@ -1429,6 +1438,7 @@ void pam_reply(struct pam_auth_req *preq) "User [%s] logged in with local passkey authentication, single " "sign on ticket is not obtained.\n", pd->user); } +#endif /* BUILD_PASSKEY */ /* Account expiration warning is printed for sshd. If pam_verbosity * is equal or above PAM_VERBOSITY_INFO then all services are informed -- 2.42.0