diff --git a/README.md b/README.md index 53a1047f..c6d8f16f 100644 --- a/README.md +++ b/README.md @@ -253,6 +253,10 @@ Options to XSecureLock can be passed by environment variables: the screen saver. * `XSECURELOCK_AUTH_WARNING_COLOR`: specifies the X11 color (see manpage of XParseColor) for the warning text of the auth dialog. +* `XSECURELOCK_AUTH_Y_POSITION`: vertical position of the auth dialog as a + percentage of screen height, from 0 (top) to 100 (bottom). Defaults to 50 + (vertically centered). For example, set to 80 to position the dialog near + the bottom of the screen. * `XSECURELOCK_BACKGROUND_COLOR`: specifies the X11 color (see manpage of XParseColor) for the background of the main and saver windows. * `XSECURELOCK_BLANK_TIMEOUT`: specifies the time (in seconds) before telling diff --git a/helpers/auth_x11.c b/helpers/auth_x11.c index 58a19139..563734d1 100644 --- a/helpers/auth_x11.c +++ b/helpers/auth_x11.c @@ -245,6 +245,10 @@ static int auth_sounds = 0; //! Whether to blink the cursor in the auth dialog. static int auth_cursor_blink = 1; +//! Vertical position of the auth dialog as a percentage (0=top, 50=center, +//! 100=bottom). +static int auth_y_position = 50; + //! Whether we only want a single auth window. static int single_auth_window = 0; @@ -570,7 +574,7 @@ void CreateOrUpdatePerMonitorWindow(size_t i, const Monitor *monitor, int w = region_w; int h = region_h; int x = monitor->x + (monitor->width - w) / 2 + x_offset; - int y = monitor->y + (monitor->height - h) / 2 + y_offset; + int y = monitor->y + (monitor->height - h) * auth_y_position / 100 + y_offset; // Clip to monitor. if (x < 0) { w += x; @@ -1306,8 +1310,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. @@ -1614,6 +1624,9 @@ int main(int argc_local, char **argv_local) { auth_sounds = GetIntSetting("XSECURELOCK_AUTH_SOUNDS", 0); single_auth_window = GetIntSetting("XSECURELOCK_SINGLE_AUTH_WINDOW", 0); auth_cursor_blink = GetIntSetting("XSECURELOCK_AUTH_CURSOR_BLINK", 1); + auth_y_position = GetIntSetting("XSECURELOCK_AUTH_Y_POSITION", 50); + if (auth_y_position < 0) auth_y_position = 0; + if (auth_y_position > 100) auth_y_position = 100; #ifdef HAVE_XKB_EXT show_keyboard_layout = GetIntSetting("XSECURELOCK_SHOW_KEYBOARD_LAYOUT", 1); diff --git a/helpers/authproto_pam.c b/helpers/authproto_pam.c index d060e228..fbd13bce 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: