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. 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: