]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session-dbus.c
logind: Make more use of cleanup macros
[thirdparty/systemd.git] / src / login / logind-session-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>
3f49d45a
LP
24
25#include "logind.h"
26#include "logind-session.h"
27#include "dbus-common.h"
28#include "util.h"
29
30#define BUS_SESSION_INTERFACE \
31 " <interface name=\"org.freedesktop.login1.Session\">\n" \
32 " <method name=\"Terminate\"/>\n" \
33 " <method name=\"Activate\"/>\n" \
f401e48c
LP
34 " <method name=\"Lock\"/>\n" \
35 " <method name=\"Unlock\"/>\n" \
36 " <method name=\"SetIdleHint\">\n" \
37 " <arg name=\"b\" type=\"b\"/>\n" \
38 " </method>\n" \
de07ab16
LP
39 " <method name=\"Kill\">\n" \
40 " <arg name=\"who\" type=\"s\"/>\n" \
41 " <arg name=\"signal\" type=\"s\"/>\n" \
42 " </method>\n" \
083f4da2
LP
43 " <signal name=\"Lock\"/>\n" \
44 " <signal name=\"Unlock\"/>\n" \
e3e9cc80 45 " <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \
3f49d45a
LP
46 " <property name=\"User\" type=\"(uo)\" access=\"read\"/>\n" \
47 " <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
f401e48c
LP
48 " <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
49 " <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
b69d29ce 50 " <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
3f49d45a
LP
51 " <property name=\"VTNr\" type=\"u\" access=\"read\"/>\n" \
52 " <property name=\"Seat\" type=\"(so)\" access=\"read\"/>\n" \
53 " <property name=\"TTY\" type=\"s\" access=\"read\"/>\n" \
54 " <property name=\"Display\" type=\"s\" access=\"read\"/>\n" \
55 " <property name=\"Remote\" type=\"b\" access=\"read\"/>\n" \
56 " <property name=\"RemoteHost\" type=\"s\" access=\"read\"/>\n" \
57 " <property name=\"RemoteUser\" type=\"s\" access=\"read\"/>\n" \
0604381b 58 " <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
3f49d45a
LP
59 " <property name=\"Leader\" type=\"u\" access=\"read\"/>\n" \
60 " <property name=\"Audit\" type=\"u\" access=\"read\"/>\n" \
61 " <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \
0604381b 62 " <property name=\"Class\" type=\"s\" access=\"read\"/>\n" \
3f49d45a 63 " <property name=\"Active\" type=\"b\" access=\"read\"/>\n" \
0604381b 64 " <property name=\"State\" type=\"s\" access=\"read\"/>\n" \
3f49d45a
LP
65 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
66 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
67 " <property name=\"KillProcesses\" type=\"b\" access=\"read\"/>\n" \
f401e48c
LP
68 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
69 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
70 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
3f49d45a
LP
71 " </interface>\n"
72
73#define INTROSPECTION \
74 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
75 "<node>\n" \
76 BUS_SESSION_INTERFACE \
77 BUS_PROPERTIES_INTERFACE \
78 BUS_PEER_INTERFACE \
79 BUS_INTROSPECTABLE_INTERFACE \
80 "</node>\n"
81
82#define INTERFACES_LIST \
83 BUS_GENERIC_INTERFACES_LIST \
84 "org.freedesktop.login1.Session\0"
85
86static int bus_session_append_seat(DBusMessageIter *i, const char *property, void *data) {
87 DBusMessageIter sub;
88 Session *s = data;
89 const char *id, *path;
90 char *p = NULL;
91
92 assert(i);
93 assert(property);
94 assert(s);
95
96 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
97 return -ENOMEM;
98
99 if (s->seat) {
100 id = s->seat->id;
101 path = p = seat_bus_path(s->seat);
102
103 if (!p)
104 return -ENOMEM;
105 } else {
106 id = "";
107 path = "/";
108 }
109
110 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
111 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
112 free(p);
113 return -ENOMEM;
114 }
115
116 free(p);
117
118 if (!dbus_message_iter_close_container(i, &sub))
119 return -ENOMEM;
120
121 return 0;
122}
123
124static int bus_session_append_user(DBusMessageIter *i, const char *property, void *data) {
125 DBusMessageIter sub;
d200735e 126 User *u = data;
3f49d45a
LP
127 char *p = NULL;
128
129 assert(i);
130 assert(property);
d200735e 131 assert(u);
3f49d45a
LP
132
133 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
134 return -ENOMEM;
135
d200735e 136 p = user_bus_path(u);
3f49d45a
LP
137 if (!p)
138 return -ENOMEM;
139
d200735e 140 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->uid) ||
3f49d45a
LP
141 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
142 free(p);
143 return -ENOMEM;
144 }
145
146 free(p);
147
148 if (!dbus_message_iter_close_container(i, &sub))
149 return -ENOMEM;
150
151 return 0;
152}
153
154static int bus_session_append_active(DBusMessageIter *i, const char *property, void *data) {
155 Session *s = data;
77527da0 156 dbus_bool_t b;
3f49d45a
LP
157
158 assert(i);
159 assert(property);
160 assert(s);
161
162 b = session_is_active(s);
163 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
164 return -ENOMEM;
165
166 return 0;
167}
168
a185c5aa
LP
169static int bus_session_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
170 Session *s = data;
77527da0 171 int b;
a185c5aa
LP
172
173 assert(i);
174 assert(property);
175 assert(s);
176
77527da0 177 b = session_get_idle_hint(s, NULL) > 0;
a185c5aa
LP
178 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
179 return -ENOMEM;
180
181 return 0;
182}
183
184static int bus_session_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
185 Session *s = data;
186 dual_timestamp t;
187 uint64_t u;
ca4f2b6d 188 int r;
a185c5aa
LP
189
190 assert(i);
191 assert(property);
192 assert(s);
193
ca4f2b6d
VP
194 r = session_get_idle_hint(s, &t);
195 if (r < 0)
196 return r;
197
a185c5aa
LP
198 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
199
200 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
201 return -ENOMEM;
202
203 return 0;
204}
205
b69d29ce
LP
206static int bus_session_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
207 Session *s = data;
208 char *t;
209 int r;
210 bool success;
211
212 assert(i);
213 assert(property);
214 assert(s);
215
216 r = cg_join_spec(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &t);
217 if (r < 0)
218 return r;
219
220 success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
221 free(t);
222
223 return success ? 0 : -ENOMEM;
224}
225
3f49d45a 226static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
55efac6c 227static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_class, session_class, SessionClass);
3f49d45a 228
0604381b
LP
229static int bus_session_append_state(DBusMessageIter *i, const char *property, void *data) {
230 Session *s = data;
231 const char *state;
232
233 assert(i);
234 assert(property);
235 assert(s);
236
237 state = session_state_to_string(session_get_state(s));
238
239 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
240 return -ENOMEM;
241
242 return 0;
243}
244
3f49d45a
LP
245static int get_session_for_path(Manager *m, const char *path, Session **_s) {
246 Session *s;
247 char *id;
248
249 assert(m);
250 assert(path);
251 assert(_s);
252
253 if (!startswith(path, "/org/freedesktop/login1/session/"))
254 return -EINVAL;
255
256 id = bus_path_unescape(path + 32);
257 if (!id)
258 return -ENOMEM;
259
260 s = hashmap_get(m->sessions, id);
261 free(id);
262
263 if (!s)
264 return -ENOENT;
265
266 *_s = s;
267 return 0;
268}
269
d200735e
MS
270static const BusProperty bus_login_session_properties[] = {
271 { "Id", bus_property_append_string, "s", offsetof(Session, id), true },
272 { "Timestamp", bus_property_append_usec, "t", offsetof(Session, timestamp.realtime) },
273 { "TimestampMonotonic", bus_property_append_usec, "t", offsetof(Session, timestamp.monotonic) },
b69d29ce 274 { "DefaultControlGroup", bus_session_append_default_cgroup, "s", 0, },
d200735e
MS
275 { "VTNr", bus_property_append_uint32, "u", offsetof(Session, vtnr) },
276 { "Seat", bus_session_append_seat, "(so)", 0 },
277 { "TTY", bus_property_append_string, "s", offsetof(Session, tty), true },
278 { "Display", bus_property_append_string, "s", offsetof(Session, display), true },
279 { "Remote", bus_property_append_bool, "b", offsetof(Session, remote) },
280 { "RemoteUser", bus_property_append_string, "s", offsetof(Session, remote_user), true },
281 { "RemoteHost", bus_property_append_string, "s", offsetof(Session, remote_host), true },
282 { "Service", bus_property_append_string, "s", offsetof(Session, service), true },
283 { "Leader", bus_property_append_pid, "u", offsetof(Session, leader) },
284 { "Audit", bus_property_append_uint32, "u", offsetof(Session, audit_id) },
285 { "Type", bus_session_append_type, "s", offsetof(Session, type) },
55efac6c 286 { "Class", bus_session_append_class, "s", offsetof(Session, class) },
d200735e 287 { "Active", bus_session_append_active, "b", 0 },
0604381b 288 { "State", bus_session_append_state, "s", 0 },
d200735e
MS
289 { "Controllers", bus_property_append_strv, "as", offsetof(Session, controllers), true },
290 { "ResetControllers", bus_property_append_strv, "as", offsetof(Session, reset_controllers), true },
291 { "KillProcesses", bus_property_append_bool, "b", offsetof(Session, kill_processes) },
292 { "IdleHint", bus_session_append_idle_hint, "b", 0 },
293 { "IdleSinceHint", bus_session_append_idle_hint_since, "t", 0 },
294 { "IdleSinceHintMonotonic", bus_session_append_idle_hint_since, "t", 0 },
295 { NULL, }
296};
297
298static const BusProperty bus_login_session_user_properties[] = {
299 { "User", bus_session_append_user, "(uo)", 0 },
300 { "Name", bus_property_append_string, "s", offsetof(User, name), true },
1d4ec315 301 { NULL, }
d200735e
MS
302};
303
3f49d45a
LP
304static DBusHandlerResult session_message_dispatch(
305 Session *s,
306 DBusConnection *connection,
307 DBusMessage *message) {
308
bef422ae 309 DBusError error;
ce0fc5f5 310 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
bef422ae
LP
311 int r;
312
3f49d45a
LP
313 assert(s);
314 assert(connection);
315 assert(message);
316
bef422ae
LP
317 dbus_error_init(&error);
318
319 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Terminate")) {
320
321 r = session_stop(s);
322 if (r < 0)
323 return bus_send_error_reply(connection, message, NULL, r);
324
325 reply = dbus_message_new_method_return(message);
326 if (!reply)
327 goto oom;
328
329 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Activate")) {
330
331 r = session_activate(s);
332 if (r < 0)
333 return bus_send_error_reply(connection, message, NULL, r);
334
335 reply = dbus_message_new_method_return(message);
336 if (!reply)
337 goto oom;
338
339 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Lock") ||
340 dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Unlock")) {
bef422ae 341
bda06175 342 if (session_send_lock(s, streq(dbus_message_get_member(message), "Lock")) < 0)
bef422ae
LP
343 goto oom;
344
345 reply = dbus_message_new_method_return(message);
346 if (!reply)
347 goto oom;
348
349 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "SetIdleHint")) {
350 dbus_bool_t b;
5bc849fd 351 unsigned long ul;
bef422ae
LP
352
353 if (!dbus_message_get_args(
354 message,
355 &error,
356 DBUS_TYPE_BOOLEAN, &b,
357 DBUS_TYPE_INVALID))
358 return bus_send_error_reply(connection, message, &error, -EINVAL);
359
5bc849fd
LP
360 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
361 if (ul == (unsigned long) -1)
362 return bus_send_error_reply(connection, message, &error, -EIO);
363
364 if (ul != 0 && ul != s->user->uid)
365 return bus_send_error_reply(connection, message, NULL, -EPERM);
366
bef422ae
LP
367 session_set_idle_hint(s, b);
368
369 reply = dbus_message_new_method_return(message);
370 if (!reply)
371 goto oom;
372
de07ab16
LP
373 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Kill")) {
374 const char *swho;
375 int32_t signo;
376 KillWho who;
377
378 if (!dbus_message_get_args(
379 message,
380 &error,
381 DBUS_TYPE_STRING, &swho,
382 DBUS_TYPE_INT32, &signo,
383 DBUS_TYPE_INVALID))
384 return bus_send_error_reply(connection, message, &error, -EINVAL);
385
386 if (isempty(swho))
387 who = KILL_ALL;
388 else {
389 who = kill_who_from_string(swho);
390 if (who < 0)
391 return bus_send_error_reply(connection, message, &error, -EINVAL);
392 }
393
394 if (signo <= 0 || signo >= _NSIG)
395 return bus_send_error_reply(connection, message, &error, -EINVAL);
396
397 r = session_kill(s, who, signo);
398 if (r < 0)
399 return bus_send_error_reply(connection, message, NULL, r);
400
401 reply = dbus_message_new_method_return(message);
402 if (!reply)
403 goto oom;
404
d200735e
MS
405 } else {
406 const BusBoundProperties bps[] = {
407 { "org.freedesktop.login1.Session", bus_login_session_properties, s },
408 { "org.freedesktop.login1.Session", bus_login_session_user_properties, s->user },
409 { NULL, }
410 };
411 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
412 }
bef422ae
LP
413
414 if (reply) {
c6a818c8 415 if (!bus_maybe_send_reply(connection, message, reply))
bef422ae 416 goto oom;
bef422ae
LP
417 }
418
419 return DBUS_HANDLER_RESULT_HANDLED;
420
421oom:
bef422ae
LP
422 dbus_error_free(&error);
423
424 return DBUS_HANDLER_RESULT_NEED_MEMORY;
3f49d45a
LP
425}
426
427static DBusHandlerResult session_message_handler(
428 DBusConnection *connection,
429 DBusMessage *message,
430 void *userdata) {
431
432 Manager *m = userdata;
433 Session *s;
434 int r;
435
436 r = get_session_for_path(m, dbus_message_get_path(message), &s);
437 if (r < 0) {
438
439 if (r == -ENOMEM)
440 return DBUS_HANDLER_RESULT_NEED_MEMORY;
441
442 if (r == -ENOENT) {
443 DBusError e;
444
445 dbus_error_init(&e);
446 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown session");
447 return bus_send_error_reply(connection, message, &e, r);
448 }
449
450 return bus_send_error_reply(connection, message, NULL, r);
451 }
452
453 return session_message_dispatch(s, connection, message);
454}
455
456const DBusObjectPathVTable bus_session_vtable = {
457 .message_function = session_message_handler
458};
459
460char *session_bus_path(Session *s) {
461 char *t, *r;
462
463 assert(s);
464
465 t = bus_path_escape(s->id);
466 if (!t)
467 return NULL;
468
469 r = strappend("/org/freedesktop/login1/session/", t);
470 free(t);
471
472 return r;
473}
da119395
LP
474
475int session_send_signal(Session *s, bool new_session) {
ce0fc5f5 476 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
da119395 477 int r = -ENOMEM;
ce0fc5f5 478 _cleanup_free_ char *p = NULL;
da119395
LP
479
480 assert(s);
481
482 m = dbus_message_new_signal("/org/freedesktop/login1",
483 "org.freedesktop.login1.Manager",
484 new_session ? "SessionNew" : "SessionRemoved");
485
486 if (!m)
487 return -ENOMEM;
488
489 p = session_bus_path(s);
490 if (!p)
491 goto finish;
492
493 if (!dbus_message_append_args(
494 m,
495 DBUS_TYPE_STRING, &s->id,
496 DBUS_TYPE_OBJECT_PATH, &p,
497 DBUS_TYPE_INVALID))
498 goto finish;
499
500 if (!dbus_connection_send(s->manager->bus, m, NULL))
501 goto finish;
502
503 r = 0;
504
505finish:
da119395
LP
506 return r;
507}
9418f147
LP
508
509int session_send_changed(Session *s, const char *properties) {
ce0fc5f5 510 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
9418f147 511 int r = -ENOMEM;
ce0fc5f5 512 _cleanup_free_ char *p = NULL;
9418f147
LP
513
514 assert(s);
515
ed18b08b
LP
516 if (!s->started)
517 return 0;
518
9418f147
LP
519 p = session_bus_path(s);
520 if (!p)
521 return -ENOMEM;
522
523 m = bus_properties_changed_new(p, "org.freedesktop.login1.Session", properties);
524 if (!m)
525 goto finish;
526
527 if (!dbus_connection_send(s->manager->bus, m, NULL))
528 goto finish;
529
530 r = 0;
531
532finish:
9418f147
LP
533 return r;
534}
88e3dc90
LP
535
536int session_send_lock(Session *s, bool lock) {
ce0fc5f5 537 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
88e3dc90 538 bool b;
ce0fc5f5 539 _cleanup_free_ char *p = NULL;
88e3dc90
LP
540
541 assert(s);
542
543 p = session_bus_path(s);
544 if (!p)
545 return -ENOMEM;
546
547 m = dbus_message_new_signal(p, "org.freedesktop.login1.Session", lock ? "Lock" : "Unlock");
88e3dc90
LP
548
549 if (!m)
550 return -ENOMEM;
551
552 b = dbus_connection_send(s->manager->bus, m, NULL);
88e3dc90
LP
553 if (!b)
554 return -ENOMEM;
555
556 return 0;
557}
7ba64386
LP
558
559int session_send_lock_all(Manager *m, bool lock) {
560 Session *session;
561 Iterator i;
562 int r = 0;
563
564 assert(m);
565
566 HASHMAP_FOREACH(session, m->sessions, i) {
567 int k;
568
569 k = session_send_lock(session, lock);
570 if (k < 0)
571 r = k;
572 }
573
574 return r;
575}