X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flogind-dbus.c;h=57ee2ee28d9fb1fe1d2259286011854146952a6f;hb=88bb8d215aa0f5576eb3f9c77c30cdc4b17783fe;hp=2a85749478346a4f6c3514e8bbd46c683b042e05;hpb=dec15e9263cadae02f4f51463860248af40475d0;p=elogind.git diff --git a/src/logind-dbus.c b/src/logind-dbus.c index 2a8574947..57ee2ee28 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" \ @@ -81,6 +84,16 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -176,8 +189,8 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess Seat *s; DBusMessageIter iter; int r; - char *id, *p; - int vtnr = -1; + char *id = NULL, *p; + uint32_t vtnr = 0; int pipe_fds[2] = { -1, -1 }; DBusMessage *reply = NULL; bool b; @@ -227,6 +240,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 +253,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; @@ -306,19 +341,74 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess audit_session_from_pid(leader, &audit_id); - if (audit_id > 0) + if (audit_id > 0) { asprintf(&id, "%lu", (unsigned long) audit_id); - else - asprintf(&id, "c%lu", ++m->session_counter); - if (!id) { - r = -ENOMEM; - goto fail; - } + if (!id) { + r = -ENOMEM; + goto fail; + } - if (hashmap_get(m->sessions, id)) { - r = -EEXIST; - goto fail; + session = hashmap_get(m->sessions, id); + + if (session) { + + /* Session already exists, client is probably + * something like "su" which changes uid but + * is still the same audit session */ + + reply = dbus_message_new_method_return(message); + if (!reply) { + r = -ENOMEM; + 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; + goto fail; + } + + b = dbus_message_append_args( + reply, + 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_INVALID); + free(p); + + if (!b) { + r = -ENOMEM; + goto fail; + } + + close_nointr_nofail(pipe_fds[1]); + *_reply = reply; + + return 0; + } + + } else { + do { + free(id); + asprintf(&id, "c%lu", ++m->session_counter); + + if (!id) { + r = -ENOMEM; + goto fail; + } + + } while (hashmap_get(m->sessions, id)); } r = manager_add_session(m, user, id, &session); @@ -382,7 +472,9 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess goto fail; } - session->pipe_fd = pipe_fds[0]; + r = session_set_pipe_fd(session, pipe_fds[0]); + if (r < 0) + goto fail; pipe_fds[0] = -1; if (s) { @@ -444,6 +536,70 @@ 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 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 (!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(file, rule); + +finish: + free(rule); + free(file); + + if (d) + udev_device_unref(d); + + return r; +} + static DBusHandlerResult manager_message_handler( DBusConnection *connection, DBusMessage *message, @@ -808,6 +964,96 @@ 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.DBus.Introspectable", "Introspect")) { char *introspection = NULL; FILE *f; @@ -896,6 +1142,36 @@ const DBusObjectPathVTable bus_manager_vtable = { .message_function = manager_message_handler }; +DBusHandlerResult bus_message_filter( + DBusConnection *connection, + DBusMessage *message, + void *userdata) { + + Manager *m = userdata; + DBusError error; + + assert(m); + assert(connection); + assert(message); + + dbus_error_init(&error); + + if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) { + const char *cgroup; + + if (!dbus_message_get_args(message, &error, + DBUS_TYPE_STRING, &cgroup, + DBUS_TYPE_INVALID)) + log_error("Failed to parse Released message: %s", bus_error_message(&error)); + else + manager_cgroup_notify_empty(m, cgroup); + } + + dbus_error_free(&error); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + int manager_send_changed(Manager *manager, const char *properties) { DBusMessage *m; int r = -ENOMEM;