Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drive interaction from the authentication backend (PAM) #389

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
4 changes: 4 additions & 0 deletions cairo.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
#endif

uint32_t color_with_alpha(uint32_t color, uint8_t alpha) {
return (color & 0xFFFFFF00) | alpha;
}

void cairo_set_source_u32(cairo_t *cairo, uint32_t color) {
cairo_set_source_rgba(cairo,
(color >> (3*8) & 0xFF) / 255.0,
Expand Down
153 changes: 112 additions & 41 deletions comm.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,41 +9,87 @@

static int comm[2][2] = {{-1, -1}, {-1, -1}};

ssize_t read_comm_request(char **buf_ptr) {
ssize_t write_string(int fd, const char *string, size_t len) {
size_t offs = 0;
if (write(fd, &len, sizeof(len)) < 0) {
swaylock_log_errno(LOG_ERROR, "Failed to write string size");
return -1;
}

do {
ssize_t amt = write(fd, &string[offs], len - offs);
if (amt < 0) {
swaylock_log_errno(LOG_ERROR, "Failed to write string");
//TODO: different return value for different error?
return -1;
}
offs += amt;
} while (offs < len);

return (ssize_t) len;
}

ssize_t read_string(int fd, char *(*alloc)(size_t), char **output) {
size_t size;
ssize_t amt;
amt = read(comm[0][0], &size, sizeof(size));
if (amt == 0) {
ssize_t amt = read(fd, &size, sizeof(size));
if (amt <= 0) {
swaylock_log_errno(LOG_ERROR, "Failed to read string size");
return amt;
}
if (size == 0) {
return 0;
} else if (amt < 0) {
swaylock_log_errno(LOG_ERROR, "read pw request");
return -1;
}
swaylock_log(LOG_DEBUG, "received pw check request");
char *buf = password_buffer_create(size);
char *buf = alloc(size);
if (!buf) {
return -1;
}
size_t offs = 0;
do {
amt = read(comm[0][0], &buf[offs], size - offs);
ssize_t amt = read(fd, &buf[offs], size - offs);
if (amt <= 0) {
swaylock_log_errno(LOG_ERROR, "failed to read pw");
swaylock_log_errno(LOG_ERROR, "Failed to read string");
return -1;
}
offs += (size_t)amt;
} while (offs < size);

*buf_ptr = buf;
*output = buf;
return size;
}

bool write_comm_reply(bool success) {
ssize_t read_comm_prompt_response(char **buf_ptr) {
ssize_t amt = read_string(comm[0][0], password_buffer_create, buf_ptr);
swaylock_log(LOG_DEBUG, "received response to prompt");
if (amt == 0) {
return 0;
} else if (amt < 0) {
swaylock_log(LOG_ERROR, "Error reading prompt response");
return -1;
}
return amt;
}

ssize_t write_comm_text_message_from_backend(const char *msg) {
enum backend_message_type msg_type = BACKEND_MESSAGE_TYPE_TEXT;
if (write(comm[1][1], &msg_type, sizeof(msg_type)) != sizeof(msg_type)) {
swaylock_log_errno(LOG_ERROR, "failed to write message type");
return -1;
}
return write_string(comm[1][1], msg, strlen(msg) + 1);
}

ssize_t write_comm_auth_result_from_backend(bool success) {
enum backend_message_type msg_type = BACKEND_MESSAGE_TYPE_AUTH_RESULT;
if (write(comm[1][1], &msg_type, sizeof(msg_type)) != sizeof(msg_type)) {
swaylock_log_errno(LOG_ERROR, "failed to write message type");
return -1;
}

if (write(comm[1][1], &success, sizeof(success)) != sizeof(success)) {
swaylock_log_errno(LOG_ERROR, "failed to write pw check result");
return false;
swaylock_log_errno(LOG_ERROR, "failed to write authentication result");
return -1;
}
return true;
return sizeof(success);
}

bool spawn_comm_child(void) {
Expand All @@ -69,41 +115,66 @@ bool spawn_comm_child(void) {
return true;
}

bool write_comm_request(struct swaylock_password *pw) {
bool write_comm_prompt_response(struct swaylock_password *pw) {
bool result = false;
ssize_t amt = write_string(comm[0][1], pw->buffer, pw->len + 1);

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 out;
if (amt < 0) {
swaylock_log_errno(LOG_ERROR, "Failed to write prompt response");
} else {
result = true;
}

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 out;
}
offs += amt;
} while (offs < len);

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;
char *malloc_str(size_t size) {
char *res = (char *) malloc(size * sizeof(char));
if (!res) {
swaylock_log_errno(LOG_ERROR, "failed to allocate string");
return NULL;
}
return result;
return res;
}

ssize_t read_comm_message_from_backend(enum backend_message_type *msg_type, void **data) {
enum backend_message_type read_type;
void *read_data;

if (read(comm[1][0], &read_type, sizeof(read_type)) != sizeof(read_type)) {
swaylock_log_errno(LOG_ERROR, "Failed to read message type from backend");
return -1;
}

ssize_t amt;
switch(read_type) {
case BACKEND_MESSAGE_TYPE_TEXT:
amt = read_string(comm[1][0], malloc_str, (char **) &read_data);
if (amt < 0) {
swaylock_log(LOG_ERROR, "Error reading string from backend");
return -1;
} else if (amt == 0) {
read_data = NULL; //TODO: good?
}
break;

case BACKEND_MESSAGE_TYPE_AUTH_RESULT:
read_data = malloc(sizeof(bool));
amt = read(comm[1][0], (bool *) read_data, sizeof(bool));
if (amt != sizeof(bool)) {
swaylock_log(LOG_ERROR, "Error reading boolean from backend");
return -1;
}
break;

}

*msg_type = read_type;
*data = read_data;
return amt;
}

int get_comm_reply_fd(void) {
int get_comm_backend_message_fd(void) {
return comm[1][0];
}
1 change: 1 addition & 0 deletions include/cairo.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
#endif

uint32_t color_with_alpha(uint32_t color, uint8_t alpha);
void cairo_set_source_u32(cairo_t *cairo, uint32_t color);
cairo_subpixel_order_t to_cairo_subpixel_order(enum wl_output_subpixel subpixel);

Expand Down
53 changes: 45 additions & 8 deletions include/comm.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,51 @@

struct swaylock_password;

enum backend_message_type {
//TODO: error messages separately?
BACKEND_MESSAGE_TYPE_TEXT, // Text info, error message or prompt
BACKEND_MESSAGE_TYPE_AUTH_RESULT, // Boolean indicating authorization success or failure
};

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);

// Write a string to a file descriptor by first sending the size and then the
// string data. len should be the length of the string, *including* null
// termination. Returns the number of bytes in the written string, *not* the
// total no. of bytes written - the total number is the return value plus
// sizeof(size_t).
ssize_t write_string(int fd, const char *string, size_t len);

// Read a string from a file descriptor by first reading the size, allocating
// memory to output using alloc(size) and then reading the string data to it.
// Returns the number of bytes in the string, *not* the total no. of bytes read
// - the total number is the return value plus sizeof(size_t).
ssize_t read_string(int fd, char *(*alloc)(size_t), char **output);

// Read a message from the password checking backend (e.g. a prompt or the
// result of authentication) in the main thread. Read first the message type,
// then the associated data itself (size + string data for strings, just the
// boolean value for booleans).
// Returns the no. of bytes in the *data* that was read, the total no. of bytes
// read is the return value plus sizeof(enum backend_message_type).
ssize_t read_comm_message_from_backend(enum backend_message_type *msg_type, void **data);
// Write a string containing a message from the backend
// Returns the no. of bytes in the *message* that was written, the total no. of
// bytes written is the return value plus sizeof(enum backend_message_type).
ssize_t write_comm_text_message_from_backend(const char *msg);
// Write a boolean value indicating the result of authentication
// Returns the no. of bytes in the *data* that was written (i.e. sizeof(bool)),
// the total no. of bytes written is the return value plus
// sizeof(enum backend_message_type).
ssize_t write_comm_auth_result_from_backend(bool success);

// Read / write the response typed by the user (password, PIN code, etc) to a
// prompt sent by the backend. The password buffer is always cleared when the
// function returns. //TODO: verify
ssize_t read_comm_prompt_response(char **buf_ptr);
bool write_comm_prompt_response(struct swaylock_password *pw);

// FD to poll for messages from the backend
int get_comm_backend_message_fd(void);

#endif
2 changes: 1 addition & 1 deletion include/log.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ void _swaylock_log(enum log_importance verbosity, const char *format, ...)
const char *_swaylock_strip_path(const char *filepath);

#define swaylock_log(verb, fmt, ...) \
_swaylock_log(verb, "[%s:%d] " fmt, _swaylock_strip_path(__FILE__), \
_swaylock_log(verb, "[%d:%s:%d] " fmt, getpid(), _swaylock_strip_path(__FILE__), \
__LINE__, ##__VA_ARGS__)

#define swaylock_log_errno(verb, fmt, ...) \
Expand Down
11 changes: 11 additions & 0 deletions include/swaylock.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ struct swaylock_password {
char *buffer;
};

struct swaylock_backend_message_list {
size_t num_messages;
size_t max_num_messages;
char **messages;
};

struct swaylock_state {
struct loop *eventloop;
struct loop_timer *input_idle_timer; // timer to reset input state to IDLE
Expand All @@ -90,6 +96,7 @@ struct swaylock_state {
struct wl_list images;
struct swaylock_args args;
struct swaylock_password password;
struct swaylock_backend_message_list backend_message_list; // backend messages displayed in the UI
struct swaylock_xkb xkb;
cairo_surface_t *test_surface;
cairo_t *test_cairo; // used to estimate font/text sizes
Expand Down Expand Up @@ -144,4 +151,8 @@ void initialize_pw_backend(int argc, char **argv);
void run_pw_backend_child(void);
void clear_buffer(char *buf, size_t size);

// Add a message to the list of displayed backend messages. Creates a copy of
// the string, it can be freed after calling this function.
void add_backend_message(struct swaylock_state *state, char *msg);

#endif
Loading