#include #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; LIST_REMOVE(session, dlist); 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; } LIST_REMOVE(session, dlist); session_free(session); return sd_bus_reply_method_return(msg, ""); } static int session_id_get(uint64_t *id) { static uint64_t count = 0; if (count == UINT64_MAX) { print_err("%s", "Congratulations, we ran out of uint64_t"); return -ERANGE; } *id = count++; return 0; } void session_free(struct session *s) { if (s == NULL) return; if (s->slot_singal != NULL) sd_bus_slot_unref(s->slot_singal); if (s->slot != NULL) sd_bus_slot_unref(s->slot); if (s->owner != NULL) free(s->owner); if (s->path != NULL) free(s->path); free(s); } int session_new(sd_bus *bus, struct session **p, const char *owner) { struct session *session; uint64_t id; int ret; *p = malloc(sizeof(**p)); if (*p == NULL) { print_err("Failed to make session: %s", strerror(errno)); return -errno; } session = *p; session->slot_singal = NULL; session->slot = NULL; session->owner = NULL; session->path = NULL; ret = session_id_get(&id); if (ret < 0) { session_free(session); return ret; } ret = asprintf(&session->path, DBUS_OBJECT_PATH "/session/%lu", id); if (ret < 0) { session_free(session); print_err("%s", "Failed to create session path"); return -ENOMEM; } session->owner = strdup(owner); if (session->owner == NULL) { session_free(session); print_err("%s", strerror(errno)); return -errno; } ret = sd_bus_add_object_vtable(bus, &session->slot, session->path, SESSION_IFACE, session_vtable, session); if (ret < 0) { session_free(session); print_err("Failed to create session: %s", strerror(-ret)); return ret; } ret = sd_bus_match_signal(bus, &session->slot_singal, "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; }