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