#include #include #include #include #include #include #include "npassd/common.h" #include "npassd/session.h" #include "util.h" static int handle_close(__attribute__((unused)) sd_bus_message *msg, void *data, __attribute__((unused)) sd_bus_error *ret_error); static int handle_nameownerchanged(sd_bus_message *msg, void *data, __attribute__((unused)) sd_bus_error *ret_error); static const sd_bus_vtable session_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_METHOD("Close", "", "", handle_close, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, }; static int handle_nameownerchanged(sd_bus_message *msg, void *data, __attribute__((unused)) sd_bus_error *ret_error) { struct session *session = data; const char *name; int ret; ret = sd_bus_message_read(msg, "ss", NULL, &name); if (ret < 0) { print_err("%s", strerror(-ret)); return ret; } ret = strcmp(session->owner, name); if (ret) return 0; session_free(session); return 0; } static int handle_close(sd_bus_message *msg, void *data, __attribute__((unused)) sd_bus_error *ret_error) { struct session *session = data; const char *sender; int ret; sender = sd_bus_message_get_sender(msg); ret = strcmp(sender, session->owner); if (ret) { print_err("Unauthorized session close by %s", sender); return -EPERM; } ret = session_free((struct session *)data); if (ret < 0) print_err("Failed to free session: %s", strerror(-ret)); return sd_bus_reply_method_return(msg, ""); } int session_slot_available(struct session *s, size_t n) { static pthread_mutex_t lock; pthread_mutex_lock(&lock); for (size_t i = 0; i < n; i++) { if (s[i].isactive == false) { pthread_mutex_unlock(&lock); return i; } } pthread_mutex_unlock(&lock); return -ENOMEM; } int session_new(sd_bus *bus, struct session *session, unsigned session_no, const char *owner) { int ret; ret = snprintf(session->path, sizeof(session->path), DBUS_OBJECT_PATH "/session/%d", session_no); if (ret < 0 || (size_t)ret > sizeof(session->path)) { print_err("%s", "Failed to create session path"); return -ENOMEM; } ret = snprintf(session->owner, sizeof(session->owner), "%s", owner); if (ret < 0 || (size_t)ret > sizeof(session->owner)) { print_err("%s", "Failed to set session owner"); return -ENOMEM; } ret = sd_bus_add_object_vtable(bus, &session->slot, session->path, SESSION_IFACE, session_vtable, session); if (ret < 0) { print_err("Failed to create session: %s", strerror(-ret)); return ret; } session->isactive = true; ret = sd_bus_match_signal(bus, NULL, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged", handle_nameownerchanged, session); if (ret < 0) { session_free(session); print_err("%s", strerror(-ret)); return ret; } return ret; } int session_free(struct session *s) { if (s->isactive == false) return -EINVAL; s->isactive = false; sd_bus_slot_unref(s->slot); return 0; } void session_init(struct session *s, size_t n) { for (size_t i = 0; i < n; i++) s[i].isactive = false; }