chiark / gitweb /
pam: set XDG_SEAT and XDG_VTNR when logging in
[elogind.git] / src / logind-user-dbus.c
index 7c8bb27c6d3ee44fd20af2a77d812814b7045d6e..3673a28bd4ceb6c7eeb64427b731536d8f32422b 100644 (file)
@@ -20,6 +20,7 @@
 ***/
 
 #include <errno.h>
+#include <string.h>
 
 #include "logind.h"
 #include "logind-user.h"
 #define BUS_USER_INTERFACE \
         " <interface name=\"org.freedesktop.login1.User\">\n"           \
         "  <method name=\"Terminate\"/>\n"                              \
+        "  <method name=\"Kill\">\n"                                    \
+        "   <arg name=\"signal\" type=\"s\"/>\n"                        \
+        "  </method>\n"                                                 \
         "  <property name=\"UID\" type=\"u\" access=\"read\"/>\n"       \
         "  <property name=\"GID\" type=\"u\" access=\"read\"/>\n"       \
         "  <property name=\"Name\" type=\"s\" access=\"read\"/>\n"      \
+        "  <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
         "  <property name=\"RuntimePath\" type=\"s\" access=\"read\"/>\n" \
-        "  <property name=\"Service\" type=\"s\" access=\"read\"/>\n"   \
         "  <property name=\"ControlGroupPath\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"Service\" type=\"s\" access=\"read\"/>\n"   \
         "  <property name=\"Display\" type=\"(so)\" access=\"read\"/>\n" \
         "  <property name=\"State\" type=\"s\" access=\"read\"/>\n"     \
         "  <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
+        "  <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n"  \
+        "  <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
+        "  <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
         " </interface>\n"                                               \
 
 #define INTROSPECTION                                                   \
