aboutsummaryrefslogtreecommitdiff
path: root/src/npassd/session.c
blob: 7190aec61921e8b03b44e2e182157a6dc299c77d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <errno.h>
#include <linux/limits.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.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;

	session_free(session);
	return 0;
}

static int handle_close(__attribute__((unused)) sd_bus_message *msg, void *data,
			__attribute__((unused)) sd_bus_error *ret_error)
{
	int ret;

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