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)
355 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
359 if (seat_can_multi_session(s)) {
360 if (vtnr <= 0 || vtnr > 63)
368 if (!dbus_message_iter_next(&iter) ||
369 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
372 dbus_message_iter_get_basic(&iter, &display);
374 if (!dbus_message_iter_next(&iter) ||
375 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
378 dbus_message_iter_get_basic(&iter, &remote);
380 if (!dbus_message_iter_next(&iter) ||
381 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
384 dbus_message_iter_get_basic(&iter, &remote_user);
386 if (!dbus_message_iter_next(&iter) ||
387 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
390 dbus_message_iter_get_basic(&iter, &remote_host);
392 if (!dbus_message_iter_next(&iter) ||
393 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
394 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
397 r = bus_parse_strv_iter(&iter, &controllers);
401 if (strv_contains(controllers, "systemd") ||
402 !dbus_message_iter_next(&iter) ||
403 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
404 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
409 r = bus_parse_strv_iter(&iter, &reset_controllers);
413 if (strv_contains(reset_controllers, "systemd") ||
414 !dbus_message_iter_next(&iter) ||
415 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
420 dbus_message_iter_get_basic(&iter, &kill_processes);
422 r = manager_add_user_by_uid(m, uid, &user);
426 audit_session_from_pid(leader, &audit_id);
429 asprintf(&id, "%lu", (unsigned long) audit_id);
436 session = hashmap_get(m->sessions, id);
441 fifo_fd = session_create_fifo(session);
447 /* Session already exists, client is probably
448 * something like "su" which changes uid but
449 * is still the same audit session */
451 reply = dbus_message_new_method_return(message);
457 p = session_bus_path(session);
463 seat = session->seat ? session->seat->id : "";
464 vtnr = session->vtnr;
465 b = dbus_message_append_args(
467 DBUS_TYPE_STRING, &session->id,
468 DBUS_TYPE_OBJECT_PATH, &p,
469 DBUS_TYPE_STRING, &session->user->runtime_path,
470 DBUS_TYPE_UNIX_FD, &fifo_fd,
471 DBUS_TYPE_STRING, &seat,
472 DBUS_TYPE_UINT32, &vtnr,
481 close_nointr_nofail(fifo_fd);
484 strv_free(controllers);
485 strv_free(reset_controllers);
495 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
500 } while (hashmap_get(m->sessions, id));
503 r = manager_add_session(m, user, id, &session);
508 session->leader = leader;
509 session->audit_id = audit_id;
512 session->remote = remote;
513 session->controllers = controllers;
514 session->reset_controllers = reset_controllers;
515 session->kill_processes = kill_processes;
516 session->vtnr = vtnr;
518 controllers = reset_controllers = NULL;
521 session->tty = strdup(tty);
528 if (!isempty(display)) {
529 session->display = strdup(display);
530 if (!session->display) {
536 if (!isempty(remote_user)) {
537 session->remote_user = strdup(remote_user);
538 if (!session->remote_user) {
544 if (!isempty(remote_host)) {
545 session->remote_host = strdup(remote_host);
546 if (!session->remote_host) {
552 if (!isempty(service)) {
553 session->service = strdup(service);
554 if (!session->service) {
560 fifo_fd = session_create_fifo(session);
567 r = seat_attach_session(s, session);
572 r = session_start(session);
576 reply = dbus_message_new_method_return(message);
582 p = session_bus_path(session);
588 seat = s ? s->id : "";
589 b = dbus_message_append_args(
591 DBUS_TYPE_STRING, &session->id,
592 DBUS_TYPE_OBJECT_PATH, &p,
593 DBUS_TYPE_STRING, &session->user->runtime_path,
594 DBUS_TYPE_UNIX_FD, &fifo_fd,
595 DBUS_TYPE_STRING, &seat,
596 DBUS_TYPE_UINT32, &vtnr,
605 close_nointr_nofail(fifo_fd);
611 strv_free(controllers);
612 strv_free(reset_controllers);
615 session_add_to_gc_queue(session);
618 user_add_to_gc_queue(user);
621 close_nointr_nofail(fifo_fd);
624 dbus_message_unref(reply);
629 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
632 const char *who, *why, *what;
637 DBusMessage *reply = NULL;
645 if (!dbus_message_get_args(
648 DBUS_TYPE_STRING, &what,
649 DBUS_TYPE_STRING, &who,
650 DBUS_TYPE_STRING, &why,
651 DBUS_TYPE_INVALID)) {
656 w = inhibit_what_from_string(what);
662 r = verify_polkit(connection, message, "org.freedesktop.login1.inhibit", false, NULL, error);
666 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
667 if (ul == (unsigned long) -1) {
672 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
682 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
686 } while (hashmap_get(m->inhibitors, id));
688 r = manager_add_inhibitor(m, id, &i);
697 i->why = strdup(why);
698 i->who = strdup(who);
700 if (!i->why || !i->who) {
705 fifo_fd = inhibitor_create_fifo(i);
711 reply = dbus_message_new_method_return(message);
717 if (!dbus_message_append_args(
719 DBUS_TYPE_UNIX_FD, &fifo_fd,
720 DBUS_TYPE_INVALID)) {
725 close_nointr_nofail(fifo_fd);
737 close_nointr_nofail(fifo_fd);
740 dbus_message_unref(reply);
745 static int trigger_device(Manager *m, struct udev_device *d) {
746 struct udev_enumerate *e;
747 struct udev_list_entry *first, *item;
752 e = udev_enumerate_new(m->udev);
759 if (udev_enumerate_add_match_parent(e, d) < 0) {
765 if (udev_enumerate_scan_devices(e) < 0) {
770 first = udev_enumerate_get_list_entry(e);
771 udev_list_entry_foreach(item, first) {
775 p = udev_list_entry_get_name(item);
777 t = strappend(p, "/uevent");
783 write_one_line_file(t, "change");
791 udev_enumerate_unref(e);
796 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
797 struct udev_device *d;
798 char *rule = NULL, *file = NULL;
799 const char *id_for_seat;
806 d = udev_device_new_from_syspath(m->udev, sysfs);
810 if (!udev_device_has_tag(d, "seat")) {
815 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
821 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
826 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
831 mkdir_p("/etc/udev/rules.d", 0755);
832 r = write_one_line_file_atomic(file, rule);
836 r = trigger_device(m, d);
843 udev_device_unref(d);
848 static int flush_devices(Manager *m) {
853 d = opendir("/etc/udev/rules.d");
856 log_warning("Failed to open /etc/udev/rules.d: %m");
860 while ((de = readdir(d))) {
862 if (!dirent_is_file(de))
865 if (!startswith(de->d_name, "72-seat-"))
868 if (!endswith(de->d_name, ".rules"))
871 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
872 log_warning("Failed to unlink %s: %m", de->d_name);
878 return trigger_device(m, NULL);
881 static int have_multiple_sessions(
882 DBusConnection *connection,
884 DBusMessage *message,
891 if (hashmap_size(m->sessions) > 1)
894 /* Hmm, there's only one session, but let's make sure it
895 * actually belongs to the user who is asking. If not, better
896 * be safe than sorry. */
898 s = hashmap_first(m->sessions);
902 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
903 if (ul == (unsigned long) -1)
906 return s->user->uid != ul;
912 static const BusProperty bus_login_manager_properties[] = {
913 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
914 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
915 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
916 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
917 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
918 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
919 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
920 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
921 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
922 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
923 { "Inhibited", bus_manager_append_inhibited, "s", 0 },
927 static DBusHandlerResult manager_message_handler(
928 DBusConnection *connection,
929 DBusMessage *message,
932 Manager *m = userdata;
935 DBusMessage *reply = NULL;
942 dbus_error_init(&error);
944 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
950 if (!dbus_message_get_args(
953 DBUS_TYPE_STRING, &name,
955 return bus_send_error_reply(connection, message, &error, -EINVAL);
957 session = hashmap_get(m->sessions, name);
959 return bus_send_error_reply(connection, message, &error, -ENOENT);
961 reply = dbus_message_new_method_return(message);
965 p = session_bus_path(session);
969 b = dbus_message_append_args(
971 DBUS_TYPE_OBJECT_PATH, &p,
978 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
984 if (!dbus_message_get_args(
987 DBUS_TYPE_UINT32, &pid,
989 return bus_send_error_reply(connection, message, &error, -EINVAL);
991 r = manager_get_session_by_pid(m, pid, &session);
993 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
995 reply = dbus_message_new_method_return(message);
999 p = session_bus_path(session);
1003 b = dbus_message_append_args(
1005 DBUS_TYPE_OBJECT_PATH, &p,
1012 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1018 if (!dbus_message_get_args(
1021 DBUS_TYPE_UINT32, &uid,
1023 return bus_send_error_reply(connection, message, &error, -EINVAL);
1025 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1027 return bus_send_error_reply(connection, message, &error, -ENOENT);
1029 reply = dbus_message_new_method_return(message);
1033 p = user_bus_path(user);
1037 b = dbus_message_append_args(
1039 DBUS_TYPE_OBJECT_PATH, &p,
1046 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1052 if (!dbus_message_get_args(
1055 DBUS_TYPE_STRING, &name,
1057 return bus_send_error_reply(connection, message, &error, -EINVAL);
1059 seat = hashmap_get(m->seats, name);
1061 return bus_send_error_reply(connection, message, &error, -ENOENT);
1063 reply = dbus_message_new_method_return(message);
1067 p = seat_bus_path(seat);
1071 b = dbus_message_append_args(
1073 DBUS_TYPE_OBJECT_PATH, &p,
1080 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1084 DBusMessageIter iter, sub;
1085 const char *empty = "";
1087 reply = dbus_message_new_method_return(message);
1091 dbus_message_iter_init_append(reply, &iter);
1093 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1096 HASHMAP_FOREACH(session, m->sessions, i) {
1097 DBusMessageIter sub2;
1100 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1103 uid = session->user->uid;
1105 p = session_bus_path(session);
1109 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1110 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1111 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1112 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1113 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1120 if (!dbus_message_iter_close_container(&sub, &sub2))
1124 if (!dbus_message_iter_close_container(&iter, &sub))
1127 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1131 DBusMessageIter iter, sub;
1133 reply = dbus_message_new_method_return(message);
1137 dbus_message_iter_init_append(reply, &iter);
1139 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1142 HASHMAP_FOREACH(user, m->users, i) {
1143 DBusMessageIter sub2;
1146 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1151 p = user_bus_path(user);
1155 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1156 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1157 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1164 if (!dbus_message_iter_close_container(&sub, &sub2))
1168 if (!dbus_message_iter_close_container(&iter, &sub))
1171 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1175 DBusMessageIter iter, sub;
1177 reply = dbus_message_new_method_return(message);
1181 dbus_message_iter_init_append(reply, &iter);
1183 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1186 HASHMAP_FOREACH(seat, m->seats, i) {
1187 DBusMessageIter sub2;
1189 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1192 p = seat_bus_path(seat);
1196 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1197 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1204 if (!dbus_message_iter_close_container(&sub, &sub2))
1208 if (!dbus_message_iter_close_container(&iter, &sub))
1211 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1212 Inhibitor *inhibitor;
1214 DBusMessageIter iter, sub;
1216 reply = dbus_message_new_method_return(message);
1220 dbus_message_iter_init_append(reply, &iter);
1222 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sssuu)", &sub))
1225 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1226 DBusMessageIter sub2;
1227 dbus_uint32_t uid, pid;
1228 const char *what, *who, *why;
1230 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1233 what = inhibit_what_to_string(inhibitor->what);
1234 who = strempty(inhibitor->who);
1235 why = strempty(inhibitor->why);
1236 uid = (dbus_uint32_t) inhibitor->uid;
1237 pid = (dbus_uint32_t) inhibitor->pid;
1239 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1240 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1241 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1242 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1243 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1246 if (!dbus_message_iter_close_container(&sub, &sub2))
1250 if (!dbus_message_iter_close_container(&iter, &sub))
1253 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1255 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1258 return bus_send_error_reply(connection, message, &error, r);
1261 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1263 r = bus_manager_create_session(m, message, &reply);
1265 /* Don't delay the work on OOM here, since it might be
1266 * triggered by a low RLIMIT_NOFILE here (since we
1267 * send a dupped fd to the client), and we'd rather
1268 * see this fail quickly then be retried later */
1271 return bus_send_error_reply(connection, message, NULL, r);
1273 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1277 if (!dbus_message_get_args(
1280 DBUS_TYPE_STRING, &name,
1282 return bus_send_error_reply(connection, message, &error, -EINVAL);
1284 session = hashmap_get(m->sessions, name);
1286 return bus_send_error_reply(connection, message, &error, -ENOENT);
1288 /* We use the FIFO to detect stray sessions where the
1289 process invoking PAM dies abnormally. We need to make
1290 sure that that process is not killed if at the clean
1291 end of the session it closes the FIFO. Hence, with
1292 this call explicitly turn off the FIFO logic, so that
1293 the PAM code can finish clean up on its own */
1294 session_remove_fifo(session);
1296 reply = dbus_message_new_method_return(message);
1300 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1304 if (!dbus_message_get_args(
1307 DBUS_TYPE_STRING, &name,
1309 return bus_send_error_reply(connection, message, &error, -EINVAL);
1311 session = hashmap_get(m->sessions, name);
1313 return bus_send_error_reply(connection, message, &error, -ENOENT);
1315 r = session_activate(session);
1317 return bus_send_error_reply(connection, message, NULL, r);
1319 reply = dbus_message_new_method_return(message);
1323 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1324 const char *session_name, *seat_name;
1328 /* Same as ActivateSession() but refuses to work if
1329 * the seat doesn't match */
1331 if (!dbus_message_get_args(
1334 DBUS_TYPE_STRING, &session_name,
1335 DBUS_TYPE_STRING, &seat_name,
1337 return bus_send_error_reply(connection, message, &error, -EINVAL);
1339 session = hashmap_get(m->sessions, session_name);
1341 return bus_send_error_reply(connection, message, &error, -ENOENT);
1343 seat = hashmap_get(m->seats, seat_name);
1345 return bus_send_error_reply(connection, message, &error, -ENOENT);
1347 if (session->seat != seat)
1348 return bus_send_error_reply(connection, message, &error, -EINVAL);
1350 r = session_activate(session);
1352 return bus_send_error_reply(connection, message, NULL, r);
1354 reply = dbus_message_new_method_return(message);
1358 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1359 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1363 if (!dbus_message_get_args(
1366 DBUS_TYPE_STRING, &name,
1368 return bus_send_error_reply(connection, message, &error, -EINVAL);
1370 session = hashmap_get(m->sessions, name);
1372 return bus_send_error_reply(connection, message, &error, -ENOENT);
1374 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1377 reply = dbus_message_new_method_return(message);
1381 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1388 if (!dbus_message_get_args(
1391 DBUS_TYPE_STRING, &name,
1392 DBUS_TYPE_STRING, &swho,
1393 DBUS_TYPE_INT32, &signo,
1395 return bus_send_error_reply(connection, message, &error, -EINVAL);
1400 who = kill_who_from_string(swho);
1402 return bus_send_error_reply(connection, message, &error, -EINVAL);
1405 if (signo <= 0 || signo >= _NSIG)
1406 return bus_send_error_reply(connection, message, &error, -EINVAL);
1408 session = hashmap_get(m->sessions, name);
1410 return bus_send_error_reply(connection, message, &error, -ENOENT);
1412 r = session_kill(session, who, signo);
1414 return bus_send_error_reply(connection, message, NULL, r);
1416 reply = dbus_message_new_method_return(message);
1420 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1425 if (!dbus_message_get_args(
1428 DBUS_TYPE_UINT32, &uid,
1429 DBUS_TYPE_INT32, &signo,
1431 return bus_send_error_reply(connection, message, &error, -EINVAL);
1433 if (signo <= 0 || signo >= _NSIG)
1434 return bus_send_error_reply(connection, message, &error, -EINVAL);
1436 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1438 return bus_send_error_reply(connection, message, &error, -ENOENT);
1440 r = user_kill(user, signo);
1442 return bus_send_error_reply(connection, message, NULL, r);
1444 reply = dbus_message_new_method_return(message);
1448 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1452 if (!dbus_message_get_args(
1455 DBUS_TYPE_STRING, &name,
1457 return bus_send_error_reply(connection, message, &error, -EINVAL);
1459 session = hashmap_get(m->sessions, name);
1461 return bus_send_error_reply(connection, message, &error, -ENOENT);
1463 r = session_stop(session);
1465 return bus_send_error_reply(connection, message, NULL, r);
1467 reply = dbus_message_new_method_return(message);
1471 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1475 if (!dbus_message_get_args(
1478 DBUS_TYPE_UINT32, &uid,
1480 return bus_send_error_reply(connection, message, &error, -EINVAL);
1482 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1484 return bus_send_error_reply(connection, message, &error, -ENOENT);
1486 r = user_stop(user);
1488 return bus_send_error_reply(connection, message, NULL, r);
1490 reply = dbus_message_new_method_return(message);
1494 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1498 if (!dbus_message_get_args(
1501 DBUS_TYPE_STRING, &name,
1503 return bus_send_error_reply(connection, message, &error, -EINVAL);
1505 seat = hashmap_get(m->seats, name);
1507 return bus_send_error_reply(connection, message, &error, -ENOENT);
1509 r = seat_stop_sessions(seat);
1511 return bus_send_error_reply(connection, message, NULL, r);
1513 reply = dbus_message_new_method_return(message);
1517 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1520 dbus_bool_t b, interactive;
1523 if (!dbus_message_get_args(
1526 DBUS_TYPE_UINT32, &uid,
1527 DBUS_TYPE_BOOLEAN, &b,
1528 DBUS_TYPE_BOOLEAN, &interactive,
1530 return bus_send_error_reply(connection, message, &error, -EINVAL);
1535 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1537 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1539 return bus_send_error_reply(connection, message, &error, r);
1541 mkdir_p("/var/lib/systemd", 0755);
1543 r = safe_mkdir("/var/lib/systemd/linger", 0755, 0, 0);
1545 return bus_send_error_reply(connection, message, &error, r);
1547 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1558 return bus_send_error_reply(connection, message, &error, r);
1560 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1569 if (r < 0 && errno != ENOENT)
1570 return bus_send_error_reply(connection, message, &error, -errno);
1572 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1574 user_add_to_gc_queue(u);
1577 reply = dbus_message_new_method_return(message);
1581 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1582 const char *sysfs, *seat;
1583 dbus_bool_t interactive;
1585 if (!dbus_message_get_args(
1588 DBUS_TYPE_STRING, &seat,
1589 DBUS_TYPE_STRING, &sysfs,
1590 DBUS_TYPE_BOOLEAN, &interactive,
1592 return bus_send_error_reply(connection, message, &error, -EINVAL);
1594 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
1595 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1597 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
1599 return bus_send_error_reply(connection, message, &error, r);
1601 r = attach_device(m, seat, sysfs);
1603 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1605 reply = dbus_message_new_method_return(message);
1610 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
1611 dbus_bool_t interactive;
1613 if (!dbus_message_get_args(
1616 DBUS_TYPE_BOOLEAN, &interactive,
1618 return bus_send_error_reply(connection, message, &error, -EINVAL);
1620 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
1622 return bus_send_error_reply(connection, message, &error, r);
1624 r = flush_devices(m);
1626 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1628 reply = dbus_message_new_method_return(message);
1632 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff") ||
1633 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
1634 dbus_bool_t interactive;
1635 bool multiple_sessions, inhibit;
1636 DBusMessage *forward, *freply;
1637 const char *name, *action;
1638 const char *mode = "replace";
1640 if (!dbus_message_get_args(
1643 DBUS_TYPE_BOOLEAN, &interactive,
1645 return bus_send_error_reply(connection, message, &error, -EINVAL);
1647 r = have_multiple_sessions(connection, m, message, &error);
1649 return bus_send_error_reply(connection, message, &error, r);
1651 multiple_sessions = r > 0;
1652 inhibit = manager_is_inhibited(m, INHIBIT_SHUTDOWN, NULL);
1654 if (multiple_sessions) {
1655 action = streq(dbus_message_get_member(message), "PowerOff") ?
1656 "org.freedesktop.login1.power-off-multiple-sessions" :
1657 "org.freedesktop.login1.reboot-multiple-sessions";
1659 r = verify_polkit(connection, message, action, interactive, NULL, &error);
1661 return bus_send_error_reply(connection, message, &error, r);
1665 action = streq(dbus_message_get_member(message), "PowerOff") ?
1666 "org.freedesktop.login1.power-off-ignore-inhibit" :
1667 "org.freedesktop.login1.reboot-ignore-inhibit";
1669 r = verify_polkit(connection, message, action, interactive, NULL, &error);
1671 return bus_send_error_reply(connection, message, &error, r);
1674 if (!multiple_sessions && !inhibit) {
1675 action = streq(dbus_message_get_member(message), "PowerOff") ?
1676 "org.freedesktop.login1.power-off" :
1677 "org.freedesktop.login1.reboot";
1679 r = verify_polkit(connection, message, action, interactive, NULL, &error);
1681 return bus_send_error_reply(connection, message, &error, r);
1684 forward = dbus_message_new_method_call(
1685 "org.freedesktop.systemd1",
1686 "/org/freedesktop/systemd1",
1687 "org.freedesktop.systemd1.Manager",
1690 return bus_send_error_reply(connection, message, NULL, -ENOMEM);
1692 name = streq(dbus_message_get_member(message), "PowerOff") ?
1693 SPECIAL_POWEROFF_TARGET : SPECIAL_REBOOT_TARGET;
1695 if (!dbus_message_append_args(forward,
1696 DBUS_TYPE_STRING, &name,
1697 DBUS_TYPE_STRING, &mode,
1698 DBUS_TYPE_INVALID)) {
1699 dbus_message_unref(forward);
1700 return bus_send_error_reply(connection, message, NULL, -ENOMEM);
1703 freply = dbus_connection_send_with_reply_and_block(connection, forward, -1, &error);
1704 dbus_message_unref(forward);
1707 return bus_send_error_reply(connection, message, &error, -EIO);
1709 dbus_message_unref(freply);
1711 reply = dbus_message_new_method_return(message);
1715 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff") ||
1716 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
1718 bool multiple_sessions, challenge, inhibit, b;
1719 const char *action, *result;
1721 r = have_multiple_sessions(connection, m, message, &error);
1723 return bus_send_error_reply(connection, message, &error, r);
1725 multiple_sessions = r > 0;
1726 inhibit = manager_is_inhibited(m, INHIBIT_SHUTDOWN, NULL);
1728 if (multiple_sessions) {
1729 action = streq(dbus_message_get_member(message), "CanPowerOff") ?
1730 "org.freedesktop.login1.power-off-multiple-sessions" :
1731 "org.freedesktop.login1.reboot-multiple-sessions";
1733 r = verify_polkit(connection, message, action, false, &challenge, &error);
1735 return bus_send_error_reply(connection, message, &error, r);
1740 result = "challenge";
1746 action = streq(dbus_message_get_member(message), "CanPowerOff") ?
1747 "org.freedesktop.login1.power-off-ignore-inhibit" :
1748 "org.freedesktop.login1.reboot-ignore-inhibit";
1750 r = verify_polkit(connection, message, action, false, &challenge, &error);
1752 return bus_send_error_reply(connection, message, &error, r);
1754 if (r > 0 && !result)
1756 else if (challenge && (!result || streq(result, "yes")))
1757 result = "challenge";
1762 if (!multiple_sessions && !inhibit) {
1763 /* If neither inhibit nor multiple sessions
1764 * apply then just check the normal policy */
1766 action = streq(dbus_message_get_member(message), "CanPowerOff") ?
1767 "org.freedesktop.login1.power-off" :
1768 "org.freedesktop.login1.reboot";
1770 r = verify_polkit(connection, message, action, false, &challenge, &error);
1772 return bus_send_error_reply(connection, message, &error, r);
1777 result = "challenge";
1782 reply = dbus_message_new_method_return(message);
1786 b = dbus_message_append_args(
1788 DBUS_TYPE_STRING, &result,
1793 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1794 char *introspection = NULL;
1803 if (!(reply = dbus_message_new_method_return(message)))
1806 /* We roll our own introspection code here, instead of
1807 * relying on bus_default_message_handler() because we
1808 * need to generate our introspection string
1811 if (!(f = open_memstream(&introspection, &size)))
1814 fputs(INTROSPECTION_BEGIN, f);
1816 HASHMAP_FOREACH(seat, m->seats, i) {
1817 p = bus_path_escape(seat->id);
1820 fprintf(f, "<node name=\"seat/%s\"/>", p);
1825 HASHMAP_FOREACH(user, m->users, i)
1826 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
1828 HASHMAP_FOREACH(session, m->sessions, i) {
1829 p = bus_path_escape(session->id);
1832 fprintf(f, "<node name=\"session/%s\"/>", p);
1837 fputs(INTROSPECTION_END, f);
1841 free(introspection);
1850 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1851 free(introspection);
1855 free(introspection);
1857 const BusBoundProperties bps[] = {
1858 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
1861 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1865 if (!dbus_connection_send(connection, reply, NULL))
1868 dbus_message_unref(reply);
1871 return DBUS_HANDLER_RESULT_HANDLED;
1875 dbus_message_unref(reply);
1877 dbus_error_free(&error);
1879 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1882 const DBusObjectPathVTable bus_manager_vtable = {
1883 .message_function = manager_message_handler
1886 DBusHandlerResult bus_message_filter(
1887 DBusConnection *connection,
1888 DBusMessage *message,
1891 Manager *m = userdata;
1898 dbus_error_init(&error);
1900 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
1903 if (!dbus_message_get_args(message, &error,
1904 DBUS_TYPE_STRING, &cgroup,
1906 log_error("Failed to parse Released message: %s", bus_error_message(&error));
1908 manager_cgroup_notify_empty(m, cgroup);
1911 dbus_error_free(&error);
1913 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1916 int manager_send_changed(Manager *manager, const char *properties) {
1922 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
1926 if (!dbus_connection_send(manager->bus, m, NULL))
1933 dbus_message_unref(m);