X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flogind-dbus.c;h=f39941c9d2f5d6e6c5e00ea9e1af9b9e4b4d7c70;hp=96216e43a358eaf81374d72664e3d7f624939ca8;hb=55af3897854263eddc0818d5cc4614ccbdae7f32;hpb=b668e06428a996348f81b352db3a1084a4e9adf5 diff --git a/src/logind-dbus.c b/src/logind-dbus.c index 96216e43a..f39941c9d 100644 --- a/src/logind-dbus.c +++ b/src/logind-dbus.c @@ -28,6 +28,7 @@ #include "dbus-common.h" #include "strv.h" #include "polkit.h" +#include "special.h" #define BUS_MANAGER_INTERFACE \ " \n" \ @@ -75,6 +76,21 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -97,6 +113,12 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -535,23 +557,7 @@ fail: return r; } -static bool device_has_tag(struct udev_device *d, const char *tag) { - struct udev_list_entry *first, *item; - - assert(d); - assert(tag); - - udev_device_get_is_initialized(d); - - first = udev_device_get_tags_list_entry(d); - udev_list_entry_foreach(item, first) - if (streq(udev_list_entry_get_name(item), tag)) - return true; - - return false; -} - -static int trigger_device(Manager *m, const char *prefix) { +static int trigger_device(Manager *m, struct udev_device *d) { struct udev_enumerate *e; struct udev_list_entry *first, *item; int r; @@ -564,6 +570,14 @@ static int trigger_device(Manager *m, const char *prefix) { goto finish; } + if (d) { + if (udev_enumerate_add_match_parent(e, d) < 0) { + r = -EIO; + goto finish; + } + } + + if (udev_enumerate_scan_devices(e) < 0) { r = -EIO; goto finish; @@ -576,9 +590,6 @@ static int trigger_device(Manager *m, const char *prefix) { p = udev_list_entry_get_name(item); - if (prefix && !path_startswith(p, prefix)) - continue; - t = strappend(p, "/uevent"); if (!t) { r = -ENOMEM; @@ -612,7 +623,7 @@ static int attach_device(Manager *m, const char *seat, const char *sysfs) { if (!d) return -ENODEV; - if (!device_has_tag(d, "seat")) { + if (!udev_device_has_tag(d, "seat")) { r = -ENODEV; goto finish; } @@ -634,11 +645,11 @@ static int attach_device(Manager *m, const char *seat, const char *sysfs) { } mkdir_p("/etc/udev/rules.d", 0755); - r = write_one_line_file(file, rule); + r = write_one_line_file_atomic(file, rule); if (r < 0) goto finish; - r = trigger_device(m, sysfs); + r = trigger_device(m, d); finish: free(rule); @@ -979,6 +990,96 @@ static DBusHandlerResult manager_message_handler( if (!reply) goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") || + dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) { + const char *name; + Session *session; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + session = hashmap_get(m->sessions, name); + if (!session) + return bus_send_error_reply(connection, message, &error, -ENOENT); + + if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0) + goto oom; + + reply = dbus_message_new_method_return(message); + if (!reply) + goto oom; + + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) { + const char *swho; + int32_t signo; + KillWho who; + const char *name; + Session *session; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &swho, + DBUS_TYPE_INT32, &signo, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + if (isempty(swho)) + who = KILL_ALL; + else { + who = kill_who_from_string(swho); + if (who < 0) + return bus_send_error_reply(connection, message, &error, -EINVAL); + } + + if (signo <= 0 || signo >= _NSIG) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + session = hashmap_get(m->sessions, name); + if (!session) + return bus_send_error_reply(connection, message, &error, -ENOENT); + + r = session_kill(session, who, signo); + if (r < 0) + return bus_send_error_reply(connection, message, NULL, r); + + reply = dbus_message_new_method_return(message); + if (!reply) + goto oom; + + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) { + uint32_t uid; + User *user; + int32_t signo; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_UINT32, &uid, + DBUS_TYPE_INT32, &signo, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + if (signo <= 0 || signo >= _NSIG) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid)); + if (!user) + return bus_send_error_reply(connection, message, &error, -ENOENT); + + r = user_kill(user, signo); + if (r < 0) + return bus_send_error_reply(connection, message, NULL, r); + + reply = dbus_message_new_method_return(message); + if (!reply) + goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) { const char *name; Session *session; @@ -1161,6 +1262,92 @@ static DBusHandlerResult manager_message_handler( if (!reply) goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff") || + dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) { + dbus_bool_t interactive; + bool multiple_sessions; + DBusMessage *forward, *freply; + const char *name; + const char *mode = "replace"; + const char *action; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_BOOLEAN, &interactive, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + multiple_sessions = hashmap_size(m->sessions) > 1; + + if (!multiple_sessions) { + Session *s; + + /* Hmm, there's only one session, but let's + * make sure it actually belongs to the user + * who is asking. If not, better be safe than + * sorry. */ + + s = hashmap_first(m->sessions); + if (s) { + unsigned long ul; + + ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error); + if (ul == (unsigned long) -1) + return bus_send_error_reply(connection, message, &error, -EIO); + + multiple_sessions = s->user->uid != ul; + } + } + + if (streq(dbus_message_get_member(message), "PowerOff")) { + if (multiple_sessions) + action = "org.freedesktop.login1.power-off-multiple-sessions"; + else + action = "org.freedesktop.login1.power-off"; + + name = SPECIAL_POWEROFF_TARGET; + } else { + if (multiple_sessions) + action = "org.freedesktop.login1.reboot-multiple-sessions"; + else + action = "org.freedesktop.login1.reboot"; + + name = SPECIAL_REBOOT_TARGET; + } + + r = verify_polkit(connection, message, action, interactive, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + forward = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartUnit"); + if (!forward) + return bus_send_error_reply(connection, message, NULL, -ENOMEM); + + if (!dbus_message_append_args(forward, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &mode, + DBUS_TYPE_INVALID)) { + dbus_message_unref(forward); + return bus_send_error_reply(connection, message, NULL, -ENOMEM); + } + + freply = dbus_connection_send_with_reply_and_block(connection, forward, -1, &error); + dbus_message_unref(forward); + + if (!freply) + return bus_send_error_reply(connection, message, &error, -EIO); + + dbus_message_unref(freply); + + reply = dbus_message_new_method_return(message); + if (!reply) + goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { char *introspection = NULL; FILE *f;