X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flogind-dbus.c;h=4321ffd90043906f4736f0de0790a7e35e569083;hp=136f610cb625b746931d166cad087e0aae6c73c4;hb=2eb916cdff570a2ce741fc9b40d7316a77c57c27;hpb=31b79c2b4a34961eefc3b3680704124d8490d105 diff --git a/src/logind-dbus.c b/src/logind-dbus.c index 136f610cb..4321ffd90 100644 --- a/src/logind-dbus.c +++ b/src/logind-dbus.c @@ -22,10 +22,12 @@ #include #include #include +#include #include "logind.h" #include "dbus-common.h" #include "strv.h" +#include "polkit.h" #define BUS_MANAGER_INTERFACE \ " \n" \ @@ -53,9 +55,10 @@ " \n" \ " \n" \ " \n" \ - " \n" \ + " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -72,6 +75,21 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -81,6 +99,19 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -177,8 +208,8 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess DBusMessageIter iter; int r; char *id = NULL, *p; - int vtnr = -1; - int pipe_fds[2] = { -1, -1 }; + uint32_t vtnr = 0; + int fifo_fd = -1; DBusMessage *reply = NULL; bool b; @@ -227,6 +258,12 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess return -ENOENT; } + if (!dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) + return -EINVAL; + + dbus_message_iter_get_basic(&iter, &vtnr); + if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) return -EINVAL; @@ -234,20 +271,36 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess dbus_message_iter_get_basic(&iter, &tty); if (tty_is_vc(tty)) { + int v; if (!s) s = m->vtconsole; else if (s != m->vtconsole) return -EINVAL; - vtnr = vtnr_from_tty(tty); + v = vtnr_from_tty(tty); + + if (v <= 0) + return v < 0 ? v : -EINVAL; if (vtnr <= 0) - return vtnr < 0 ? vtnr : -EINVAL; + vtnr = (uint32_t) v; + else if (vtnr != (uint32_t) v) + return -EINVAL; - } else if (s == m->vtconsole) + } else if (!isempty(tty) && s && seat_is_vtconsole(s)) return -EINVAL; + if (s) { + if (seat_is_vtconsole(s)) { + if (vtnr <= 0 || vtnr > 63) + return -EINVAL; + } else { + if (vtnr > 0) + return -EINVAL; + } + } + if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) return -EINVAL; @@ -281,7 +334,8 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess if (r < 0) return -EINVAL; - if (!dbus_message_iter_next(&iter) || + if (strv_contains(controllers, "systemd") || + !dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) { r = -EINVAL; @@ -292,7 +346,8 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess if (r < 0) goto fail; - if (!dbus_message_iter_next(&iter) || + if (strv_contains(reset_controllers, "systemd") || + !dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) { r = -EINVAL; goto fail; @@ -318,6 +373,12 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess if (session) { + fifo_fd = session_create_fifo(session); + if (fifo_fd < 0) { + r = fifo_fd; + goto fail; + } + /* Session already exists, client is probably * something like "su" which changes uid but * is still the same audit session */ @@ -328,15 +389,6 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess goto fail; } - /* Create a throw-away fd */ - if (pipe(pipe_fds) < 0) { - r = -errno; - goto fail; - } - - close_nointr_nofail(pipe_fds[0]); - pipe_fds[0] = -1; - p = session_bus_path(session); if (!p) { r = -ENOMEM; @@ -348,7 +400,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess DBUS_TYPE_STRING, &session->id, DBUS_TYPE_OBJECT_PATH, &p, DBUS_TYPE_STRING, &session->user->runtime_path, - DBUS_TYPE_UNIX_FD, &pipe_fds[1], + DBUS_TYPE_UNIX_FD, &fifo_fd, DBUS_TYPE_INVALID); free(p); @@ -357,7 +409,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess goto fail; } - close_nointr_nofail(pipe_fds[1]); + close_nointr_nofail(fifo_fd); *_reply = reply; return 0; @@ -432,16 +484,12 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess } } - if (pipe(pipe_fds) < 0) { - r = -errno; + fifo_fd = session_create_fifo(session); + if (fifo_fd < 0) { + r = fifo_fd; goto fail; } - r = session_set_pipe_fd(session, pipe_fds[0]); - if (r < 0) - goto fail; - pipe_fds[0] = -1; - if (s) { r = seat_attach_session(s, session); if (r < 0) @@ -469,7 +517,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess DBUS_TYPE_STRING, &session->id, DBUS_TYPE_OBJECT_PATH, &p, DBUS_TYPE_STRING, &session->user->runtime_path, - DBUS_TYPE_UNIX_FD, &pipe_fds[1], + DBUS_TYPE_UNIX_FD, &fifo_fd, DBUS_TYPE_INVALID); free(p); @@ -478,7 +526,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess goto fail; } - close_nointr_nofail(pipe_fds[1]); + close_nointr_nofail(fifo_fd); *_reply = reply; return 0; @@ -493,7 +541,8 @@ fail: if (user) user_add_to_gc_queue(user); - close_pipe(pipe_fds); + if (fifo_fd >= 0) + close_nointr_nofail(fifo_fd); if (reply) dbus_message_unref(reply); @@ -501,6 +550,143 @@ fail: return r; } +static int trigger_device(Manager *m, struct udev_device *d) { + struct udev_enumerate *e; + struct udev_list_entry *first, *item; + int r; + + assert(m); + + e = udev_enumerate_new(m->udev); + if (!e) { + r = -ENOMEM; + 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; + } + + first = udev_enumerate_get_list_entry(e); + udev_list_entry_foreach(item, first) { + char *t; + const char *p; + + p = udev_list_entry_get_name(item); + + t = strappend(p, "/uevent"); + if (!t) { + r = -ENOMEM; + goto finish; + } + + write_one_line_file(t, "change"); + free(t); + } + + r = 0; + +finish: + if (e) + udev_enumerate_unref(e); + + return r; +} + +static int attach_device(Manager *m, const char *seat, const char *sysfs) { + struct udev_device *d; + char *rule = NULL, *file = NULL; + const char *id_for_seat; + int r; + + assert(m); + assert(seat); + assert(sysfs); + + d = udev_device_new_from_syspath(m->udev, sysfs); + if (!d) + return -ENODEV; + + if (!udev_device_has_tag(d, "seat")) { + r = -ENODEV; + goto finish; + } + + id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT"); + if (!id_for_seat) { + r = -ENODEV; + goto finish; + } + + if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) { + r = -ENOMEM; + goto finish; + } + + if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) { + r = -ENOMEM; + goto finish; + } + + mkdir_p("/etc/udev/rules.d", 0755); + r = write_one_line_file_atomic(file, rule); + if (r < 0) + goto finish; + + r = trigger_device(m, d); + +finish: + free(rule); + free(file); + + if (d) + udev_device_unref(d); + + return r; +} + +static int flush_devices(Manager *m) { + DIR *d; + + assert(m); + + d = opendir("/etc/udev/rules.d"); + if (!d) { + if (errno != ENOENT) + log_warning("Failed to open /etc/udev/rules.d: %m"); + } else { + struct dirent *de; + + while ((de = readdir(d))) { + + if (!dirent_is_file(de)) + continue; + + if (!startswith(de->d_name, "72-seat-")) + continue; + + if (!endswith(de->d_name, ".rules")) + continue; + + if (unlinkat(dirfd(d), de->d_name, 0) < 0) + log_warning("Failed to unlink %s: %m", de->d_name); + } + + closedir(d); + } + + return trigger_device(m, NULL); +} + static DBusHandlerResult manager_message_handler( DBusConnection *connection, DBusMessage *message, @@ -511,6 +697,7 @@ static DBusHandlerResult manager_message_handler( const BusProperty properties[] = { { "org.freedesktop.login1.Manager", "ControlGroupHierarchy", bus_property_append_string, "s", m->cgroup_path }, { "org.freedesktop.login1.Manager", "Controllers", bus_property_append_strv, "as", m->controllers }, + { "org.freedesktop.login1.Manager", "ResetControllers", bus_property_append_strv, "as", m->reset_controllers }, { "org.freedesktop.login1.Manager", "NAutoVTs", bus_property_append_unsigned, "u", &m->n_autovts }, { "org.freedesktop.login1.Manager", "KillOnlyUsers", bus_property_append_strv, "as", m->kill_only_users }, { "org.freedesktop.login1.Manager", "KillExcludeUsers", bus_property_append_strv, "as", m->kill_exclude_users }, @@ -796,6 +983,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; @@ -865,6 +1142,119 @@ static DBusHandlerResult manager_message_handler( if (!reply) goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) { + uint32_t uid; + struct passwd *pw; + dbus_bool_t b, interactive; + char *path; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_UINT32, &uid, + DBUS_TYPE_BOOLEAN, &b, + DBUS_TYPE_BOOLEAN, &interactive, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + errno = 0; + pw = getpwuid(uid); + if (!pw) + return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL); + + r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + r = safe_mkdir("/var/lib/systemd/linger", 0755, 0, 0); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + path = strappend("/var/lib/systemd/linger/", pw->pw_name); + if (!path) + goto oom; + + if (b) { + User *u; + + r = touch(path); + free(path); + + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + if (manager_add_user_by_uid(m, uid, &u) >= 0) + user_start(u); + + } else { + User *u; + + r = unlink(path); + free(path); + + if (r < 0 && errno != ENOENT) + return bus_send_error_reply(connection, message, &error, -errno); + + u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid)); + if (u) + user_add_to_gc_queue(u); + } + + reply = dbus_message_new_method_return(message); + if (!reply) + goto oom; + + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) { + const char *sysfs, *seat; + dbus_bool_t interactive; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_STRING, &seat, + DBUS_TYPE_STRING, &sysfs, + DBUS_TYPE_BOOLEAN, &interactive, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat)) + return bus_send_error_reply(connection, message, NULL, -EINVAL); + + r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + r = attach_device(m, seat, sysfs); + if (r < 0) + return bus_send_error_reply(connection, message, NULL, -EINVAL); + + reply = dbus_message_new_method_return(message); + if (!reply) + goto oom; + + + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) { + dbus_bool_t interactive; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_BOOLEAN, &interactive, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + r = flush_devices(m); + if (r < 0) + return bus_send_error_reply(connection, message, NULL, -EINVAL); + + 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;