diff --git a/comm.c b/comm.c index 6add38a..ff91a95 100644 --- a/comm.c +++ b/comm.c @@ -38,8 +38,8 @@ ssize_t read_comm_request(char **buf_ptr) { return size; } -bool write_comm_reply(bool success) { - if (write(comm[1][1], &success, sizeof(success)) != sizeof(success)) { +bool write_comm_reply(struct comm_reply reply) { + if (write(comm[1][1], &reply, sizeof(reply)) != sizeof(reply)) { swaylock_log_errno(LOG_ERROR, "failed to write pw check result"); return false; } @@ -95,11 +95,11 @@ out: return result; } -bool read_comm_reply(void) { - bool result = false; +struct comm_reply read_comm_reply(void) { + struct comm_reply result; if (read(comm[1][0], &result, sizeof(result)) != sizeof(result)) { swaylock_log_errno(LOG_ERROR, "Failed to read pw result"); - result = false; + result.kind = REPLY_AUTH_ERR; } return result; } diff --git a/include/comm.h b/include/comm.h index defc2f4..f390b39 100644 --- a/include/comm.h +++ b/include/comm.h @@ -5,13 +5,25 @@ struct swaylock_password; +enum conn_reply_kind { + REPLY_SUCCESS, + REPLY_AUTH_ERR, + REPLY_CONTINUE, + REPLY_MSG, +}; + +struct comm_reply { + enum conn_reply_kind kind; + char pam_msg[256]; +}; + bool spawn_comm_child(void); ssize_t read_comm_request(char **buf_ptr); -bool write_comm_reply(bool success); +bool write_comm_reply(struct comm_reply reply); // 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); +struct comm_reply read_comm_reply(void); // FD to poll for password authentication replies. int get_comm_reply_fd(void); diff --git a/include/swaylock.h b/include/swaylock.h index b9ddda7..3e7292d 100644 --- a/include/swaylock.h +++ b/include/swaylock.h @@ -17,6 +17,7 @@ enum auth_state { AUTH_STATE_BACKSPACE, AUTH_STATE_VALIDATING, AUTH_STATE_INVALID, + AUTH_STATE_IDLE_MSG, }; struct swaylock_colorset { @@ -93,6 +94,7 @@ struct swaylock_state { bool run_display, locked; struct ext_session_lock_manager_v1 *ext_session_lock_manager_v1; struct ext_session_lock_v1 *ext_session_lock_v1; + char pam_msg[256]; }; struct swaylock_surface { diff --git a/main.c b/main.c index 7b86168..43a3a07 100644 --- a/main.c +++ b/main.c @@ -1117,14 +1117,28 @@ static void display_in(int fd, short mask, void *data) { } static void comm_in(int fd, short mask, void *data) { - if (read_comm_reply()) { + struct comm_reply reply = read_comm_reply(); + if (reply.kind == REPLY_SUCCESS) { // Authentication succeeded state.run_display = false; - } else { + } else if (reply.kind == REPLY_AUTH_ERR) { state.auth_state = AUTH_STATE_INVALID; schedule_indicator_clear(&state); ++state.failed_attempts; damage_state(&state); + } else if (reply.kind == REPLY_CONTINUE) { + state.auth_state = AUTH_STATE_IDLE; + schedule_indicator_clear(&state); + damage_state(&state); + } else if (reply.kind == REPLY_MSG) { + state.auth_state = AUTH_STATE_IDLE_MSG; + memcpy(&state.pam_msg[0], &reply.pam_msg[0], 256); + schedule_indicator_clear(&state); + damage_state(&state); + } + struct swaylock_surface *surface; + wl_list_for_each(surface, &state.surfaces, link) { + render_frame(surface); } } diff --git a/pam.c b/pam.c index 0e48fcc..cd4f25b 100644 --- a/pam.c +++ b/pam.c @@ -1,3 +1,4 @@ +#include #define _POSIX_C_SOURCE 200809L #include #include @@ -11,6 +12,7 @@ #include "swaylock.h" static char *pw_buf = NULL; +static bool prompt_send_response = false; void initialize_pw_backend(int argc, char **argv) { if (getuid() != geteuid() || getgid() != getegid()) { @@ -38,14 +40,41 @@ static int handle_conversation(int num_msg, const struct pam_message **msg, switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_OFF: case PAM_PROMPT_ECHO_ON: - pam_reply[i].resp = strdup(pw_buf); // PAM clears and frees this - if (pam_reply[i].resp == NULL) { - swaylock_log(LOG_ERROR, "Allocation failed"); - return PAM_ABORT; + { + if (prompt_send_response) { + prompt_send_response = false; + struct comm_reply reply; + reply.kind = REPLY_CONTINUE; + if (!write_comm_reply(reply)) { + exit(EXIT_FAILURE); + } + } + ssize_t size = read_comm_request(&pw_buf); + if (size < 0) { + exit(EXIT_FAILURE); + } else if (size == 0) { + pam_reply[i].resp = NULL; + } else { + pam_reply[i].resp = strdup(pw_buf); // PAM clears and frees this + password_buffer_destroy(pw_buf, size); + pw_buf = NULL; + if (pam_reply[i].resp == NULL) { + swaylock_log(LOG_ERROR, "Allocation failed"); + return PAM_ABORT; + } } break; + } case PAM_ERROR_MSG: case PAM_TEXT_INFO: + swaylock_log(LOG_DEBUG, "PAM message %s", msg[i]->msg); + prompt_send_response = false; + struct comm_reply reply; + reply.kind = REPLY_MSG; + strncpy(&reply.pam_msg[0], msg[i]->msg, 255); + if (!write_comm_reply(reply)) { + exit(EXIT_FAILURE); + } break; } } @@ -89,16 +118,8 @@ void run_pw_backend_child(void) { int pam_status = PAM_SUCCESS; while (1) { - ssize_t size = read_comm_request(&pw_buf); - if (size < 0) { - exit(EXIT_FAILURE); - } else if (size == 0) { - break; - } - int pam_status = pam_authenticate(auth_handle, 0); - password_buffer_destroy(pw_buf, size); - pw_buf = NULL; + prompt_send_response = false; bool success = pam_status == PAM_SUCCESS; if (!success) { @@ -106,7 +127,14 @@ void run_pw_backend_child(void) { get_pam_auth_error(pam_status)); } - if (!write_comm_reply(success)) { + struct comm_reply reply; + if (success) { + reply.kind = REPLY_SUCCESS; + } else { + reply.kind = REPLY_AUTH_ERR; + } + + if (!write_comm_reply(reply)) { exit(EXIT_FAILURE); } } diff --git a/render.c b/render.c index 3ce7a80..c2c0a75 100644 --- a/render.c +++ b/render.c @@ -3,6 +3,7 @@ #include #include "cairo.h" #include "background-image.h" +#include "log.h" #include "swaylock.h" #define M_PI 3.14159265358979323846 @@ -94,7 +95,8 @@ void render_frame(struct swaylock_surface *surface) { char attempts[4]; // like i3lock: count no more than 999 char *text = NULL; - const char *layout_text = NULL; + const char *layout_text = &state->pam_msg[0]; + swaylock_log(LOG_DEBUG, "RNDR pm %s", layout_text); if (state->args.show_indicator) { switch (state->auth_state) { @@ -135,7 +137,7 @@ void render_frame(struct swaylock_surface *surface) { ++curr_layout; } // will handle invalid index if none are active - layout_text = xkb_keymap_layout_get_name(state->xkb.keymap, curr_layout); + // layout_text = xkb_keymap_layout_get_name(state->xkb.keymap, curr_layout); } break; default: @@ -143,6 +145,7 @@ void render_frame(struct swaylock_surface *surface) { } } + // Compute the size of the buffer needed int arc_radius = state->args.radius * surface->scale; int arc_thickness = state->args.thickness * surface->scale; @@ -219,7 +222,7 @@ void render_frame(struct swaylock_surface *surface) { float type_indicator_border_thickness = TYPE_INDICATOR_BORDER_THICKNESS * surface->scale; - if (state->args.show_indicator && (state->auth_state != AUTH_STATE_IDLE || + if (state->args.show_indicator && ((state->auth_state != AUTH_STATE_IDLE) || state->args.indicator_idle_visible)) { // Fill inner circle cairo_set_line_width(cairo, 0);