1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
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
11 (at your option) any later version.
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
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "dbus-common.h"
34 #define BUS_MANAGER_INTERFACE \
35 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
36 " <method name=\"GetSession\">\n" \
37 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
38 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
40 " <method name=\"GetSessionByPID\">\n" \
41 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
42 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
44 " <method name=\"GetUser\">\n" \
45 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
46 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
48 " <method name=\"GetSeat\">\n" \
49 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
50 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
52 " <method name=\"ListSessions\">\n" \
53 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
55 " <method name=\"ListUsers\">\n" \
56 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
58 " <method name=\"ListSeats\">\n" \
59 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
61 " <method name=\"CreateSession\">\n" \
62 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
63 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
64 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
65 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
66 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
67 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
68 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
69 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
72 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
74 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
75 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
76 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
77 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
78 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
79 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
80 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
81 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
82 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
84 " <method name=\"ReleaseSession\">\n" \
85 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
87 " <method name=\"ActivateSession\">\n" \
88 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
90 " <method name=\"ActivateSessionOnSeat\">\n" \
91 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
92 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
94 " <method name=\"LockSession\">\n" \
95 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
97 " <method name=\"UnlockSession\">\n" \
98 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
100 " <method name=\"KillSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
102 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
103 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
105 " <method name=\"KillUser\">\n" \
106 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
107 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
109 " <method name=\"TerminateSession\">\n" \
110 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
112 " <method name=\"TerminateUser\">\n" \
113 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
115 " <method name=\"TerminateSeat\">\n" \
116 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
118 " <method name=\"SetUserLinger\">\n" \
119 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
120 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
121 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
123 " <method name=\"AttachDevice\">\n" \
124 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
125 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
126 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
128 " <method name=\"FlushDevices\">\n" \
129 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
131 " <method name=\"PowerOff\">\n" \
132 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
134 " <method name=\"Reboot\">\n" \
135 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
137 " <method name=\"CanPowerOff\">\n" \
138 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
140 " <method name=\"CanReboot\">\n" \
141 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
143 " <method name=\"Inhibit\">\n" \
144 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
145 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
146 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
147 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
149 " <method name=\"ListInhibitors\">\n" \
150 " <arg name=\"inhibitors\" type=\"a(sssuu)\" direction=\"out\"/>\n" \
152 " <signal name=\"SessionNew\">\n" \
153 " <arg name=\"id\" type=\"s\"/>\n" \
154 " <arg name=\"path\" type=\"o\"/>\n" \
156 " <signal name=\"SessionRemoved\">\n" \
157 " <arg name=\"id\" type=\"s\"/>\n" \
158 " <arg name=\"path\" type=\"o\"/>\n" \
160 " <signal name=\"UserNew\">\n" \
161 " <arg name=\"uid\" type=\"u\"/>\n" \
162 " <arg name=\"path\" type=\"o\"/>\n" \
164 " <signal name=\"UserRemoved\">\n" \
165 " <arg name=\"uid\" type=\"u\"/>\n" \
166 " <arg name=\"path\" type=\"o\"/>\n" \
168 " <signal name=\"SeatNew\">\n" \
169 " <arg name=\"id\" type=\"s\"/>\n" \
170 " <arg name=\"path\" type=\"o\"/>\n" \
172 " <signal name=\"SeatRemoved\">\n" \
173 " <arg name=\"id\" type=\"s\"/>\n" \
174 " <arg name=\"path\" type=\"o\"/>\n" \
176 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
177 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
178 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
179 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
180 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
181 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
182 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
183 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
184 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
185 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
186 " <property name=\"Inhibited\" type=\"s\" access=\"read\"/>\n" \
189 #define INTROSPECTION_BEGIN \
190 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
192 BUS_MANAGER_INTERFACE \
193 BUS_PROPERTIES_INTERFACE \
195 BUS_INTROSPECTABLE_INTERFACE
197 #define INTROSPECTION_END \
200 #define INTERFACES_LIST \
201 BUS_GENERIC_INTERFACES_LIST \
202 "org.freedesktop.login1.Manager\0"
204 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
212 b = manager_get_idle_hint(m, NULL) > 0;
213 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
219 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
228 manager_get_idle_hint(m, &t);
229 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
231 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
237 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
242 w = manager_inhibit_what(m);
243 p = inhibit_what_to_string(w);
245 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
251 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
252 Session *session = NULL;
254 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
255 uint32_t uid, leader, audit_id = 0;
256 dbus_bool_t remote, kill_processes;
257 char **controllers = NULL, **reset_controllers = NULL;
261 DBusMessageIter iter;
266 DBusMessage *reply = NULL;
273 if (!dbus_message_iter_init(message, &iter) ||
274 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
277 dbus_message_iter_get_basic(&iter, &uid);
279 if (!dbus_message_iter_next(&iter) ||
280 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
283 dbus_message_iter_get_basic(&iter, &leader);
286 !dbus_message_iter_next(&iter) ||
287 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
290 dbus_message_iter_get_basic(&iter, &service);
292 if (!dbus_message_iter_next(&iter) ||
293 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
296 dbus_message_iter_get_basic(&iter, &type);
297 t = session_type_from_string(type);
300 !dbus_message_iter_next(&iter) ||
301 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
304 dbus_message_iter_get_basic(&iter, &class);
308 c = session_class_from_string(class);
311 !dbus_message_iter_next(&iter) ||
312 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
315 dbus_message_iter_get_basic(&iter, &seat);
320 s = hashmap_get(m->seats, seat);
325 if (!dbus_message_iter_next(&iter) ||
326 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
329 dbus_message_iter_get_basic(&iter, &vtnr);
331 if (!dbus_message_iter_next(&iter) ||
332 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
335 dbus_message_iter_get_basic(&iter, &tty);
337 if (tty_is_vc(tty)) {
342 else if (s != m->vtconsole)
345 v = vtnr_from_tty(tty);
348 return v < 0 ? v : -EINVAL;
352 else if (vtnr != (uint32_t) v)
354 } else if (tty_is_console(tty)) {
358 else if (s != m->vtconsole)
364 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
368 if (seat_can_multi_session(s)) {
377 if (!dbus_message_iter_next(&iter) ||
378 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
381 dbus_message_iter_get_basic(&iter, &display);
383 if (!dbus_message_iter_next(&iter) ||
384 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
387 dbus_message_iter_get_basic(&iter, &remote);
389 if (!dbus_message_iter_next(&iter) ||
390 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
393 dbus_message_iter_get_basic(&iter, &remote_user);
395 if (!dbus_message_iter_next(&iter) ||
396 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
399 dbus_message_iter_get_basic(&iter, &remote_host);
401 if (!dbus_message_iter_next(&iter) ||
402 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
403 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
406 r = bus_parse_strv_iter(&iter, &controllers);
410 if (strv_contains(controllers, "systemd") ||
411 !dbus_message_iter_next(&iter) ||
412 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
413 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
418 r = bus_parse_strv_iter(&iter, &reset_controllers);
422 if (strv_contains(reset_controllers, "systemd") ||
423 !dbus_message_iter_next(&iter) ||
424 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
429 dbus_message_iter_get_basic(&iter, &kill_processes);
431 r = manager_add_user_by_uid(m, uid, &user);
435 audit_session_from_pid(leader, &audit_id);
438 asprintf(&id, "%lu", (unsigned long) audit_id);
445 session = hashmap_get(m->sessions, id);
450 fifo_fd = session_create_fifo(session);
456 /* Session already exists, client is probably
457 * something like "su" which changes uid but
458 * is still the same audit session */
460 reply = dbus_message_new_method_return(message);
466 p = session_bus_path(session);
472 seat = session->seat ? session->seat->id : "";
473 vtnr = session->vtnr;
474 b = dbus_message_append_args(
476 DBUS_TYPE_STRING, &session->id,
477 DBUS_TYPE_OBJECT_PATH, &p,
478 DBUS_TYPE_STRING, &session->user->runtime_path,
479 DBUS_TYPE_UNIX_FD, &fifo_fd,
480 DBUS_TYPE_STRING, &seat,
481 DBUS_TYPE_UINT32, &vtnr,
490 close_nointr_nofail(fifo_fd);
493 strv_free(controllers);
494 strv_free(reset_controllers);
504 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
509 } while (hashmap_get(m->sessions, id));
512 r = manager_add_session(m, user, id, &session);
517 session->leader = leader;
518 session->audit_id = audit_id;
521 session->remote = remote;
522 session->controllers = controllers;
523 session->reset_controllers = reset_controllers;
524 session->kill_processes = kill_processes;
525 session->vtnr = vtnr;
527 controllers = reset_controllers = NULL;
530 session->tty = strdup(tty);
537 if (!isempty(display)) {
538 session->display = strdup(display);
539 if (!session->display) {
545 if (!isempty(remote_user)) {
546 session->remote_user = strdup(remote_user);
547 if (!session->remote_user) {
553 if (!isempty(remote_host)) {
554 session->remote_host = strdup(remote_host);
555 if (!session->remote_host) {
561 if (!isempty(service)) {
562 session->service = strdup(service);
563 if (!session->service) {
569 fifo_fd = session_create_fifo(session);
576 r = seat_attach_session(s, session);
581 r = session_start(session);
585 reply = dbus_message_new_method_return(message);
591 p = session_bus_path(session);
597 seat = s ? s->id : "";
598 b = dbus_message_append_args(
600 DBUS_TYPE_STRING, &session->id,
601 DBUS_TYPE_OBJECT_PATH, &p,
602 DBUS_TYPE_STRING, &session->user->runtime_path,
603 DBUS_TYPE_UNIX_FD, &fifo_fd,
604 DBUS_TYPE_STRING, &seat,
605 DBUS_TYPE_UINT32, &vtnr,
614 close_nointr_nofail(fifo_fd);
620 strv_free(controllers);
621 strv_free(reset_controllers);
624 session_add_to_gc_queue(session);
627 user_add_to_gc_queue(user);
630 close_nointr_nofail(fifo_fd);
633 dbus_message_unref(reply);
638 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
641 const char *who, *why, *what;
646 DBusMessage *reply = NULL;
654 if (!dbus_message_get_args(
657 DBUS_TYPE_STRING, &what,
658 DBUS_TYPE_STRING, &who,
659 DBUS_TYPE_STRING, &why,
660 DBUS_TYPE_INVALID)) {
665 w = inhibit_what_from_string(what);
671 r = verify_polkit(connection, message, "org.freedesktop.login1.inhibit", false, NULL, error);
675 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
676 if (ul == (unsigned long) -1) {
681 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
691 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
695 } while (hashmap_get(m->inhibitors, id));
697 r = manager_add_inhibitor(m, id, &i);
706 i->why = strdup(why);
707 i->who = strdup(who);
709 if (!i->why || !i->who) {
714 fifo_fd = inhibitor_create_fifo(i);
720 reply = dbus_message_new_method_return(message);
726 if (!dbus_message_append_args(
728 DBUS_TYPE_UNIX_FD, &fifo_fd,
729 DBUS_TYPE_INVALID)) {
734 close_nointr_nofail(fifo_fd);
746 close_nointr_nofail(fifo_fd);
749 dbus_message_unref(reply);
754 static int trigger_device(Manager *m, struct udev_device *d) {
755 struct udev_enumerate *e;
756 struct udev_list_entry *first, *item;
761 e = udev_enumerate_new(m->udev);
768 if (udev_enumerate_add_match_parent(e, d) < 0) {
774 if (udev_enumerate_scan_devices(e) < 0) {
779 first = udev_enumerate_get_list_entry(e);
780 udev_list_entry_foreach(item, first) {
784 p = udev_list_entry_get_name(item);
786 t = strappend(p, "/uevent");
792 write_one_line_file(t, "change");
800 udev_enumerate_unref(e);
805 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
806 struct udev_device *d;
807 char *rule = NULL, *file = NULL;
808 const char *id_for_seat;
815 d = udev_device_new_from_syspath(m->udev, sysfs);
819 if (!udev_device_has_tag(d, "seat")) {
824 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
830 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
835 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
840 mkdir_p("/etc/udev/rules.d", 0755);
841 r = write_one_line_file_atomic(file, rule);
845 r = trigger_device(m, d);
852 udev_device_unref(d);
857 static int flush_devices(Manager *m) {
862 d = opendir("/etc/udev/rules.d");
865 log_warning("Failed to open /etc/udev/rules.d: %m");
869 while ((de = readdir(d))) {
871 if (!dirent_is_file(de))
874 if (!startswith(de->d_name, "72-seat-"))
877 if (!endswith(de->d_name, ".rules"))
880 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
881 log_warning("Failed to unlink %s: %m", de->d_name);
887 return trigger_device(m, NULL);
890 static int have_multiple_sessions(
891 DBusConnection *connection,
893 DBusMessage *message,
900 if (hashmap_size(m->sessions) > 1)
903 /* Hmm, there's only one session, but let's make sure it
904 * actually belongs to the user who is asking. If not, better
905 * be safe than sorry. */
907 s = hashmap_first(m->sessions);
911 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
912 if (ul == (unsigned long) -1)
915 return s->user->uid != ul;
921 static const BusProperty bus_login_manager_properties[] = {
922 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
923 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
924 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
925 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
926 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
927 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
928 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
929 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
930 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
931 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
932 { "Inhibited", bus_manager_append_inhibited, "s", 0 },
936 static DBusHandlerResult manager_message_handler(
937 DBusConnection *connection,
938 DBusMessage *message,
941 Manager *m = userdata;
944 DBusMessage *reply = NULL;
951 dbus_error_init(&error);
953 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
959 if (!dbus_message_get_args(
962 DBUS_TYPE_STRING, &name,
964 return bus_send_error_reply(connection, message, &error, -EINVAL);
966 session = hashmap_get(m->sessions, name);
968 return bus_send_error_reply(connection, message, &error, -ENOENT);
970 reply = dbus_message_new_method_return(message);
974 p = session_bus_path(session);
978 b = dbus_message_append_args(
980 DBUS_TYPE_OBJECT_PATH, &p,
987 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
993 if (!dbus_message_get_args(
996 DBUS_TYPE_UINT32, &pid,
998 return bus_send_error_reply(connection, message, &error, -EINVAL);
1000 r = manager_get_session_by_pid(m, pid, &session);
1002 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1004 reply = dbus_message_new_method_return(message);
1008 p = session_bus_path(session);
1012 b = dbus_message_append_args(
1014 DBUS_TYPE_OBJECT_PATH, &p,
1021 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1027 if (!dbus_message_get_args(
1030 DBUS_TYPE_UINT32, &uid,
1032 return bus_send_error_reply(connection, message, &error, -EINVAL);
1034 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1036 return bus_send_error_reply(connection, message, &error, -ENOENT);
1038 reply = dbus_message_new_method_return(message);
1042 p = user_bus_path(user);
1046 b = dbus_message_append_args(
1048 DBUS_TYPE_OBJECT_PATH, &p,
1055 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1061 if (!dbus_message_get_args(
1064 DBUS_TYPE_STRING, &name,
1066 return bus_send_error_reply(connection, message, &error, -EINVAL);
1068 seat = hashmap_get(m->seats, name);
1070 return bus_send_error_reply(connection, message, &error, -ENOENT);
1072 reply = dbus_message_new_method_return(message);
1076 p = seat_bus_path(seat);
1080 b = dbus_message_append_args(
1082 DBUS_TYPE_OBJECT_PATH, &p,
1089 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1093 DBusMessageIter iter, sub;
1094 const char *empty = "";
1096 reply = dbus_message_new_method_return(message);
1100 dbus_message_iter_init_append(reply, &iter);
1102 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1105 HASHMAP_FOREACH(session, m->sessions, i) {
1106 DBusMessageIter sub2;
1109 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1112 uid = session->user->uid;
1114 p = session_bus_path(session);
1118 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1119 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1120 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1121 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1122 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1129 if (!dbus_message_iter_close_container(&sub, &sub2))
1133 if (!dbus_message_iter_close_container(&iter, &sub))
1136 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1140 DBusMessageIter iter, sub;
1142 reply = dbus_message_new_method_return(message);
1146 dbus_message_iter_init_append(reply, &iter);
1148 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1151 HASHMAP_FOREACH(user, m->users, i) {
1152 DBusMessageIter sub2;
1155 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1160 p = user_bus_path(user);
1164 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1165 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1166 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1173 if (!dbus_message_iter_close_container(&sub, &sub2))
1177 if (!dbus_message_iter_close_container(&iter, &sub))
1180 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1184 DBusMessageIter iter, sub;
1186 reply = dbus_message_new_method_return(message);
1190 dbus_message_iter_init_append(reply, &iter);
1192 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1195 HASHMAP_FOREACH(seat, m->seats, i) {
1196 DBusMessageIter sub2;
1198 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1201 p = seat_bus_path(seat);
1205 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1206 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1213 if (!dbus_message_iter_close_container(&sub, &sub2))
1217 if (!dbus_message_iter_close_container(&iter, &sub))
1220 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1221 Inhibitor *inhibitor;
1223 DBusMessageIter iter, sub;
1225 reply = dbus_message_new_method_return(message);
1229 dbus_message_iter_init_append(reply, &iter);
1231 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sssuu)", &sub))
1234 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1235 DBusMessageIter sub2;
1236 dbus_uint32_t uid, pid;
1237 const char *what, *who, *why;
1239 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1242 what = inhibit_what_to_string(inhibitor->what);
1243 who = strempty(inhibitor->who);
1244 why = strempty(inhibitor->why);
1245 uid = (dbus_uint32_t) inhibitor->uid;
1246 pid = (dbus_uint32_t) inhibitor->pid;
1248 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1249 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1250 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1251 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1252 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1255 if (!dbus_message_iter_close_container(&sub, &sub2))
1259 if (!dbus_message_iter_close_container(&iter, &sub))
1262 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1264 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1267 return bus_send_error_reply(connection, message, &error, r);
1270 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1272 r = bus_manager_create_session(m, message, &reply);
1274 /* Don't delay the work on OOM here, since it might be
1275 * triggered by a low RLIMIT_NOFILE here (since we
1276 * send a dupped fd to the client), and we'd rather
1277 * see this fail quickly then be retried later */
1280 return bus_send_error_reply(connection, message, NULL, r);
1282 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1286 if (!dbus_message_get_args(
1289 DBUS_TYPE_STRING, &name,
1291 return bus_send_error_reply(connection, message, &error, -EINVAL);
1293 session = hashmap_get(m->sessions, name);
1295 return bus_send_error_reply(connection, message, &error, -ENOENT);
1297 /* We use the FIFO to detect stray sessions where the
1298 process invoking PAM dies abnormally. We need to make
1299 sure that that process is not killed if at the clean
1300 end of the session it closes the FIFO. Hence, with
1301 this call explicitly turn off the FIFO logic, so that
1302 the PAM code can finish clean up on its own */
1303 session_remove_fifo(session);
1305 reply = dbus_message_new_method_return(message);
1309 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1313 if (!dbus_message_get_args(
1316 DBUS_TYPE_STRING, &name,
1318 return bus_send_error_reply(connection, message, &error, -EINVAL);
1320 session = hashmap_get(m->sessions, name);
1322 return bus_send_error_reply(connection, message, &error, -ENOENT);
1324 r = session_activate(session);
1326 return bus_send_error_reply(connection, message, NULL, r);
1328 reply = dbus_message_new_method_return(message);
1332 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1333 const char *session_name, *seat_name;
1337 /* Same as ActivateSession() but refuses to work if
1338 * the seat doesn't match */
1340 if (!dbus_message_get_args(
1343 DBUS_TYPE_STRING, &session_name,
1344 DBUS_TYPE_STRING, &seat_name,
1346 return bus_send_error_reply(connection, message, &error, -EINVAL);
1348 session = hashmap_get(m->sessions, session_name);
1350 return bus_send_error_reply(connection, message, &error, -ENOENT);
1352 seat = hashmap_get(m->seats, seat_name);
1354 return bus_send_error_reply(connection, message, &error, -ENOENT);
1356 if (session->seat != seat)
1357 return bus_send_error_reply(connection, message, &error, -EINVAL);
1359 r = session_activate(session);
1361 return bus_send_error_reply(connection, message, NULL, r);
1363 reply = dbus_message_new_method_return(message);
1367 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1368 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1372 if (!dbus_message_get_args(
1375 DBUS_TYPE_STRING, &name,
1377 return bus_send_error_reply(connection, message, &error, -EINVAL);
1379 session = hashmap_get(m->sessions, name);
1381 return bus_send_error_reply(connection, message, &error, -ENOENT);
1383 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1386 reply = dbus_message_new_method_return(message);
1390 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1397 if (!dbus_message_get_args(
1400 DBUS_TYPE_STRING, &name,
1401 DBUS_TYPE_STRING, &swho,
1402 DBUS_TYPE_INT32, &signo,
1404 return bus_send_error_reply(connection, message, &error, -EINVAL);
1409 who = kill_who_from_string(swho);
1411 return bus_send_error_reply(connection, message, &error, -EINVAL);
1414 if (signo <= 0 || signo >= _NSIG)
1415 return bus_send_error_reply(connection, message, &error, -EINVAL);
1417 session = hashmap_get(m->sessions, name);
1419 return bus_send_error_reply(connection, message, &error, -ENOENT);
1421 r = session_kill(session, who, signo);
1423 return bus_send_error_reply(connection, message, NULL, r);
1425 reply = dbus_message_new_method_return(message);
1429 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1434 if (!dbus_message_get_args(
1437 DBUS_TYPE_UINT32, &uid,
1438 DBUS_TYPE_INT32, &signo,
1440 return bus_send_error_reply(connection, message, &error, -EINVAL);
1442 if (signo <= 0 || signo >= _NSIG)
1443 return bus_send_error_reply(connection, message, &error, -EINVAL);
1445 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1447 return bus_send_error_reply(connection, message, &error, -ENOENT);
1449 r = user_kill(user, signo);
1451 return bus_send_error_reply(connection, message, NULL, r);
1453 reply = dbus_message_new_method_return(message);
1457 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1461 if (!dbus_message_get_args(
1464 DBUS_TYPE_STRING, &name,
1466 return bus_send_error_reply(connection, message, &error, -EINVAL);
1468 session = hashmap_get(m->sessions, name);
1470 return bus_send_error_reply(connection, message, &error, -ENOENT);
1472 r = session_stop(session);
1474 return bus_send_error_reply(connection, message, NULL, r);
1476 reply = dbus_message_new_method_return(message);
1480 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1484 if (!dbus_message_get_args(
1487 DBUS_TYPE_UINT32, &uid,
1489 return bus_send_error_reply(connection, message, &error, -EINVAL);
1491 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1493 return bus_send_error_reply(connection, message, &error, -ENOENT);
1495 r = user_stop(user);
1497 return bus_send_error_reply(connection, message, NULL, r);
1499 reply = dbus_message_new_method_return(message);
1503 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1507 if (!dbus_message_get_args(
1510 DBUS_TYPE_STRING, &name,
1512 return bus_send_error_reply(connection, message, &error, -EINVAL);
1514 seat = hashmap_get(m->seats, name);
1516 return bus_send_error_reply(connection, message, &error, -ENOENT);
1518 r = seat_stop_sessions(seat);
1520 return bus_send_error_reply(connection, message, NULL, r);
1522 reply = dbus_message_new_method_return(message);
1526 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1529 dbus_bool_t b, interactive;
1532 if (!dbus_message_get_args(
1535 DBUS_TYPE_UINT32, &uid,
1536 DBUS_TYPE_BOOLEAN, &b,
1537 DBUS_TYPE_BOOLEAN, &interactive,
1539 return bus_send_error_reply(connection, message, &error, -EINVAL);
1544 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1546 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1548 return bus_send_error_reply(connection, message, &error, r);
1550 mkdir_p("/var/lib/systemd", 0755);
1552 r = safe_mkdir("/var/lib/systemd/linger", 0755, 0, 0);
1554 return bus_send_error_reply(connection, message, &error, r);
1556 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1567 return bus_send_error_reply(connection, message, &error, r);
1569 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1578 if (r < 0 && errno != ENOENT)
1579 return bus_send_error_reply(connection, message, &error, -errno);
1581 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1583 user_add_to_gc_queue(u);
1586 reply = dbus_message_new_method_return(message);
1590 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1591 const char *sysfs, *seat;
1592 dbus_bool_t interactive;
1594 if (!dbus_message_get_args(
1597 DBUS_TYPE_STRING, &seat,
1598 DBUS_TYPE_STRING, &sysfs,
1599 DBUS_TYPE_BOOLEAN, &interactive,
1601 return bus_send_error_reply(connection, message, &error, -EINVAL);
1603 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
1604 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1606 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
1608 return bus_send_error_reply(connection, message, &error, r);
1610 r = attach_device(m, seat, sysfs);
1612 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1614 reply = dbus_message_new_method_return(message);
1619 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
1620 dbus_bool_t interactive;
1622 if (!dbus_message_get_args(
1625 DBUS_TYPE_BOOLEAN, &interactive,
1627 return bus_send_error_reply(connection, message, &error, -EINVAL);
1629 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
1631 return bus_send_error_reply(connection, message, &error, r);
1633 r = flush_devices(m);
1635 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1637 reply = dbus_message_new_method_return(message);
1641 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff") ||
1642 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
1643 dbus_bool_t interactive;
1644 bool multiple_sessions, inhibit;
1645 DBusMessage *forward, *freply;
1646 const char *name, *action;
1647 const char *mode = "replace";
1649 if (!dbus_message_get_args(
1652 DBUS_TYPE_BOOLEAN, &interactive,
1654 return bus_send_error_reply(connection, message, &error, -EINVAL);
1656 r = have_multiple_sessions(connection, m, message, &error);
1658 return bus_send_error_reply(connection, message, &error, r);
1660 multiple_sessions = r > 0;
1661 inhibit = manager_is_inhibited(m, INHIBIT_SHUTDOWN, NULL);
1663 if (multiple_sessions) {
1664 action = streq(dbus_message_get_member(message), "PowerOff") ?
1665 "org.freedesktop.login1.power-off-multiple-sessions" :
1666 "org.freedesktop.login1.reboot-multiple-sessions";
1668 r = verify_polkit(connection, message, action, interactive, NULL, &error);
1670 return bus_send_error_reply(connection, message, &error, r);
1674 action = streq(dbus_message_get_member(message), "PowerOff") ?
1675 "org.freedesktop.login1.power-off-ignore-inhibit" :
1676 "org.freedesktop.login1.reboot-ignore-inhibit";
1678 r = verify_polkit(connection, message, action, interactive, NULL, &error);
1680 return bus_send_error_reply(connection, message, &error, r);
1683 if (!multiple_sessions && !inhibit) {
1684 action = streq(dbus_message_get_member(message), "PowerOff") ?
1685 "org.freedesktop.login1.power-off" :
1686 "org.freedesktop.login1.reboot";
1688 r = verify_polkit(connection, message, action, interactive, NULL, &error);
1690 return bus_send_error_reply(connection, message, &error, r);
1693 forward = dbus_message_new_method_call(
1694 "org.freedesktop.systemd1",
1695 "/org/freedesktop/systemd1",
1696 "org.freedesktop.systemd1.Manager",
1699 return bus_send_error_reply(connection, message, NULL, -ENOMEM);
1701 name = streq(dbus_message_get_member(message), "PowerOff") ?
1702 SPECIAL_POWEROFF_TARGET : SPECIAL_REBOOT_TARGET;
1704 if (!dbus_message_append_args(forward,
1705 DBUS_TYPE_STRING, &name,
1706 DBUS_TYPE_STRING, &mode,
1707 DBUS_TYPE_INVALID)) {
1708 dbus_message_unref(forward);
1709 return bus_send_error_reply(connection, message, NULL, -ENOMEM);
1712 freply = dbus_connection_send_with_reply_and_block(connection, forward, -1, &error);
1713 dbus_message_unref(forward);
1716 return bus_send_error_reply(connection, message, &error, -EIO);
1718 dbus_message_unref(freply);
1720 reply = dbus_message_new_method_return(message);
1724 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff") ||
1725 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
1727 bool multiple_sessions, challenge, inhibit, b;
1728 const char *action, *result;
1730 r = have_multiple_sessions(connection, m, message, &error);
1732 return bus_send_error_reply(connection, message, &error, r);
1734 multiple_sessions = r > 0;
1735 inhibit = manager_is_inhibited(m, INHIBIT_SHUTDOWN, NULL);
1737 if (multiple_sessions) {
1738 action = streq(dbus_message_get_member(message), "CanPowerOff") ?
1739 "org.freedesktop.login1.power-off-multiple-sessions" :
1740 "org.freedesktop.login1.reboot-multiple-sessions";
1742 r = verify_polkit(connection, message, action, false, &challenge, &error);
1744 return bus_send_error_reply(connection, message, &error, r);
1749 result = "challenge";
1755 action = streq(dbus_message_get_member(message), "CanPowerOff") ?
1756 "org.freedesktop.login1.power-off-ignore-inhibit" :
1757 "org.freedesktop.login1.reboot-ignore-inhibit";
1759 r = verify_polkit(connection, message, action, false, &challenge, &error);
1761 return bus_send_error_reply(connection, message, &error, r);
1763 if (r > 0 && !result)
1765 else if (challenge && (!result || streq(result, "yes")))
1766 result = "challenge";
1771 if (!multiple_sessions && !inhibit) {
1772 /* If neither inhibit nor multiple sessions
1773 * apply then just check the normal policy */
1775 action = streq(dbus_message_get_member(message), "CanPowerOff") ?
1776 "org.freedesktop.login1.power-off" :
1777 "org.freedesktop.login1.reboot";
1779 r = verify_polkit(connection, message, action, false, &challenge, &error);
1781 return bus_send_error_reply(connection, message, &error, r);
1786 result = "challenge";
1791 reply = dbus_message_new_method_return(message);
1795 b = dbus_message_append_args(
1797 DBUS_TYPE_STRING, &result,
1802 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1803 char *introspection = NULL;
1812 if (!(reply = dbus_message_new_method_return(message)))
1815 /* We roll our own introspection code here, instead of
1816 * relying on bus_default_message_handler() because we
1817 * need to generate our introspection string
1820 if (!(f = open_memstream(&introspection, &size)))
1823 fputs(INTROSPECTION_BEGIN, f);
1825 HASHMAP_FOREACH(seat, m->seats, i) {
1826 p = bus_path_escape(seat->id);
1829 fprintf(f, "<node name=\"seat/%s\"/>", p);
1834 HASHMAP_FOREACH(user, m->users, i)
1835 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
1837 HASHMAP_FOREACH(session, m->sessions, i) {
1838 p = bus_path_escape(session->id);
1841 fprintf(f, "<node name=\"session/%s\"/>", p);
1846 fputs(INTROSPECTION_END, f);
1850 free(introspection);
1859 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1860 free(introspection);
1864 free(introspection);
1866 const BusBoundProperties bps[] = {
1867 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
1870 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1874 if (!dbus_connection_send(connection, reply, NULL))
1877 dbus_message_unref(reply);
1880 return DBUS_HANDLER_RESULT_HANDLED;
1884 dbus_message_unref(reply);
1886 dbus_error_free(&error);
1888 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1891 const DBusObjectPathVTable bus_manager_vtable = {
1892 .message_function = manager_message_handler
1895 DBusHandlerResult bus_message_filter(
1896 DBusConnection *connection,
1897 DBusMessage *message,
1900 Manager *m = userdata;
1907 dbus_error_init(&error);
1909 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
1912 if (!dbus_message_get_args(message, &error,
1913 DBUS_TYPE_STRING, &cgroup,
1915 log_error("Failed to parse Released message: %s", bus_error_message(&error));
1917 manager_cgroup_notify_empty(m, cgroup);
1920 dbus_error_free(&error);
1922 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1925 int manager_send_changed(Manager *manager, const char *properties) {
1931 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
1935 if (!dbus_connection_send(manager->bus, m, NULL))
1942 dbus_message_unref(m);