Compare commits

..

No commits in common. "9b164de0cf452002269e49329ac2520778a79170" and "376cc5fcd486a3065b4c04ee4a1573606fb09038" have entirely different histories.

33 changed files with 124 additions and 191 deletions

View File

@ -31,12 +31,8 @@ cairo_surface_t *load_background_image(const char *path) {
err->message); err->message);
return NULL; return NULL;
} }
// Correct for embedded image orientation; typical images are not image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf);
// rotated and will be handled efficiently
GdkPixbuf *oriented = gdk_pixbuf_apply_embedded_orientation(pixbuf);
g_object_unref(pixbuf); g_object_unref(pixbuf);
image = gdk_cairo_image_surface_create_from_pixbuf(oriented);
g_object_unref(oriented);
#else #else
image = cairo_image_surface_create_from_png(path); image = cairo_image_surface_create_from_png(path);
#endif // HAVE_GDK_PIXBUF #endif // HAVE_GDK_PIXBUF

10
comm.c
View File

@ -38,8 +38,8 @@ ssize_t read_comm_request(char **buf_ptr) {
return size; return size;
} }
bool write_comm_reply(struct comm_reply reply) { bool write_comm_reply(bool success) {
if (write(comm[1][1], &reply, sizeof(reply)) != sizeof(reply)) { if (write(comm[1][1], &success, sizeof(success)) != sizeof(success)) {
swaylock_log_errno(LOG_ERROR, "failed to write pw check result"); swaylock_log_errno(LOG_ERROR, "failed to write pw check result");
return false; return false;
} }
@ -95,11 +95,11 @@ out:
return result; return result;
} }
struct comm_reply read_comm_reply(void) { bool read_comm_reply(void) {
struct comm_reply result; bool result = false;
if (read(comm[1][0], &result, sizeof(result)) != sizeof(result)) { if (read(comm[1][0], &result, sizeof(result)) != sizeof(result)) {
swaylock_log_errno(LOG_ERROR, "Failed to read pw result"); swaylock_log_errno(LOG_ERROR, "Failed to read pw result");
result.kind = REPLY_AUTH_ERR; result = false;
} }
return result; return result;
} }

View File

@ -5,25 +5,13 @@
struct swaylock_password; 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); bool spawn_comm_child(void);
ssize_t read_comm_request(char **buf_ptr); ssize_t read_comm_request(char **buf_ptr);
bool write_comm_reply(struct comm_reply reply); bool write_comm_reply(bool success);
// Requests the provided password to be checked. The password is always cleared // Requests the provided password to be checked. The password is always cleared
// when the function returns. // when the function returns.
bool write_comm_request(struct swaylock_password *pw); bool write_comm_request(struct swaylock_password *pw);
struct comm_reply read_comm_reply(void); bool read_comm_reply(void);
// FD to poll for password authentication replies. // FD to poll for password authentication replies.
int get_comm_reply_fd(void); int get_comm_reply_fd(void);

View File

