]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blobdiff - src/session.c
Don't reconnect a display server if already connected to it
[sojka/lightdm.git] / src / session.c
index 3b360d287e95a8ac1826d845ad692fb6c755693a..e2967b43a0da1b5a4373fc3ecbf0a4f18be16a85 100644 (file)
@@ -26,6 +26,7 @@
 #include "console-kit.h"
 #include "login1.h"
 #include "guest-account.h"
+#include "shared-data-manager.h"
 
 enum {
     GOT_MESSAGES,
@@ -37,8 +38,8 @@ static guint signals[LAST_SIGNAL] = { 0 };
 
 struct SessionPrivate
 {
-    /* Session type */
-    gchar *session_type;
+    /* Configuration for this session */
+    SessionConfig *config;
 
     /* Display server running on */
     DisplayServer *display_server;
@@ -83,9 +84,7 @@ struct SessionPrivate
 
     /* File to log to */
     gchar *log_filename;
-
-    /* Seat class */
-    gchar *class;
+    LogMode log_mode;
 
     /* tty this session is running on */
     gchar *tty;
@@ -101,8 +100,8 @@ struct SessionPrivate
     /* Console kit cookie */
     gchar *console_kit_cookie;
 
-    /* login1 session */
-    gchar *login1_session;
+    /* login1 session ID */
+    gchar *login1_session_id;
 
     /* Environment to set in child */
     GList *env;
@@ -120,7 +119,11 @@ struct SessionPrivate
 /* Maximum length of a string to pass between daemon and session */
 #define MAX_STRING_LENGTH 65535
 
-G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
+static void session_logger_iface_init (LoggerInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (Session, session, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (
+                             LOGGER_TYPE, session_logger_iface_init));
 
 Session *
 session_new (void)
@@ -129,18 +132,26 @@ session_new (void)
 }
 
 void
-session_set_session_type (Session *session, const gchar *session_type)
+session_set_config (Session *session, SessionConfig *config)
 {
     g_return_if_fail (session != NULL);
-    g_free (session->priv->session_type);
-    session->priv->session_type = g_strdup (session_type);
+
+    g_clear_object (&session->priv->config);
+    session->priv->config = g_object_ref (config);
+}
+
+SessionConfig *
+session_get_config (Session *session)
+{
+    g_return_val_if_fail (session != NULL, NULL);
+    return session->priv->config;
 }
 
 const gchar *
 session_get_session_type (Session *session)
 {
     g_return_val_if_fail (session != NULL, NULL);
-    return session->priv->session_type;
+    return session_config_get_session_type (session_get_config (session));
 }
 
 void
@@ -188,19 +199,12 @@ session_get_is_guest (Session *session)
 }
 
 void
-session_set_log_file (Session *session, const gchar *filename)
+session_set_log_file (Session *session, const gchar *filename, LogMode log_mode)
 {
     g_return_if_fail (session != NULL);
     g_free (session->priv->log_filename);
     session->priv->log_filename = g_strdup (filename);
-}
-
-void
-session_set_class (Session *session, const gchar *class)
-{
-    g_return_if_fail (session != NULL);
-    g_free (session->priv->class);
-    session->priv->class = g_strdup (class);
+    session->priv->log_mode = log_mode;
 }
 
 void
@@ -208,6 +212,10 @@ session_set_display_server (Session *session, DisplayServer *display_server)
 {
     g_return_if_fail (session != NULL);
     g_return_if_fail (display_server != NULL);
+
+    if (session->priv->display_server == display_server)
+        return;
+
     if (session->priv->display_server)
     {
         display_server_disconnect_session (session->priv->display_server, session);
@@ -243,11 +251,7 @@ void
 session_set_x_authority (Session *session, XAuthority *authority, gboolean use_system_location)
 {
     g_return_if_fail (session != NULL);
-    if (session->priv->x_authority)
-    {
-        g_object_unref (session->priv->x_authority);
-        session->priv->x_authority = NULL;
-    }
+    g_clear_object (&session->priv->x_authority);
     if (authority)
         session->priv->x_authority = g_object_ref (authority);
     session->priv->x_authority_use_system_location = use_system_location;
@@ -298,19 +302,34 @@ session_set_env (Session *session, const gchar *name, const gchar *value)
         session->priv->env = g_list_append (session->priv->env, entry);
 }
 
+const gchar *
+session_get_env (Session *session, const gchar *name)
+{
+    GList *link;
+    gchar *entry;
+
+    link = find_env_entry (session, name);
+    if (!link)
+        return NULL;
+
+    entry = link->data;
+
+    return entry + strlen (name) + 1;
+}
+
 void
 session_unset_env (Session *session, const gchar *name)
 {
     GList *link;
 
     g_return_if_fail (session != NULL);
-  
+
     link = find_env_entry (session, name);
     if (!link)
         return;
 
     g_free (link->data);
-    session->priv->env = g_list_remove_link (session->priv->env, link);
+    session->priv->env = g_list_delete_link (session->priv->env, link);
 }
 
 void
@@ -338,7 +357,7 @@ static void
 write_data (Session *session, const void *buf, size_t count)
 {
     if (write (session->priv->to_child_input, buf, count) != count)
-        g_warning ("Error writing to session: %s", strerror (errno));
+        l_warning (session, "Error writing to session: %s", strerror (errno));
 }
 
 static void
@@ -382,7 +401,7 @@ read_from_child (Session *session, void *buf, size_t count)
     ssize_t n_read;
     n_read = read (session->priv->from_child_output, buf, count);
     if (n_read < 0)
-        g_warning ("Error reading from session: %s", strerror (errno));
+        l_warning (session, "Error reading from session: %s", strerror (errno));
     return n_read;
 }
 
@@ -398,7 +417,7 @@ read_string_from_child (Session *session)
         return NULL;
     if (length > MAX_STRING_LENGTH)
     {
-        g_warning ("Invalid string length %d from child", length);
+        l_warning (session, "Invalid string length %d from child", length);
         return NULL;
     }
 
@@ -414,17 +433,20 @@ session_watch_cb (GPid pid, gint status, gpointer data)
 {
     Session *session = data;
 
-    session->priv->pid = 0;
+    session->priv->child_watch = 0;
 
     if (WIFEXITED (status))
-        g_debug ("Session %d exited with return value %d", pid, WEXITSTATUS (status));
+        l_debug (session, "Exited with return value %d", WEXITSTATUS (status));
     else if (WIFSIGNALED (status))
-        g_debug ("Session %d terminated with signal %d", pid, WTERMSIG (status));
+        l_debug (session, "Terminated with signal %d", WTERMSIG (status));
+
+    /* do this as late as possible for log messages prefix */
+    session->priv->pid = 0;
 
     /* If failed during authentication then report this as an authentication failure */
     if (session->priv->authentication_started && !session->priv->authentication_complete)
     {
-        g_debug ("Session %d failed during authentication", pid);
+        l_debug (session, "Failed during authentication");
         session->priv->authentication_complete = TRUE;
         session->priv->authentication_result = PAM_CONV_ERR;
         g_free (session->priv->authentication_result_string);
@@ -463,9 +485,7 @@ from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
     {
         g_free (session->priv->username);
         session->priv->username = username;
-        if (session->priv->user)
-            g_object_unref (session->priv->user);
-        session->priv->user = NULL;
+        g_clear_object (&session->priv->user);
     }
     else
         g_free (username);
@@ -473,7 +493,7 @@ from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
     /* Check if authentication completed */
     n_read = read_from_child (session, &auth_complete, sizeof (auth_complete));
     if (n_read < 0)
-        g_debug ("Error reading from child: %s", strerror (errno));
+        l_debug (session, "Error reading from child: %s", strerror (errno));
     if (n_read <= 0)
     {
         session->priv->from_child_watch = 0;
@@ -487,7 +507,7 @@ from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
         g_free (session->priv->authentication_result_string);
         session->priv->authentication_result_string = read_string_from_child (session);
 
-        g_debug ("Session %d authentication complete with return value %d: %s", session->priv->pid, session->priv->authentication_result, session->priv->authentication_result_string);
+        l_debug (session, "Authentication complete with return value %d: %s", session->priv->authentication_result, session->priv->authentication_result_string);
 
         /* No longer expect any more messages */
         session->priv->from_child_watch = 0;
@@ -510,7 +530,7 @@ from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
             m->msg = read_string_from_child (session);
         }
 
-        g_debug ("Session %d got %d message(s) from PAM", session->priv->pid, session->priv->messages_length);
+        l_debug (session, "Got %d message(s) from PAM", session->priv->messages_length);
 
         g_signal_emit (G_OBJECT (session), signals[GOT_MESSAGES], 0);
     }
@@ -522,7 +542,6 @@ gboolean
 session_start (Session *session)
 {
     g_return_val_if_fail (session != NULL, FALSE);
-    g_return_val_if_fail (session->priv->display_server != NULL, FALSE);
     return SESSION_GET_CLASS (session)->start (session);
 }
 
@@ -538,10 +557,12 @@ session_real_start (Session *session)
     int version;
     int to_child_pipe[2], from_child_pipe[2];
     int to_child_output, from_child_input;
+    gchar *arg0, *arg1;
 
     g_return_val_if_fail (session->priv->pid == 0, FALSE);
 
-    display_server_connect_session (session->priv->display_server, session);
+    if (session->priv->display_server)
+        display_server_connect_session (session->priv->display_server, session);
 
     /* Create pipes to talk to the child */
     if (pipe (to_child_pipe) < 0 || pipe (from_child_pipe) < 0)
@@ -569,24 +590,26 @@ session_real_start (Session *session)
     }
 
     /* Run the child */
+    arg0 = g_strdup_printf ("%d", to_child_output);
+    arg1 = g_strdup_printf ("%d", from_child_input);
     session->priv->pid = fork ();
-    if (session->priv->pid < 0)
-    {
-        g_debug ("Failed to fork session child process: %s", strerror (errno));
-        return FALSE;
-    }
-
     if (session->priv->pid == 0)
     {
         /* Run us again in session child mode */
         execlp ("lightdm",
                 "lightdm",
                 "--session-child",
-                g_strdup_printf ("%d", to_child_output),
-                g_strdup_printf ("%d", from_child_input),
-                NULL);
+                arg0, arg1, NULL);
         _exit (EXIT_FAILURE);
     }
+    g_free (arg0);
+    g_free (arg1);
+
+    if (session->priv->pid < 0)
+    {
+        g_debug ("Failed to fork session child process: %s", strerror (errno));
+        return FALSE;
+    }
 
     /* Hold a reference on this object until the child process terminates so we
      * can handle the watch callback even if it is no longer used. Otherwise a
@@ -602,7 +625,7 @@ session_real_start (Session *session)
     close (from_child_input);
 
     /* Indicate what version of the protocol we are using */
-    version = 1;
+    version = 3;
     write_data (session, &version, sizeof (version));
 
     /* Send configuration */
@@ -610,13 +633,13 @@ session_real_start (Session *session)
     write_string (session, session->priv->username);
     write_data (session, &session->priv->do_authenticate, sizeof (session->priv->do_authenticate));
     write_data (session, &session->priv->is_interactive, sizeof (session->priv->is_interactive));
-    write_string (session, session->priv->class);
+    write_string (session, NULL); /* Used to be class, now we just use the environment variable */
     write_string (session, session->priv->tty);
     write_string (session, session->priv->remote_host_name);
     write_string (session, session->priv->xdisplay);
     write_xauth (session, session->priv->x_authority);
 
-    g_debug ("Started session %d with service '%s', username '%s'", session->priv->pid, session->priv->pam_service, session->priv->username);
+    l_debug (session, "Started with service '%s', username '%s'", session->priv->pam_service, session->priv->username);
 
     return TRUE;
 }
