chiark / gitweb /
logind: check whether newly created session is active
[elogind.git] / src / logind-dbus.c
index 2bad549fc528a60e49eda77ec1027cfda8d4e32e..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"       \
@@ -177,7 +178,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 +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;
@@ -314,9 +337,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 +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) {