@ -11,7 +11,6 @@
// Indicator state: status of authentication attempt // Indicator state: status of authentication attempt
enum auth_state { enum auth_state {
AUTH_STATE_IDLE, // nothing happening AUTH_STATE_IDLE, // nothing happening
AUTH_STATE_IDLE_MSG, // showing a PAM message
AUTH_STATE_VALIDATING, // currently validating password AUTH_STATE_VALIDATING, // currently validating password
AUTH_STATE_INVALID, // displaying message: password was wrong AUTH_STATE_INVALID, // displaying message: password was wrong
}; };
@ -101,7 +100,6 @@ struct swaylock_state {
bool run_display, locked; bool run_display, locked;
struct ext_session_lock_manager_v1 *ext_session_lock_manager_v1; struct ext_session_lock_manager_v1 *ext_session_lock_manager_v1;
struct ext_session_lock_v1 *ext_session_lock_v1; struct ext_session_lock_v1 *ext_session_lock_v1;
char pam_msg[256];
}; };
struct swaylock_surface { struct swaylock_surface {
@ -115,13 +113,12 @@ struct swaylock_surface {
struct ext_session_lock_surface_v1 *ext_session_lock_surface_v1; struct ext_session_lock_surface_v1 *ext_session_lock_surface_v1;
struct pool_buffer indicator_buffers[2]; struct pool_buffer indicator_buffers[2];
bool created; bool created;
bool dirty; bool frame_pending, dirty;
uint32_t width, height; uint32_t width, height;
int32_t scale; int32_t scale;
enum wl_output_subpixel subpixel; enum wl_output_subpixel subpixel;
char *output_name; char *output_name;
struct wl_list link; struct wl_list link;
struct wl_callback *frame;
// Dimensions of last wl_buffer committed to background surface // Dimensions of last wl_buffer committed to background surface
int last_buffer_width, last_buffer_height; int last_buffer_width, last_buffer_height;
}; };
@ -136,12 +133,12 @@ struct swaylock_image {
void swaylock_handle_key(struct swaylock_state *state, void swaylock_handle_key(struct swaylock_state *state,
xkb_keysym_t keysym, uint32_t codepoint); xkb_keysym_t keysym, uint32_t codepoint);
void render_frame_background(struct swaylock_surface *surface);
void render(struct swaylock_surface *surface); void render_frame(struct swaylock_surface *surface);
void damage_surface(struct swaylock_surface *surface);
void damage_state(struct swaylock_state *state); void damage_state(struct swaylock_state *state);
void clear_password_buffer(struct swaylock_password *pw); void clear_password_buffer(struct swaylock_password *pw);
void schedule_auth_idle(struct swaylock_state *state); void schedule_auth_idle(struct swaylock_state *state);
void schedule_auth_idle_msg(struct swaylock_state *state);
void initialize_pw_backend(int argc, char **argv); void initialize_pw_backend(int argc, char **argv);
void run_pw_backend_child(void); void run_pw_backend_child(void);

71
main.c
View File

@ -163,19 +163,59 @@ static void ext_session_lock_surface_v1_handle_configure(void *data,
surface->width = width; surface->width = width;
surface->height = height; surface->height = height;
ext_session_lock_surface_v1_ack_configure(lock_surface, serial); ext_session_lock_surface_v1_ack_configure(lock_surface, serial);
surface->dirty = true; render_frame_background(surface);
render(surface); render_frame(surface);
} }
static const struct ext_session_lock_surface_v1_listener ext_session_lock_surface_v1_listener = { static const struct ext_session_lock_surface_v1_listener ext_session_lock_surface_v1_listener = {
.configure = ext_session_lock_surface_v1_handle_configure, .configure = ext_session_lock_surface_v1_handle_configure,
}; };
static const struct wl_callback_listener surface_frame_listener;
static void surface_frame_handle_done(void *data, struct wl_callback *callback,
uint32_t time) {
struct swaylock_surface *surface = data;
wl_callback_destroy(callback);
surface->frame_pending = false;
if (surface->dirty) {
// Schedule a frame in case the surface is damaged again
struct wl_callback *callback = wl_surface_frame(surface->surface);
wl_callback_add_listener(callback, &surface_frame_listener, surface);
surface->frame_pending = true;
render_frame(surface);
surface->dirty = false;
}
}
static const struct wl_callback_listener surface_frame_listener = {
.done = surface_frame_handle_done,
};
void damage_surface(struct swaylock_surface *surface) {
if (surface->width == 0 || surface->height == 0) {
// Not yet configured
return;
}
surface->dirty = true;
if (surface->frame_pending) {
return;
}
struct wl_callback *callback = wl_surface_frame(surface->surface);
wl_callback_add_listener(callback, &surface_frame_listener, surface);
surface->frame_pending = true;
wl_surface_commit(surface->surface);
}
void damage_state(struct swaylock_state *state) { void damage_state(struct swaylock_state *state) {
struct swaylock_surface *surface; struct swaylock_surface *surface;
wl_list_for_each(surface, &state->surfaces, link) { wl_list_for_each(surface, &state->surfaces, link) {
surface->dirty = true; damage_surface(surface);
render(surface);
} }
} }
@ -186,8 +226,7 @@ static void handle_wl_output_geometry(void *data, struct wl_output *wl_output,
struct swaylock_surface *surface = data; struct swaylock_surface *surface = data;
surface->subpixel = subpixel; surface->subpixel = subpixel;
if (surface->state->run_display) { if (surface->state->run_display) {
surface->dirty = true; damage_surface(surface);
render(surface);
} }
} }
@ -208,8 +247,7 @@ static void handle_wl_output_scale(void *data, struct wl_output *output,
struct swaylock_surface *surface = data; struct swaylock_surface *surface = data;
surface->scale = factor; surface->scale = factor;
if (surface->state->run_display) { if (surface->state->run_display) {
surface->dirty = true; damage_surface(surface);
render(surface);
} }
} }
@ -1035,27 +1073,14 @@ static void display_in(int fd, short mask, void *data) {
} }
static void comm_in(int fd, short mask, void *data) { static void comm_in(int fd, short mask, void *data) {
struct comm_reply reply = read_comm_reply(); if (read_comm_reply()) {
if (reply.kind == REPLY_SUCCESS) {
// Authentication succeeded // Authentication succeeded
state.run_display = false; state.run_display = false;
} else if (mask & (POLLHUP | POLLERR)) { } else {
swaylock_log(LOG_ERROR, "Password checking subprocess crashed; exiting.");
exit(EXIT_FAILURE);
} else if (reply.kind == REPLY_AUTH_ERR) {
state.auth_state = AUTH_STATE_INVALID; state.auth_state = AUTH_STATE_INVALID;
schedule_auth_idle(&state); schedule_auth_idle(&state);
++state.failed_attempts; ++state.failed_attempts;
damage_state(&state); damage_state(&state);
} else if (reply.kind == REPLY_CONTINUE) {
state.auth_state = AUTH_STATE_IDLE;
schedule_auth_idle(&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_auth_idle_msg(&state);
damage_state(&state);
} }
} }

View File

@ -1,7 +1,7 @@
project( project(
'swaylock', 'swaylock',
'c', 'c',
version: '1.8.0', version: '1.7.2',
license: 'MIT', license: 'MIT',
meson_version: '>=0.59.0', meson_version: '>=0.59.0',
default_options: [ default_options: [

62
pam.c
View File

@ -1,4 +1,3 @@
#include <security/_pam_types.h>
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <pwd.h> #include <pwd.h>
#include <security/pam_appl.h> #include <security/pam_appl.h>
@ -12,7 +11,6 @@
#include "swaylock.h" #include "swaylock.h"
static char *pw_buf = NULL; static char *pw_buf = NULL;
static bool prompt_send_response = false;
void initialize_pw_backend(int argc, char **argv) { void initialize_pw_backend(int argc, char **argv) {
if (getuid() != geteuid() || getgid() != getegid()) { if (getuid() != geteuid() || getgid() != getegid()) {
@ -40,41 +38,14 @@ static int handle_conversation(int num_msg, const struct pam_message **msg,
switch (msg[i]->msg_style) { switch (msg[i]->msg_style) {
case PAM_PROMPT_ECHO_OFF: case PAM_PROMPT_ECHO_OFF:
case PAM_PROMPT_ECHO_ON: case PAM_PROMPT_ECHO_ON:
{ pam_reply[i].resp = strdup(pw_buf); // PAM clears and frees this
if (prompt_send_response) { if (pam_reply[i].resp == NULL) {
prompt_send_response = false; swaylock_log(LOG_ERROR, "Allocation failed");
struct comm_reply reply; return PAM_ABORT;
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; break;
}
case PAM_ERROR_MSG: case PAM_ERROR_MSG:
case PAM_TEXT_INFO: 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; break;
} }
} }
@ -118,8 +89,16 @@ void run_pw_backend_child(void) {
int pam_status = PAM_SUCCESS; int pam_status = PAM_SUCCESS;
while (1) { 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); int pam_status = pam_authenticate(auth_handle, 0);
prompt_send_response = false; password_buffer_destroy(pw_buf, size);
pw_buf = NULL;
bool success = pam_status == PAM_SUCCESS; bool success = pam_status == PAM_SUCCESS;
if (!success) { if (!success) {
@ -127,22 +106,9 @@ void run_pw_backend_child(void) {
get_pam_auth_error(pam_status)); get_pam_auth_error(pam_status));
} }
struct comm_reply reply; if (!write_comm_reply(success)) {
if (success) {
reply.kind = REPLY_SUCCESS;
} else {
reply.kind = REPLY_AUTH_ERR;
}
if (!write_comm_reply(reply)) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (success) {
/* Unsuccessful requests may be queued after a successful one;
* do not process them. */
break;
}
} }
pam_setcred(auth_handle, PAM_REFRESH_CRED); pam_setcred(auth_handle, PAM_REFRESH_CRED);

View File

@ -60,13 +60,6 @@ static void set_auth_idle(void *data) {
damage_state(state); damage_state(state);
} }
static void set_auth_idle_msg(void *data) {
struct swaylock_state *state = data;
state->auth_idle_timer = NULL;
state->auth_state = AUTH_STATE_IDLE_MSG;
damage_state(state);
}
static void schedule_input_idle(struct swaylock_state *state) { static void schedule_input_idle(struct swaylock_state *state) {
if (state->input_idle_timer) { if (state->input_idle_timer) {
loop_remove_timer(state->eventloop, state->input_idle_timer); loop_remove_timer(state->eventloop, state->input_idle_timer);
@ -90,14 +83,6 @@ void schedule_auth_idle(struct swaylock_state *state) {
state->eventloop, 3000, set_auth_idle, state); state->eventloop, 3000, set_auth_idle, state);
} }
void schedule_auth_idle_msg(struct swaylock_state *state) {
if (state->auth_idle_timer) {
loop_remove_timer(state->eventloop, state->auth_idle_timer);
}
state->auth_idle_timer = loop_add_timer(
state->eventloop, 3000, set_auth_idle_msg, state);
}
static void clear_password(void *data) { static void clear_password(void *data) {
struct swaylock_state *state = data; struct swaylock_state *state = data;
state->clear_password_timer = NULL; state->clear_password_timer = NULL;
@ -161,7 +146,7 @@ void swaylock_handle_key(struct swaylock_state *state,
state->input_state = INPUT_STATE_CLEAR; state->input_state = INPUT_STATE_CLEAR;
cancel_password_clear(state); cancel_password_clear(state);
} else { } else {
if (backspace(&state->password) && state->password.len != 0) { if (backspace(&state->password)) {
state->input_state = INPUT_STATE_BACKSPACE; state->input_state = INPUT_STATE_BACKSPACE;
schedule_password_clear(state); schedule_password_clear(state);
update_highlight(state); update_highlight(state);

View File

@ -3,7 +3,6 @@
#include <wayland-client.h> #include <wayland-client.h>
#include "cairo.h" #include "cairo.h"
#include "background-image.h" #include "background-image.h"
#include "log.h"
#include "swaylock.h" #include "swaylock.h"
#include "log.h" #include "log.h"
@ -34,23 +33,7 @@ static void set_color_for_state(cairo_t *cairo, struct swaylock_state *state,
} }
} }
static void surface_frame_handle_done(void *data, struct wl_callback *callback, void render_frame_background(struct swaylock_surface *surface) {
uint32_t time) {
struct swaylock_surface *surface = data;
wl_callback_destroy(callback);
surface->frame = NULL;
render(surface);
}
static const struct wl_callback_listener surface_frame_listener = {
.done = surface_frame_handle_done,
};
static bool render_frame(struct swaylock_surface *surface);
void render(struct swaylock_surface *surface) {
struct swaylock_state *state = surface->state; struct swaylock_state *state = surface->state;
int buffer_width = surface->width * surface->scale; int buffer_width = surface->width * surface->scale;
@ -59,17 +42,11 @@ void render(struct swaylock_surface *surface) {
return; // not yet configured return; // not yet configured
} }
if (!surface->dirty || surface->frame) { wl_surface_set_buffer_scale(surface->surface, surface->scale);
// Nothing to do or frame already pending
return;
}
bool need_destroy = false;
struct pool_buffer buffer;
if (buffer_width != surface->last_buffer_width || if (buffer_width != surface->last_buffer_width ||
buffer_height != surface->last_buffer_height) { buffer_height != surface->last_buffer_height) {
need_destroy = true; struct pool_buffer buffer;
if (!create_buffer(state->shm, &buffer, buffer_width, buffer_height, if (!create_buffer(state->shm, &buffer, buffer_width, buffer_height,
WL_SHM_FORMAT_ARGB8888)) { WL_SHM_FORMAT_ARGB8888)) {
swaylock_log(LOG_ERROR, swaylock_log(LOG_ERROR,
@ -92,23 +69,15 @@ void render(struct swaylock_surface *surface) {
cairo_restore(cairo); cairo_restore(cairo);
cairo_identity_matrix(cairo); cairo_identity_matrix(cairo);
wl_surface_set_buffer_scale(surface->surface, surface->scale);
wl_surface_attach(surface->surface, buffer.buffer, 0, 0); wl_surface_attach(surface->surface, buffer.buffer, 0, 0);
wl_surface_damage_buffer(surface->surface, 0, 0, INT32_MAX, INT32_MAX); wl_surface_damage_buffer(surface->surface, 0, 0, INT32_MAX, INT32_MAX);
need_destroy = true; wl_surface_commit(surface->surface);
destroy_buffer(&buffer);
surface->last_buffer_width = buffer_width; surface->last_buffer_width = buffer_width;
surface->last_buffer_height = buffer_height; surface->last_buffer_height = buffer_height;
} } else {
wl_surface_commit(surface->surface);
render_frame(surface);
surface->dirty = false;
surface->frame = wl_surface_frame(surface->surface);
wl_callback_add_listener(surface->frame, &surface_frame_listener, surface);
wl_surface_commit(surface->surface);
if (need_destroy) {
destroy_buffer(&buffer);
} }
} }
@ -130,7 +99,7 @@ static void configure_font_drawing(cairo_t *cairo, struct swaylock_state *state,
cairo_font_options_destroy(fo); cairo_font_options_destroy(fo);
} }
static bool render_frame(struct swaylock_surface *surface) { void render_frame(struct swaylock_surface *surface) {
struct swaylock_state *state = surface->state; struct swaylock_state *state = surface->state;
// First, compute the text that will be drawn, if any, since this // First, compute the text that will be drawn, if any, since this
@ -138,8 +107,7 @@ static bool render_frame(struct swaylock_surface *surface) {
char attempts[4]; // like i3lock: count no more than 999 char attempts[4]; // like i3lock: count no more than 999
char *text = NULL; char *text = NULL;
const char *layout_text = &state->pam_msg[0]; const char *layout_text = NULL;
swaylock_log(LOG_DEBUG, "RNDR pm %s", layout_text);
bool draw_indicator = state->args.show_indicator && bool draw_indicator = state->args.show_indicator &&
(state->auth_state != AUTH_STATE_IDLE || (state->auth_state != AUTH_STATE_IDLE ||
@ -180,12 +148,11 @@ static bool render_frame(struct swaylock_surface *surface) {
++curr_layout; ++curr_layout;
} }
// will handle invalid index if none are active // 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);
} }
} }
} }
// Compute the size of the buffer needed // Compute the size of the buffer needed
int arc_radius = state->args.radius * surface->scale; int arc_radius = state->args.radius * surface->scale;
int arc_thickness = state->args.thickness * surface->scale; int arc_thickness = state->args.thickness * surface->scale;
@ -243,8 +210,7 @@ static bool render_frame(struct swaylock_surface *surface) {
struct pool_buffer *buffer = get_next_buffer(state->shm, struct pool_buffer *buffer = get_next_buffer(state->shm,
surface->indicator_buffers, buffer_width, buffer_height); surface->indicator_buffers, buffer_width, buffer_height);
if (buffer == NULL) { if (buffer == NULL) {
swaylock_log(LOG_ERROR, "No buffer"); return;
return false;
} }
// Render the buffer // Render the buffer
@ -386,5 +352,5 @@ static bool render_frame(struct swaylock_surface *surface) {
wl_surface_damage_buffer(surface->child, 0, 0, INT32_MAX, INT32_MAX); wl_surface_damage_buffer(surface->child, 0, 0, INT32_MAX, INT32_MAX);
wl_surface_commit(surface->child); wl_surface_commit(surface->child);
return true; wl_surface_commit(surface->surface);
} }

View File

@ -1,5 +1,4 @@
#define _XOPEN_SOURCE // for crypt #define _XOPEN_SOURCE // for crypt
#include <assert.h>
#include <pwd.h> #include <pwd.h>
#include <shadow.h> #include <shadow.h>
#include <stdlib.h> #include <stdlib.h>
@ -15,23 +14,15 @@
#include "password-buffer.h" #include "password-buffer.h"
#include "swaylock.h" #include "swaylock.h"
char *encpw = NULL;
void initialize_pw_backend(int argc, char **argv) { void initialize_pw_backend(int argc, char **argv) {
/* This code runs as root */ if (geteuid() != 0) {
struct passwd *pwent = getpwuid(getuid()); swaylock_log(LOG_ERROR,
if (!pwent) { "swaylock needs to be setuid to read /etc/shadow");
swaylock_log_errno(LOG_ERROR, "failed to getpwuid");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
encpw = pwent->pw_passwd;
if (strcmp(encpw, "x") == 0) { if (!spawn_comm_child()) {
struct spwd *swent = getspnam(pwent->pw_name); exit(EXIT_FAILURE);
if (!swent) {
swaylock_log_errno(LOG_ERROR, "failed to getspnam");
exit(EXIT_FAILURE);
}
encpw = swent->sp_pwdp;
} }
if (setgid(getgid()) != 0) { if (setgid(getgid()) != 0) {
@ -47,21 +38,40 @@ void initialize_pw_backend(int argc, char **argv) {
"able to restore it after setuid/setgid)"); "able to restore it after setuid/setgid)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
}
void run_pw_backend_child(void) {
/* This code runs as root */
struct passwd *pwent = getpwuid(getuid());
if (!pwent) {
swaylock_log_errno(LOG_ERROR, "failed to getpwuid");
exit(EXIT_FAILURE);
}
char *encpw = pwent->pw_passwd;
if (strcmp(encpw, "x") == 0) {
struct spwd *swent = getspnam(pwent->pw_name);
if (!swent) {
swaylock_log_errno(LOG_ERROR, "failed to getspnam");
exit(EXIT_FAILURE);
}
encpw = swent->sp_pwdp;
}
/* We don't need any additional logging here because the parent process will
* also fail here and will handle logging for us. */
if (setgid(getgid()) != 0) {
exit(EXIT_FAILURE);
}
if (setuid(getuid()) != 0) {
exit(EXIT_FAILURE);
}
if (setuid(0) != -1) {
exit(EXIT_FAILURE);
}
/* This code does not run as root */ /* This code does not run as root */
swaylock_log(LOG_DEBUG, "Prepared to authorize user %s", pwent->pw_name); swaylock_log(LOG_DEBUG, "Prepared to authorize user %s", pwent->pw_name);
if (!spawn_comm_child()) {
exit(EXIT_FAILURE);
}
/* Buffer is only used by the child */
clear_buffer(encpw, strlen(encpw));
encpw = NULL;
}
void run_pw_backend_child(void) {
assert(encpw != NULL);
while (1) { while (1) {
char *buf; char *buf;
ssize_t size = read_comm_request(&buf); ssize_t size = read_comm_request(&buf);