From 8014c09be9ecc83964d2cc0ac2cb4914108dc6e1 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 22 Jan 2026 12:27:01 +0100 Subject: [PATCH 1/2] pam_sss: change PAM message type for PIN locked To make sure GDM can display this message together with an authentication failed error message the PAM message type has to be the same. Reviewed-by: Alexey Tikhonov Reviewed-by: Iker Pedrosa (cherry picked from commit 4ca8bb655a5cfa717fe0ba512326c2f542dde7d5) --- src/sss_client/pam_sss.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c index 21d2e7f2849..83c952b116f 100644 --- a/src/sss_client/pam_sss.c +++ b/src/sss_client/pam_sss.c @@ -732,7 +732,9 @@ static int user_info_pin_locked(pam_handle_t *pamh) { int ret; - ret = do_pam_conversation(pamh, PAM_TEXT_INFO, _("PIN locked"), + /* PAM_ERROR_MSG is used here to allow GDM to display this message + * together with an authentication failed error message. */ + ret = do_pam_conversation(pamh, PAM_ERROR_MSG, _("PIN locked"), NULL, NULL); if (ret != PAM_SUCCESS) { D(("do_pam_conversation failed.")); From 37df45fead96dda51576969365b7aa19b8fed770 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 22 Jan 2026 12:27:48 +0100 Subject: [PATCH 2/2] krb5: check for PIN locked in error message Currently the PIN locked message is only displays if the Smartcard authentication is done locally, e.g. if the system is offline. During pkinit libkrb5 does not send a dedicated error code but the error message generated by the library contains a hint. This patch checks the libkrb5 error message in case the authentication fails with the pre-authentication failed error code. This is a bit tricky because 'krb5_get_error_message()' currently only returns a defined result at the first call after a failed library call. Reviewed-by: Alexey Tikhonov Reviewed-by: Iker Pedrosa (cherry picked from commit bc3ad168e1b5ef07c11488cd745446d799ff8fd2) --- src/providers/krb5/krb5_child.c | 65 ++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index 6ad0e5286bf..217731aa9d4 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -125,18 +125,47 @@ struct krb5_req { static krb5_context krb5_error_ctx; +static inline void debug_and_log(int level, int line, + krb5_error_code krb5_error, + const char *krb5_error_msg) +{ + DEBUG(level, "%d: [%d][%s]\n", line, krb5_error, krb5_error_msg); + if (level & (SSSDBG_CRIT_FAILURE | SSSDBG_FATAL_FAILURE)) { + sss_log(SSS_LOG_ERR, "%s", krb5_error_msg); + } + + return; +} + #define KRB5_CHILD_DEBUG_INT(level, errctx, krb5_error) do { \ const char *__krb5_error_msg; \ __krb5_error_msg = sss_krb5_get_error_message(errctx, krb5_error); \ - DEBUG(level, "%d: [%d][%s]\n", __LINE__, krb5_error, __krb5_error_msg); \ - if (level & (SSSDBG_CRIT_FAILURE | SSSDBG_FATAL_FAILURE)) { \ - sss_log(SSS_LOG_ERR, "%s", __krb5_error_msg); \ - } \ + debug_and_log(level, __LINE__, krb5_error, __krb5_error_msg); \ sss_krb5_free_error_message(errctx, __krb5_error_msg); \ } while(0) #define KRB5_CHILD_DEBUG(level, error) KRB5_CHILD_DEBUG_INT(level, krb5_error_ctx, error) +static bool debug_and_check_if_pin_locked_error(krb5_context ctx, int level, + krb5_error_code krb5_error) +{ + const char *krb5_error_msg; + bool res = false; + + /* sss_krb5_free_error_message() never returns NULL */ + krb5_error_msg = sss_krb5_get_error_message(ctx, krb5_error); + + if (strstr(krb5_error_msg, "pin locked") != NULL) { + res = true; + } + + debug_and_log(level, __LINE__, krb5_error, krb5_error_msg); + + sss_krb5_free_error_message(ctx, krb5_error_msg); + + return res; +} + static krb5_error_code get_tgt_times(krb5_context ctx, const char *ccname, krb5_principal server_principal, krb5_principal client_principal, @@ -2418,6 +2447,7 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, char *cc_name; int ret; char *identity = NULL; + const uint32_t user_info_pin_locked = SSS_PAM_USER_INFO_PIN_LOCKED; kerr = sss_krb5_get_init_creds_opt_set_expire_callback(kr->ctx, kr->options, sss_krb5_expire_callback_func, @@ -2483,7 +2513,32 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, return 0; } else { if (kerr != 0) { - KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); + /* If + * - during authentication + * - the pre-authentication failed + * - while Smartcard authentication was possible + * - and Smartcard credentials were available + * check if the PIN might be locked. + * Must be called before/instead of KRB5_CHILD_DEBUG because + * krb5_get_error_message() might only return the proper error + * message at the first call. */ + if (kr->pd->cmd == SSS_PAM_AUTHENTICATE + && kerr == KRB5_PREAUTH_FAILED + && kr->pkinit_prompting == true + && IS_SC_AUTHTOK(kr->pd->authtok) ) { + if (debug_and_check_if_pin_locked_error(kr->ctx, + SSSDBG_CRIT_FAILURE, kerr) ) { + ret = pam_add_response(kr->pd, SSS_PAM_USER_INFO, + sizeof(uint32_t), + (const uint8_t *) &user_info_pin_locked); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Failed to add PIN locked message.\n"); + } + } + } else { + KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); + } if (kerr == EAGAIN) { /* The most probable reason for krb5_get_init_creds_password()