]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-user-dbus.c
bus: introduce "trusted" bus concept and encode access control in object vtables
[thirdparty/systemd.git] / src / login / logind-user-dbus.c
CommitLineData
3f49d45a
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
3f49d45a
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
3f49d45a 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
3f49d45a
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
a185c5aa 23#include <string.h>
adacb957 24#include <sys/capability.h>
3f49d45a 25
cc377381
LP
26#include "strv.h"
27#include "bus-util.h"
3f49d45a
LP
28#include "logind.h"
29#include "logind-user.h"
3f49d45a 30
cc377381
LP
31static int property_get_display(
32 sd_bus *bus,
33 const char *path,
34 const char *interface,
35 const char *property,
36 sd_bus_message *reply,
ebcf1f97
LP
37 void *userdata,
38 sd_bus_error *error) {
3f49d45a 39
cc377381
LP
40 _cleanup_free_ char *p = NULL;
41 User *u = userdata;
3f49d45a 42
cc377381
LP
43 assert(bus);
44 assert(reply);
45 assert(u);
3f49d45a 46
cc377381
LP
47 p = u->display ? session_bus_path(u->display) : strdup("/");
48 if (!p)
3f49d45a
LP
49 return -ENOMEM;
50
cc377381 51 return sd_bus_message_append(reply, "(so)", u->display ? u->display->id : "", p);
3f49d45a
LP
52}
53
cc377381
LP
54static int property_get_state(
55 sd_bus *bus,
56 const char *path,
57 const char *interface,
58 const char *property,
59 sd_bus_message *reply,
ebcf1f97
LP
60 void *userdata,
61 sd_bus_error *error) {
3f49d45a 62
cc377381 63 User *u = userdata;
3f49d45a 64
cc377381
LP
65 assert(bus);
66 assert(reply);
67 assert(u);
3f49d45a 68
cc377381 69 return sd_bus_message_append(reply, "s", user_state_to_string(user_get_state(u)));
3f49d45a
LP
70}
71
cc377381
LP
72static int property_get_sessions(
73 sd_bus *bus,
74 const char *path,
75 const char *interface,
76 const char *property,
77 sd_bus_message *reply,
ebcf1f97
LP
78 void *userdata,
79 sd_bus_error *error) {
cc377381
LP
80
81 User *u = userdata;
3f49d45a 82 Session *session;
cc377381 83 int r;
3f49d45a 84
cc377381
LP
85 assert(bus);
86 assert(reply);
3f49d45a
LP
87 assert(u);
88
cc377381
LP
89 r = sd_bus_message_open_container(reply, 'a', "(so)");
90 if (r < 0)
91 return r;
3f49d45a
LP
92
93 LIST_FOREACH(sessions_by_user, session, u->sessions) {
cc377381 94 _cleanup_free_ char *p = NULL;
3f49d45a
LP
95
96 p = session_bus_path(session);
97 if (!p)
98 return -ENOMEM;
99
cc377381
LP
100 r = sd_bus_message_append(reply, "(so)", session->id, p);
101 if (r < 0)
102 return r;
3f49d45a 103
3f49d45a
LP
104 }
105
cc377381
LP
106 r = sd_bus_message_close_container(reply);
107 if (r < 0)
108 return r;
3f49d45a 109
cc377381 110 return 1;
3f49d45a
LP
111}
112
cc377381
LP
113static int property_get_idle_hint(
114 sd_bus *bus,
115 const char *path,
116 const char *interface,
117 const char *property,
118 sd_bus_message *reply,
ebcf1f97
LP
119 void *userdata,
120 sd_bus_error *error) {
a185c5aa 121
cc377381 122 User *u = userdata;
77527da0 123
cc377381
LP
124 assert(bus);
125 assert(reply);
126 assert(u);
a185c5aa 127
cc377381 128 return sd_bus_message_append(reply, "b", user_get_idle_hint(u, NULL) > 0);
a185c5aa
LP
129}
130
cc377381
LP
131static int property_get_idle_since_hint(
132 sd_bus *bus,
133 const char *path,
134 const char *interface,
135 const char *property,
136 sd_bus_message *reply,
ebcf1f97
LP
137 void *userdata,
138 sd_bus_error *error) {
cc377381
LP
139
140 User *u = userdata;
a185c5aa
LP
141 dual_timestamp t;
142 uint64_t k;
143
cc377381
LP
144 assert(bus);
145 assert(reply);
a185c5aa
LP
146 assert(u);
147
148 user_get_idle_hint(u, &t);
149 k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
150
cc377381 151 return sd_bus_message_append(reply, "t", k);
a185c5aa
LP
152}
153
3a9f7a30
LP
154static int property_get_linger(
155 sd_bus *bus,
156 const char *path,
157 const char *interface,
158 const char *property,
159 sd_bus_message *reply,
ebcf1f97
LP
160 void *userdata,
161 sd_bus_error *error) {
3a9f7a30
LP
162
163 User *u = userdata;
164 int r;
165
166 assert(bus);
167 assert(reply);
168 assert(u);
169
170 r = user_check_linger_file(u);
171
172 return sd_bus_message_append(reply, "b", r > 0);
173}
174
ebcf1f97 175static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 176 User *u = userdata;
3f49d45a
LP
177 int r;
178
cc377381
LP
179 assert(bus);
180 assert(message);
181 assert(u);
3f49d45a 182
cc377381 183 r = user_stop(u);
3f49d45a 184 if (r < 0)
ebcf1f97 185 return r;
3f49d45a 186
df2d202e 187 return sd_bus_reply_method_return(message, NULL);
3f49d45a
LP
188}
189
ebcf1f97 190static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
191 User *u = userdata;
192 int32_t signo;
a185c5aa
LP
193 int r;
194
cc377381 195 assert(bus);
3f49d45a 196 assert(message);
cc377381 197 assert(u);
3f49d45a 198
cc377381
LP
199 r = sd_bus_message_read(message, "i", &signo);
200 if (r < 0)
ebcf1f97 201 return r;
a185c5aa 202
cc377381 203 if (signo <= 0 || signo >= _NSIG)
ebcf1f97 204 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
a185c5aa 205
cc377381
LP
206 r = user_kill(u, signo);
207 if (r < 0)
ebcf1f97 208 return r;
a185c5aa 209
df2d202e 210 return sd_bus_reply_method_return(message, NULL);
3f49d45a
LP
211}
212
cc377381
LP
213const sd_bus_vtable user_vtable[] = {
214 SD_BUS_VTABLE_START(0),
215
216 SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(User, uid), 0),
217 SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(User, gid), 0),
218 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(User, name), 0),
219 SD_BUS_PROPERTY("Timestamp", "t", NULL, offsetof(User, timestamp.realtime), 0),
220 SD_BUS_PROPERTY("TimestampMonotonic", "t", NULL, offsetof(User, timestamp.monotonic), 0),
221 SD_BUS_PROPERTY("RuntimePath", "s", NULL, offsetof(User, runtime_path), 0),
222 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(User, service), 0),
223 SD_BUS_PROPERTY("Slice", "s", NULL, offsetof(User, slice), 0),
224 SD_BUS_PROPERTY("Display", "(so)", property_get_display, 0, 0),
225 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
226 SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
227 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
228 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
229 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
3a9f7a30 230 SD_BUS_PROPERTY("Linger", "b", property_get_linger, 0, 0),
cc377381 231
adacb957
LP
232 SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
233 SD_BUS_METHOD("Kill", "i", NULL, method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
cc377381
LP
234
235 SD_BUS_VTABLE_END
236};
3f49d45a 237
f00c3121 238int user_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
3f49d45a 239 Manager *m = userdata;
cc377381 240 User *user;
3f49d45a
LP
241 int r;
242
cc377381
LP
243 assert(bus);
244 assert(path);
245 assert(interface);
246 assert(found);
247 assert(m);
3f49d45a 248
927b1649 249 if (streq(path, "/org/freedesktop/login1/user/self")) {
5b12334d 250 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
927b1649
LP
251 sd_bus_message *message;
252 pid_t pid;
3f49d45a 253
927b1649
LP
254 message = sd_bus_get_current(bus);
255 if (!message)
256 return 0;
257
5b12334d 258 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
927b1649 259 if (r < 0)
5b12334d
LP
260 return r;
261
262 r = sd_bus_creds_get_pid(creds, &pid);
263 if (r < 0)
264 return r;
927b1649
LP
265
266 r = manager_get_user_by_pid(m, pid, &user);
267 if (r <= 0)
268 return 0;
269 } else {
270 unsigned long lu;
271 const char *p;
3f49d45a 272
927b1649
LP
273 p = startswith(path, "/org/freedesktop/login1/user/_");
274 if (!p)
275 return 0;
276
277 r = safe_atolu(p, &lu);
278 if (r < 0)
279 return 0;
280
281 user = hashmap_get(m->users, ULONG_TO_PTR(lu));
282 if (!user)
283 return 0;
284 }
3f49d45a 285
cc377381
LP
286 *found = user;
287 return 1;
3f49d45a
LP
288}
289
3f49d45a
LP
290char *user_bus_path(User *u) {
291 char *s;
292
293 assert(u);
294
9444b1f2 295 if (asprintf(&s, "/org/freedesktop/login1/user/_%llu", (unsigned long long) u->uid) < 0)
3f49d45a
LP
296 return NULL;
297
298 return s;
299}
da119395 300
f00c3121 301int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
cc377381
LP
302 _cleanup_strv_free_ char **l = NULL;
303 Manager *m = userdata;
304 User *user;
305 Iterator i;
306 int r;
da119395 307
cc377381
LP
308 assert(bus);
309 assert(path);
310 assert(nodes);
da119395 311
cc377381
LP
312 HASHMAP_FOREACH(user, m->users, i) {
313 char *p;
da119395 314
cc377381
LP
315 p = user_bus_path(user);
316 if (!p)
317 return -ENOMEM;
da119395 318
cc377381
LP
319 r = strv_push(&l, p);
320 if (r < 0) {
321 free(p);
322 return r;
323 }
324 }
da119395 325
cc377381
LP
326 *nodes = l;
327 l = NULL;
da119395 328
cc377381
LP
329 return 1;
330}
331
332int user_send_signal(User *u, bool new_user) {
333 _cleanup_free_ char *p = NULL;
da119395 334
cc377381
LP
335 assert(u);
336
337 p = user_bus_path(u);
338 if (!p)
4654e558 339 return -ENOMEM;
da119395 340
cc377381
LP
341 return sd_bus_emit_signal(
342 u->manager->bus,
343 "/org/freedesktop/login1",
344 "org.freedesktop.login1.Manager",
345 new_user ? "UserNew" : "UserRemoved",
346 "uo", (uint32_t) u->uid, p);
da119395 347}
9418f147 348
cc377381 349int user_send_changed(User *u, const char *properties, ...) {
ce0fc5f5 350 _cleanup_free_ char *p = NULL;
cc377381 351 char **l;
9418f147
LP
352
353 assert(u);
354
ed18b08b
LP
355 if (!u->started)
356 return 0;
357
9418f147
LP
358 p = user_bus_path(u);
359 if (!p)
360 return -ENOMEM;
361
cc377381 362 l = strv_from_stdarg_alloca(properties);
9418f147 363
cc377381 364 return sd_bus_emit_properties_changed_strv(u->manager->bus, p, "org.freedesktop.login1.User", l);
9418f147 365}