summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkoebi <koebischnell@googlemail.com>2013-09-07 19:41:16 +0200
committerMichael Stapelberg <michael@stapelberg.de>2013-09-19 06:18:41 +0200
commita305e622a6cad3f9ba267d6810fee54b7c7c86c3 (patch)
tree0e2e250c4d029a8258568a9e09d74f849dd59ee5
parent94c9274bd326bd7c4ae4c08d84fe9b553af7a69c (diff)
Run authentification in different process
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
-rw-r--r--i3lock.c67
1 files 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 <string.h>
#include <ev.h>
#include <sys/mman.h>
+#include <sys/wait.h>
#include <X11/XKBlib.h>
#include <X11/extensions/XKBfile.h>
#include <xkbcommon/xkbcommon.h>
@@ -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.