diff --git a/i3lock.c b/i3lock.c index 74e15f2..7d1f7b3 100644 --- a/i3lock.c +++ b/i3lock.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -199,27 +200,11 @@ static void clear_input(void) { 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); - } - +static void auth_failed(void) { 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 @@ -241,6 +226,54 @@ static void input_done(void) { } } +static void child_cb(EV_P_ ev_child *child_watcher, int revents) { + if (child_watcher->rstatus != 0) { + DEBUG("Authentication successfull\n"); + clear_password_memory(); + + exit(0); + } else { + auth_failed(); + } + ev_child_stop(main_loop, child_watcher); + free(child_watcher); +} + +static void input_done(void) { + if (pam_state == STATE_PAM_VERIFY) { + return; + } + + 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(); + + /* fork to unblock pam_authenticate */ + pid_t cpid = fork(); + if (cpid == 0) { + exit(pam_authenticate(pam_handle, 0) == PAM_SUCCESS); + } else if (cpid > 0) { + clear_input(); + struct ev_child *child_watcher = calloc(sizeof(struct ev_io), 1); + ev_child_init(child_watcher, child_cb, cpid, 0); + ev_child_set(child_watcher, cpid, 0); + ev_child_start(EV_DEFAULT_ child_watcher); + } else if (cpid < 0) { + DEBUG("Could not fork"); + if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) { + DEBUG("successfully authenticated\n"); + clear_password_memory(); + exit(0); + } + auth_failed(); + } +} + /* * Called when the user releases a key. We need to leave the Mode_switch * state when the user releases the Mode_switch key.