#include <errno.h>
#include <linux/limits.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
#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;
sd_bus_slot_unref(s->slot_singal);
sd_bus_slot_unref(s->slot);
free(s->owner);
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;
}