chiark / gitweb /
logind: check whether newly created session is active
[elogind.git] / src / logind-dbus.c
index 693906ef70e05cbd8d0a8b2b6ab7aa2c4b1451d3..050eb7160edde03b4a7b075208b2c53c5357ab57 100644 (file)
         "  <method name=\"CreateSession\">\n"                           \
         "   <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n"          \
         "   <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n"       \
-        "   <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n"       \
         "   <arg name=\"type\" type=\"s\" direction=\"in\"/>\n"         \
         "   <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n"         \
         "   <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n"          \
         "   <arg name=\"display\" type=\"s\" direction=\"in\"/>\n"      \
         "   <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n"       \
@@ -176,8 +177,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 +228,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 +241,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) && 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 +329,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 +460,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) {
@@ -589,7 +669,7 @@ static DBusHandlerResult manager_message_handler(
 
                 dbus_message_iter_init_append(reply, &iter);
 
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "susso", &sub))
+                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
                         goto oom;
 
                 HASHMAP_FOREACH(session, m->sessions, i) {
@@ -635,7 +715,7 @@ static DBusHandlerResult manager_message_handler(
 
                 dbus_message_iter_init_append(reply, &iter);
 
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "uso", &sub))
+                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
                         goto oom;
 
                 HASHMAP_FOREACH(user, m->users, i) {
@@ -679,7 +759,7 @@ static DBusHandlerResult manager_message_handler(
 
                 dbus_message_iter_init_append(reply, &iter);
 
-                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "so", &sub))
+                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
                         goto oom;
 
                 HASHMAP_FOREACH(seat, m->seats, i) {
@@ -896,6 +976,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;