@@ -628,6 +651,13 @@ session_get_username (Session *session)
     return session->priv->username;
 }
 
+const gchar *
+session_get_login1_session_id (Session *session)
+{
+    g_return_val_if_fail (session != NULL, NULL);
+    return session->priv->login1_session_id;
+}
+
 const gchar *
 session_get_console_kit_cookie (Session *session)
 {
@@ -727,7 +757,7 @@ session_real_run (Session *session)
     session->priv->command_run = TRUE;
 
     command = g_strjoinv (" ", session->priv->argv);
-    g_debug ("Session %d running command %s", session->priv->pid, command);
+    l_debug (session, "Running command %s", command);
     g_free (command);
 
     /* Create authority location */
@@ -740,11 +770,11 @@ session_real_run (Session *session)
         g_free (run_dir);
 
         if (g_mkdir_with_parents (dir, S_IRWXU) < 0)
-            g_warning ("Failed to set create system authority dir %s: %s", dir, strerror (errno));          
+            l_warning (session, "Failed to set create system authority dir %s: %s", dir, strerror (errno));
         if (getuid () == 0)
         {
             if (chown (dir, user_get_uid (session_get_user (session)), user_get_gid (session_get_user (session))) < 0)
-                g_warning ("Failed to set ownership of user authority dir: %s", strerror (errno));
+                l_warning (session, "Failed to set ownership of user authority dir: %s", strerror (errno));
         }
 
         x_authority_filename = g_build_filename (dir, "xauthority", NULL);
@@ -753,7 +783,21 @@ session_real_run (Session *session)
     else
         x_authority_filename = g_build_filename (user_get_home_directory (session_get_user (session)), ".Xauthority", NULL);
 
+    /* Make sure shared user directory for this user exists */
+    if (!session->priv->remote_host_name)
+    {
+        gchar *data_dir = shared_data_manager_ensure_user_dir (shared_data_manager_get_instance (), session->priv->username);
+        if (data_dir)
+        {
+            session_set_env (session, "XDG_GREETER_DATA_DIR", data_dir);
+            g_free (data_dir);
+        }
+    }
+
+    if (session->priv->log_filename)
+        l_debug (session, "Logging to %s", session->priv->log_filename);
     write_string (session, session->priv->log_filename);
+    write_data (session, &session->priv->log_mode, sizeof (session->priv->log_mode));
     write_string (session, session->priv->tty);
     write_string (session, x_authority_filename);
     g_free (x_authority_filename);
@@ -768,10 +812,8 @@ session_real_run (Session *session)
     for (i = 0; i < argc; i++)
         write_string (session, session->priv->argv[i]);
 
-    if (login1_is_running ())
-        session->priv->login1_session = read_string_from_child (session);
-    if (!session->priv->login1_session)
-        session->priv->console_kit_cookie = read_string_from_child (session);
+    session->priv->login1_session_id = read_string_from_child (session);
+    session->priv->console_kit_cookie = read_string_from_child (session);
 }
 
 void
