diff --git a/comm.c b/comm.c index 9a02b24..7855a7f 100644 --- a/comm.c +++ b/comm.c @@ -6,7 +6,7 @@ #include "log.h" #include "swaylock.h" -static int comm[2][2]; +static int comm[2][2] = {{-1, -1}, {-1, -1}}; ssize_t read_comm_request(char **buf_ptr) { size_t size; @@ -69,28 +69,41 @@ bool spawn_comm_child(void) { return true; } -bool attempt_password(struct swaylock_password *pw) { +bool write_comm_request(struct swaylock_password *pw) { bool result = false; + size_t len = pw->len + 1; size_t offs = 0; if (write(comm[0][1], &len, sizeof(len)) < 0) { swaylock_log_errno(LOG_ERROR, "Failed to request pw check"); - goto ret; + goto out; } + do { ssize_t amt = write(comm[0][1], &pw->buffer[offs], len - offs); if (amt < 0) { swaylock_log_errno(LOG_ERROR, "Failed to write pw buffer"); - goto ret; + goto out; } offs += amt; } while (offs < len); - if (read(comm[1][0], &result, sizeof(result)) != sizeof(result)) { - swaylock_log_errno(LOG_ERROR, "Failed to read pw result"); - goto ret; - } - swaylock_log(LOG_DEBUG, "pw result: %d", result); -ret: + + result = true; + +out: clear_password_buffer(pw); return result; } + +bool read_comm_reply(void) { + bool result = false; + if (read(comm[1][0], &result, sizeof(result)) != sizeof(result)) { + swaylock_log_errno(LOG_ERROR, "Failed to read pw result"); + result = false; + } + return result; +} + +int get_comm_reply_fd(void) { + return comm[1][0]; +} diff --git a/include/comm.h b/include/comm.h index 8d3ff09..defc2f4 100644 --- a/include/comm.h +++ b/include/comm.h @@ -1,8 +1,18 @@ #ifndef _SWAYLOCK_COMM_H #define _SWAYLOCK_COMM_H +#include + +struct swaylock_password; + bool spawn_comm_child(void); ssize_t read_comm_request(char **buf_ptr); bool write_comm_reply(bool success); +// Requests the provided password to be checked. The password is always cleared +// when the function returns. +bool write_comm_request(struct swaylock_password *pw); +bool read_comm_reply(void); +// FD to poll for password authentication replies. +int get_comm_reply_fd(void); #endif diff --git a/include/swaylock.h b/include/swaylock.h index c33c29f..32ded18 100644 --- a/include/swaylock.h +++ b/include/swaylock.h @@ -62,7 +62,6 @@ struct swaylock_state { struct loop *eventloop; struct loop_timer *clear_indicator_timer; // clears the indicator struct loop_timer *clear_password_timer; // clears the password buffer - struct loop_timer *verify_password_timer; struct wl_display *display; struct wl_compositor *compositor; struct zwlr_layer_shell_v1 *layer_shell; @@ -110,8 +109,8 @@ void render_frame(struct swaylock_surface *surface); void render_frames(struct swaylock_state *state); void damage_surface(struct swaylock_surface *surface); void damage_state(struct swaylock_state *state); -bool attempt_password(struct swaylock_password *pw); void clear_password_buffer(struct swaylock_password *pw); +void schedule_indicator_clear(struct swaylock_state *state); void initialize_pw_backend(void); void run_pw_backend_child(void); diff --git a/main.c b/main.c index 02d6e13..6520106 100644 --- a/main.c +++ b/main.c @@ -17,6 +17,7 @@ #include #include "background-image.h" #include "cairo.h" +#include "comm.h" #include "log.h" #include "loop.h" #include "pool-buffer.h" @@ -956,6 +957,17 @@ static void display_in(int fd, short mask, void *data) { } } +static void comm_in(int fd, short mask, void *data) { + if (read_comm_reply()) { + // Authentication succeeded + state.run_display = false; + } else { + state.auth_state = AUTH_STATE_INVALID; + schedule_indicator_clear(&state); + damage_state(&state); + } +} + int main(int argc, char **argv) { swaylock_log_init(LOG_ERROR); initialize_pw_backend(); @@ -1081,6 +1093,8 @@ int main(int argc, char **argv) { loop_add_fd(state.eventloop, wl_display_get_fd(state.display), POLLIN, display_in, NULL); + loop_add_fd(state.eventloop, get_comm_reply_fd(), POLLIN, comm_in, NULL); + state.run_display = true; while (state.run_display) { errno = 0; diff --git a/password.c b/password.c index 43b6c75..2c7f0f9 100644 --- a/password.c +++ b/password.c @@ -5,6 +5,7 @@ #include #include #include +#include "comm.h" #include "log.h" #include "loop.h" #include "seat.h" @@ -51,7 +52,7 @@ static void clear_indicator(void *data) { damage_state(state); } -static void schedule_indicator_clear(struct swaylock_state *state) { +void schedule_indicator_clear(struct swaylock_state *state) { if (state->clear_indicator_timer) { loop_remove_timer(state->eventloop, state->clear_indicator_timer); } @@ -76,57 +77,28 @@ static void schedule_password_clear(struct swaylock_state *state) { state->eventloop, 10000, clear_password, state); } -static void handle_preverify_timeout(void *data) { - struct swaylock_state *state = data; - state->verify_password_timer = NULL; -} - static void submit_password(struct swaylock_state *state) { if (state->args.ignore_empty && state->password.len == 0) { return; } state->auth_state = AUTH_STATE_VALIDATING; - damage_state(state); - // We generally want to wait until all surfaces are showing the - // "verifying" state before we go and verify the password, because - // verifying it is a blocking operation. However, if the surface is on - // an output with DPMS off then it won't update, so we set a timer. - state->verify_password_timer = loop_add_timer( - state->eventloop, 50, handle_preverify_timeout, state); - - while (state->run_display && state->verify_password_timer) { - errno = 0; - if (wl_display_flush(state->display) == -1 && errno != EAGAIN) { - break; - } - loop_poll(state->eventloop); - - bool ok = 1; - struct swaylock_surface *surface; - wl_list_for_each(surface, &state->surfaces, link) { - if (surface->dirty) { - ok = 0; - } - } - if (ok) { - break; - } + if (!write_comm_request(&state->password)) { + state->auth_state = AUTH_STATE_INVALID; + schedule_indicator_clear(state); } - wl_display_flush(state->display); - if (attempt_password(&state->password)) { - state->run_display = false; - return; - } - state->auth_state = AUTH_STATE_INVALID; damage_state(state); - schedule_indicator_clear(state); } void swaylock_handle_key(struct swaylock_state *state, xkb_keysym_t keysym, uint32_t codepoint) { + // Ignore input events if validating + if (state->auth_state == AUTH_STATE_VALIDATING) { + return; + } + switch (keysym) { case XKB_KEY_KP_Enter: /* fallthrough */ case XKB_KEY_Return: