From a305e622a6cad3f9ba267d6810fee54b7c7c86c3 Mon Sep 17 00:00:00 2001 From: koebi Date: Sat, 7 Sep 2013 19:41:16 +0200 Subject: [PATCH] Run authentification in different process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When having i3bar in “hide” mode, it could previously be brought up while the authentication was running. This is not 100% fixed with this change, but a lot better, as the normal “raise i3lock to the top” behavior is not blocked now anymore. fixes #895 --- i3lock.c | 67 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 17 deletions(-) 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.