summaryrefslogtreecommitdiff
path: root/i3lock.c
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 /i3lock.c
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
Diffstat (limited to 'i3lock.c')
-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.