@@ -780,9 +822,9 @@ session_lock (Session *session)
     g_return_if_fail (session != NULL);
     if (getuid () == 0)
     {
-        if (login1_is_running ())
-            login1_lock_session (session->priv->login1_session);
-        if (!session->priv->login1_session)
+        if (session->priv->login1_session_id)
+            login1_service_lock_session (login1_service_get_instance (), session->priv->login1_session_id);
+        else if (session->priv->console_kit_cookie)
             ck_lock_session (session->priv->console_kit_cookie);
     }
 }
@@ -793,18 +835,49 @@ session_unlock (Session *session)
     g_return_if_fail (session != NULL);
     if (getuid () == 0)
     {
-        if (login1_is_running ())
-            login1_unlock_session (session->priv->login1_session);
-        if (!session->priv->login1_session)
+        if (session->priv->login1_session_id)
+            login1_service_unlock_session (login1_service_get_instance (), session->priv->login1_session_id);
+        else if (session->priv->console_kit_cookie)
             ck_unlock_session (session->priv->console_kit_cookie);
     }
 }
 
+void
+session_activate (Session *session)
+{
+    g_return_if_fail (session != NULL);
+    if (getuid () == 0)
+    {
+        if (session->priv->login1_session_id)
+            login1_service_activate_session (login1_service_get_instance (), session->priv->login1_session_id);
+        else if (session->priv->console_kit_cookie)
+            ck_activate_session (session->priv->console_kit_cookie);
+    }
+}
+
 void
 session_stop (Session *session)
 {
     g_return_if_fail (session != NULL);
 
+    /* If can cleanly stop then do that */
+    if (session_get_is_authenticated (session) && !session->priv->command_run)
+    {
+        gsize n = 0;
+        LogMode log_mode = LOG_MODE_INVALID;
+
+        session->priv->command_run = TRUE;
+        write_string (session, NULL); // log filename
+        write_data (session, &log_mode, sizeof (log_mode)); // log mode
+        write_string (session, NULL); // tty
+        write_string (session, NULL); // xauth filename
+        write_string (session, NULL); // xdisplay
+        write_xauth (session, NULL); // xauth
+        write_data (session, &n, sizeof (n)); // environment
+        write_data (session, &n, sizeof (n)); // command
+        return;
+    }
+
     if (session->priv->stopping)
         return;
     session->priv->stopping = TRUE;
@@ -819,7 +892,7 @@ session_real_stop (Session *session)
 
     if (session->priv->pid > 0)
     {
-        g_debug ("Session %d: Sending SIGTERM", session->priv->pid);
+        l_debug (session, "Sending SIGTERM");
         kill (session->priv->pid, SIGTERM);
         // FIXME: Handle timeout
     }
@@ -839,6 +912,9 @@ session_init (Session *session)
 {
     session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, SESSION_TYPE, SessionPrivate);
     session->priv->log_filename = g_strdup (".xsession-errors");
+    session->priv->log_mode = LOG_MODE_BACKUP_AND_TRUNCATE;
+    session->priv->to_child_input = -1;
+    session->priv->from_child_output = -1;
 }
 
 static void
