+
+/*
+ * Resets pam_state to STATE_PAM_IDLE 2 seconds after an unsuccesful
+ * authentication event.
+ *
+ */
+static void clear_pam_wrong(EV_P_ ev_timer *w, int revents) {
+ DEBUG("clearing pam wrong\n");
+ pam_state = STATE_PAM_IDLE;
+ unlock_state = STATE_STARTED;
+ redraw_screen();
+
+ /* Now free this timeout. */
+ ev_timer_stop(main_loop, clear_pam_wrong_timeout);
+ free(clear_pam_wrong_timeout);
+ clear_pam_wrong_timeout = NULL;
+}
+
+static void clear_input(void) {
+ input_position = 0;
+ clear_password_memory();
+ password[input_position] = '\0';
+
+ /* Hide the unlock indicator after a bit if the password buffer is
+ * empty. */
+ start_clear_indicator_timeout();
+ unlock_state = STATE_BACKSPACE_ACTIVE;
+ redraw_screen();
+ unlock_state = STATE_KEY_PRESSED;
+}
+
+static void input_done(void) {
+ if (clear_pam_wrong_timeout) {
+ ev_timer_stop(main_loop, clear_pam_wrong_timeout);
+ free(clear_pam_wrong_timeout);
+ clear_pam_wrong_timeout = NULL;
+ }
+
+ pam_state = STATE_PAM_VERIFY;
+ redraw_screen();
+
+ if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) {
+ DEBUG("successfully authenticated\n");
+ clear_password_memory();
+ exit(0);
+ }
+
+ if (debug_mode)
+ fprintf(stderr, "Authentication failure\n");
+
+ pam_state = STATE_PAM_WRONG;
+ clear_input();
+ redraw_screen();
+
+ /* Clear this state after 2 seconds (unless the user enters another
+ * password during that time). */
+ ev_now_update(main_loop);
+ if ((clear_pam_wrong_timeout = calloc(sizeof(struct ev_timer), 1))) {
+ ev_timer_init(clear_pam_wrong_timeout, clear_pam_wrong, 2.0, 0.);
+ ev_timer_start(main_loop, clear_pam_wrong_timeout);
+ }
+
+ /* Cancel the clear_indicator_timeout, it would hide the unlock indicator
+ * too early. */
+ stop_clear_indicator_timeout();
+
+ /* beep on authentication failure, if enabled */
+ if (beep) {
+ xcb_bell(conn, 100);
+ xcb_flush(conn);
+ }