+ return NULL;
+}
+
+/*
+ * Neccessary calls after ending input via enter or others
+ *
+ */
+static void finish_input(void) {
+ password[input_position] = '\0';
+ unlock_state = STATE_KEY_PRESSED;
+ redraw_screen();
+ input_done();
+}
+
+/*
+ * Resets auth_state to STATE_AUTH_IDLE 2 seconds after an unsuccessful
+ * authentication event.
+ *
+ */
+static void clear_auth_wrong(EV_P_ ev_timer *w, int revents) {
+ DEBUG("clearing auth wrong\n");
+ auth_state = STATE_AUTH_IDLE;
+ redraw_screen();
+
+ /* Clear modifier string. */
+ if (modifier_string != NULL) {
+ free(modifier_string);
+ modifier_string = NULL;
+ }
+
+ /* Now free this timeout. */
+ STOP_TIMER(clear_auth_wrong_timeout);
+
+ /* retry with input done during auth verification */
+ if (retry_verification) {
+ retry_verification = false;
+ finish_input();
+ }
+}
+
+static void clear_indicator_cb(EV_P_ ev_timer *w, int revents) {
+ clear_indicator();
+ STOP_TIMER(clear_indicator_timeout);
+}
+
+static void clear_input(void) {
+ input_position = 0;
+ clear_password_memory();
+ password[input_position] = '\0';
+}
+
+static void discard_passwd_cb(EV_P_ ev_timer *w, int revents) {
+ clear_input();
+ STOP_TIMER(discard_passwd_timeout);
+}
+
+static void input_done(void) {
+ STOP_TIMER(clear_auth_wrong_timeout);
+ auth_state = STATE_AUTH_VERIFY;
+ unlock_state = STATE_STARTED;
+ redraw_screen();
+
+#ifdef __OpenBSD__
+ struct passwd *pw;
+
+ if (!(pw = getpwuid(getuid())))
+ errx(1, "unknown uid %u.", getuid());
+
+ if (auth_userokay(pw->pw_name, NULL, NULL, password) != 0) {
+ DEBUG("successfully authenticated\n");
+ clear_password_memory();
+
+ exit(0);
+ }
+#else
+ if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) {
+ DEBUG("successfully authenticated\n");
+ clear_password_memory();
+
+ /* PAM credentials should be refreshed, this will for example update any kerberos tickets.
+ * Related to credentials pam_end() needs to be called to cleanup any temporary
+ * credentials like kerberos /tmp/krb5cc_pam_* files which may of been left behind if the
+ * refresh of the credentials failed. */
+ pam_setcred(pam_handle, PAM_REFRESH_CRED);
+ pam_end(pam_handle, PAM_SUCCESS);
+
+ exit(0);
+ }
+#endif
+
+ if (debug_mode)
+ fprintf(stderr, "Authentication failure\n");
+
+ /* Get state of Caps and Num lock modifiers, to be displayed in
+ * STATE_AUTH_WRONG state */
+ xkb_mod_index_t idx, num_mods;
+ const char *mod_name;
+
+ num_mods = xkb_keymap_num_mods(xkb_keymap);
+
+ for (idx = 0; idx < num_mods; idx++) {
+ if (!xkb_state_mod_index_is_active(xkb_state, idx, XKB_STATE_MODS_EFFECTIVE))
+ continue;
+
+ mod_name = xkb_keymap_mod_get_name(xkb_keymap, idx);
+ if (mod_name == NULL)
+ continue;
+
+ /* Replace certain xkb names with nicer, human-readable ones. */
+ if (strcmp(mod_name, XKB_MOD_NAME_CAPS) == 0)
+ mod_name = "Caps Lock";
+ else if (strcmp(mod_name, XKB_MOD_NAME_ALT) == 0)
+ mod_name = "Alt";
+ else if (strcmp(mod_name, XKB_MOD_NAME_NUM) == 0)
+ mod_name = "Num Lock";
+ else if (strcmp(mod_name, XKB_MOD_NAME_LOGO) == 0)
+ mod_name = "Win";
+
+ char *tmp;
+ if (modifier_string == NULL) {
+ if (asprintf(&tmp, "%s", mod_name) != -1)
+ modifier_string = tmp;
+ } else if (asprintf(&tmp, "%s, %s", modifier_string, mod_name) != -1) {
+ free(modifier_string);
+ modifier_string = tmp;
+ }
+ }
+
+ auth_state = STATE_AUTH_WRONG;
+ failed_attempts += 1;
+ clear_input();
+ if (unlock_indicator)
+ redraw_screen();
+
+ /* Clear this state after 2 seconds (unless the user enters another
+ * password during that time). */
+ ev_now_update(main_loop);
+ START_TIMER(clear_auth_wrong_timeout, TSTAMP_N_SECS(2), clear_auth_wrong);
+
+ /* Cancel the clear_indicator_timeout, it would hide the unlock indicator
+ * too early. */
+ STOP_TIMER(clear_indicator_timeout);
+
+ /* beep on authentication failure, if enabled */
+ if (beep) {
+ xcb_bell(conn, 100);
+ xcb_flush(conn);
+ }
+}
+
+static void redraw_timeout(EV_P_ ev_timer *w, int revents) {
+ redraw_screen();
+ STOP_TIMER(w);
+}
+
+static bool skip_without_validation(void) {
+ if (input_position != 0)
+ return false;
+
+ if (skip_repeated_empty_password || ignore_empty_password)
+ return true;
+
+ return false;