@@ -847,11 +923,12 @@ session_finalize (GObject *object)
     Session *self = SESSION (object);
     int i;
 
-    g_free (self->priv->session_type);
-    if (self->priv->display_server)
-        g_object_unref (self->priv->display_server);
+    g_clear_object (&self->priv->config);
+    g_clear_object (&self->priv->display_server);
     if (self->priv->pid)
         kill (self->priv->pid, SIGKILL);
+    close (self->priv->to_child_input);
+    close (self->priv->from_child_output);
     if (self->priv->from_child_channel)
         g_io_channel_unref (self->priv->from_child_channel);
     if (self->priv->from_child_watch)
@@ -859,21 +936,18 @@ session_finalize (GObject *object)
     if (self->priv->child_watch)
         g_source_remove (self->priv->child_watch);
     g_free (self->priv->username);
-    if (self->priv->user)
-        g_object_unref (self->priv->user);
+    g_clear_object (&self->priv->user);
     g_free (self->priv->pam_service);
     for (i = 0; i < self->priv->messages_length; i++)
         g_free ((char *) self->priv->messages[i].msg);
     g_free (self->priv->messages);
     g_free (self->priv->authentication_result_string);
     g_free (self->priv->log_filename);
-    g_free (self->priv->class);
     g_free (self->priv->tty);
     g_free (self->priv->xdisplay);