@@ -115,7 +124,7 @@ static int bus_user_append_sessions(DBusMessageIter *i, const char *property, vo
         assert(property);
         assert(u);
 
-        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "so", &sub))
+        if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(so)", &sub))
                 return -ENOMEM;
 
         LIST_FOREACH(sessions_by_user, session, u->sessions) {
@@ -146,6 +155,40 @@ static int bus_user_append_sessions(DBusMessageIter *i, const char *property, vo
         return 0;
 }
 
+static int bus_user_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
+        User *u = data;
+        dbus_bool_t b;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        b = user_get_idle_hint(u, NULL) > 0;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int bus_user_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
+        User *u = data;
+        dual_timestamp t;
+        uint64_t k;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        user_get_idle_hint(u, &t);
+        k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k))
+                return -ENOMEM;
+
+        return 0;
+}
+
 static int get_user_for_path(Manager *m, const char *path, User **_u) {
         User *u;
         unsigned long lu;
@@ -176,23 +219,80 @@ static DBusHandlerResult user_message_dispatch(
                 DBusMessage *message) {
 
         const BusProperty properties[] = {
-                { "org.freedesktop.login1.User", "UID",              bus_property_append_uid,    "u",     &u->uid         },
-                { "org.freedesktop.login1.User", "GID",              bus_property_append_gid,    "u",     &u->gid         },
-                { "org.freedesktop.login1.User", "Name",             bus_property_append_string, "s",     u->name         },
-                { "org.freedesktop.login1.User", "RuntimePath",      bus_property_append_string, "s",     u->runtime_path },
-                { "org.freedesktop.login1.User", "ControlGroupPath", bus_property_append_string, "s",     u->cgroup_path  },
-                { "org.freedesktop.login1.User", "Service",          bus_property_append_string, "s",     u->service      },
-                { "org.freedesktop.login1.User", "Display",          bus_user_append_display,    "(so)",  u               },
-                { "org.freedesktop.login1.User", "State",            bus_user_append_state,      "s",     u               },
-                { "org.freedesktop.login1.User", "Sessions",         bus_user_append_sessions,   "a(so)", u               },
+                { "org.freedesktop.login1.User", "UID",                bus_property_append_uid,    "u",     &u->uid                 },
+                { "org.freedesktop.login1.User", "GID",                bus_property_append_gid,    "u",     &u->gid                 },
+                { "org.freedesktop.login1.User", "Name",               bus_property_append_string, "s",     u->name                 },
+                { "org.freedesktop.login1.User", "Timestamp",          bus_property_append_usec,   "t",     &u->timestamp.realtime  },
+                { "org.freedesktop.login1.User", "TimestampMonotonic", bus_property_append_usec,   "t",     &u->timestamp.monotonic },
+                { "org.freedesktop.login1.User", "RuntimePath",        bus_property_append_string, "s",     u->runtime_path         },
+                { "org.freedesktop.login1.User", "ControlGroupPath",   bus_property_append_string, "s",     u->cgroup_path          },
+                { "org.freedesktop.login1.User", "Service",            bus_property_append_string, "s",     u->service              },
+                { "org.freedesktop.login1.User", "Display",            bus_user_append_display,    "(so)",  u                       },
+                { "org.freedesktop.login1.User", "State",              bus_user_append_state,      "s",     u                       },
+                { "org.freedesktop.login1.User", "Sessions",           bus_user_append_sessions,   "a(so)", u                       },
+                { "org.freedesktop.login1.User", "IdleHint",           bus_user_append_idle_hint,  "b",     u                       },
+                { "org.freedesktop.login1.User", "IdleSinceHint",          bus_user_append_idle_hint_since, "t", u                  },
+                { "org.freedesktop.login1.User", "IdleSinceHintMonotonic", bus_user_append_idle_hint_since, "t", u                  },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 
+        DBusError error;
+        DBusMessage *reply = NULL;
+        int r;
+
         assert(u);
         assert(connection);
         assert(message);
 
-        return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+        if (dbus_message_is_method_call(message, "org.freedesktop.login1.User", "Terminate")) {
+
+                r = user_stop(u);
+                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.User", "Kill")) {
+                int32_t signo;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    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);
+
+                r = user_kill(u, 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
+                return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+
+        if (reply) {
+                if (!dbus_connection_send(connection, reply, NULL))
+                        goto oom;
+
+                dbus_message_unref(reply);
+        }
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
 }
 
 static DBusHandlerResult user_message_handler(
@@ -238,3 +338,74 @@ char *user_bus_path(User *u) {
 
         return s;
 }
+
+int user_send_signal(User *u, bool new_user) {
+        DBusMessage *m;
+        int r = -ENOMEM;
+        char *p = NULL;
+        uint32_t uid;
+
+        assert(u);
+
+        m = dbus_message_new_signal("/org/freedesktop/login1",
+                                    "org.freedesktop.login1.Manager",
+                                    new_user ? "UserNew" : "UserRemoved");
+
+        if (!m)
+                return -ENOMEM;
+
+        p = user_bus_path(u);
+        if (!p)
+                goto finish;
+
+        uid = u->uid;
+
+        if (!dbus_message_append_args(
+                            m,
+                            DBUS_TYPE_UINT32, &uid,
+                            DBUS_TYPE_OBJECT_PATH, &p,
+                            DBUS_TYPE_INVALID))
+                goto finish;
+
+        if (!dbus_connection_send(u->manager->bus, m, NULL))
+                goto finish;
+
+        r = 0;
+
+finish:
+        dbus_message_unref(m);
+        free(p);
+
+        return r;
+}
+
+int user_send_changed(User *u, const char *properties) {
+        DBusMessage *m;
+        int r = -ENOMEM;
+        char *p = NULL;
+
+        assert(u);
+
+        if (!u->started)
+                return 0;
+
+        p = user_bus_path(u);
+        if (!p)
+                return -ENOMEM;
+
+        m = bus_properties_changed_new(p, "org.freedesktop.login1.User", properties);
+        if (!m)
+                goto finish;
+
+        if (!dbus_connection_send(u->manager->bus, m, NULL))
+                goto finish;
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+        free(p);
+
+        return r;
+}