X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flogind-dbus.c;h=af5176ca32bb6a1953be6fe2641ea9f18d96d6d0;hb=bbd4388153bde7b7fdb39ce5c88dd92f7b8a4d2d;hp=2bad549fc528a60e49eda77ec1027cfda8d4e32e;hpb=0771475394887e3635e67196fa6f56486fa2126c;p=elogind.git diff --git a/src/logind-dbus.c b/src/logind-dbus.c index 2bad549fc..af5176ca3 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,11 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -177,7 +185,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess DBusMessageIter iter; int r; char *id = NULL, *p; - int vtnr = -1; + uint32_t vtnr = 0; int pipe_fds[2] = { -1, -1 }; DBusMessage *reply = NULL; bool b; @@ -227,6 +235,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 +248,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; @@ -314,9 +344,53 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess 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 { @@ -393,7 +467,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) { @@ -819,6 +895,69 @@ 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.DBus.Introspectable", "Introspect")) { char *introspection = NULL; FILE *f;