-    if (self->priv->x_authority)
-        g_object_unref (self->priv->x_authority);
+    g_clear_object (&self->priv->x_authority);
     g_free (self->priv->remote_host_name);
-    g_free (self->priv->login1_session);
+    g_free (self->priv->login1_session_id);
     g_free (self->priv->console_kit_cookie);
     g_list_free_full (self->priv->env, g_free);
     g_strfreev (self->priv->argv);
@@ -894,7 +968,7 @@ session_class_init (SessionClass *klass)
     g_type_class_add_private (klass, sizeof (SessionPrivate));
 
     signals[GOT_MESSAGES] =
-        g_signal_new ("got-messages",
+        g_signal_new (SESSION_SIGNAL_GOT_MESSAGES,
                       G_TYPE_FROM_CLASS (klass),
                       G_SIGNAL_RUN_LAST,
                       G_STRUCT_OFFSET (SessionClass, got_messages),
@@ -903,7 +977,7 @@ session_class_init (SessionClass *klass)
                       G_TYPE_NONE, 0);
 
     signals[AUTHENTICATION_COMPLETE] =
-        g_signal_new ("authentication-complete",
+        g_signal_new (SESSION_SIGNAL_AUTHENTICATION_COMPLETE,
                       G_TYPE_FROM_CLASS (klass),
                       G_SIGNAL_RUN_LAST,
                       G_STRUCT_OFFSET (SessionClass, authentication_complete),
@@ -912,7 +986,7 @@ session_class_init (SessionClass *klass)
                       G_TYPE_NONE, 0);
 
     signals[STOPPED] =
-        g_signal_new ("stopped",
+        g_signal_new (SESSION_SIGNAL_STOPPED,
                       G_TYPE_FROM_CLASS (klass),
                       G_SIGNAL_RUN_LAST,
                       G_STRUCT_OFFSET (SessionClass, stopped),
@@ -920,3 +994,19 @@ session_class_init (SessionClass *klass)
                       NULL,
                       G_TYPE_NONE, 0);
 }
+
+static gint
+session_real_logprefix (Logger *self, gchar *buf, gulong buflen)
+{
+    Session *session = SESSION (self);
+    if (session->priv->pid != 0)
+        return g_snprintf (buf, buflen, "Session pid=%d: ", session->priv->pid);
+    else
+        return g_snprintf (buf, buflen, "Session: ");
+}
+
+static void
+session_logger_iface_init (LoggerInterface *iface)
+{
+    iface->logprefix = &session_real_logprefix;
+}