From a0d4dd81f8b21046aae9b4f9d53c03be1414c2a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Stachowiak?= Date: Sat, 15 Nov 2025 18:08:11 +0100 Subject: [PATCH 1/2] Fix ESC/timeout incorrectly counting as failed login attempt When the user presses ESC or the prompt times out, the auth UI sends PTYPE_RESPONSE_CANCELLED to the PAM conversation handler. Previously, this returned PAM_CONV_ERR, which caused some PAM modules (particularly with PAM 1.4.0+) to attempt authentication with empty input, resulting in PAM_AUTH_ERR. This was counted by pam_faillock as a failed login attempt, potentially locking users out after 3 ESC presses or timeouts. The fix returns PAM_ABORT instead of PAM_CONV_ERR when receiving PTYPE_RESPONSE_CANCELLED. This cleanly aborts the PAM authentication session without counting as a failed attempt, which is the correct semantic meaning of a user-initiated cancellation. Fixes #114 Amp-Thread-ID: https://ampcode.com/threads/T-60336806-26ca-40b3-bb77-86a913f74a0c Co-authored-by: Amp --- helpers/authproto_pam.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/helpers/authproto_pam.c b/helpers/authproto_pam.c index d060e22..fbd13bc 100644 --- a/helpers/authproto_pam.c +++ b/helpers/authproto_pam.c @@ -44,11 +44,25 @@ int ConverseOne(const struct pam_message *msg, struct pam_response *resp) { case PAM_PROMPT_ECHO_OFF: { WritePacket(1, PTYPE_PROMPT_LIKE_PASSWORD, msg->msg); char type = ReadPacket(0, &resp->resp, 0); + if (type == PTYPE_RESPONSE_CANCELLED) { + // User pressed ESC or prompt timed out. Return PAM_ABORT to cleanly + // abort the authentication session. Returning PAM_CONV_ERR instead would + // cause some PAM modules to attempt authentication with empty input, + // which trips faillock and counts as a failed login attempt. + return PAM_ABORT; + } return type == PTYPE_RESPONSE_LIKE_PASSWORD ? PAM_SUCCESS : PAM_CONV_ERR; } case PAM_PROMPT_ECHO_ON: { WritePacket(1, PTYPE_PROMPT_LIKE_USERNAME, msg->msg); char type = ReadPacket(0, &resp->resp, 0); + if (type == PTYPE_RESPONSE_CANCELLED) { + // User pressed ESC or prompt timed out. Return PAM_ABORT to cleanly + // abort the authentication session. Returning PAM_CONV_ERR instead would + // cause some PAM modules to attempt authentication with empty input, + // which trips faillock and counts as a failed login attempt. + return PAM_ABORT; + } return type == PTYPE_RESPONSE_LIKE_USERNAME ? PAM_SUCCESS : PAM_CONV_ERR; } case PAM_ERROR_MSG: From 779903c663b00cfdd8728ff9cc88d382b973ff18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Stachowiak?= Date: Sat, 15 Nov 2025 18:08:11 +0100 Subject: [PATCH 2/2] Make ESC clear password field instead of canceling prompt Change the behavior of the ESC key to clear the password input field (similar to Ctrl-U) instead of immediately canceling the authentication prompt. This provides better UX - users who accidentally start typing their password can press ESC to clear it and try again, rather than having the prompt close. Users can still cancel the prompt by waiting for the timeout, and the previous commit ensures timeout/cancellation won't count as a failed login attempt. Related to #114 Amp-Thread-ID: https://ampcode.com/threads/T-60336806-26ca-40b3-bb77-86a913f74a0c Co-authored-by: Amp --- helpers/auth_x11.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/helpers/auth_x11.c b/helpers/auth_x11.c index 58a1913..18d0dab 100644 --- a/helpers/auth_x11.c +++ b/helpers/auth_x11.c @@ -1306,8 +1306,14 @@ int Prompt(const char *msg, char **response, int echo) { BumpDisplayMarker(priv.pwlen, &priv.displaymarker, &priv.last_keystroke); break; - case 0: // Shouldn't happen. case '\033': // Escape. + // Clear the input line (like Ctrl-U). User can still press ESC + // again or wait for timeout to cancel the prompt entirely. + priv.pwlen = 0; + BumpDisplayMarker(priv.pwlen, &priv.displaymarker, + &priv.last_keystroke); + break; + case 0: // Shouldn't happen. done = 1; break; case '\r': // Return.