]> rtime.felk.cvut.cz Git - sojka/lightdm.git/commitdiff
Move greeter code into greeter.c
authorunknown <robert.ancell@canonical.com>
Sun, 13 Mar 2011 06:35:28 +0000 (17:35 +1100)
committerunknown <robert.ancell@canonical.com>
Sun, 13 Mar 2011 06:35:28 +0000 (17:35 +1100)
src/Makefile.am
src/display.c
src/greeter.c [new file with mode: 0644]
src/greeter.h [new file with mode: 0644]
src/ldm-marshal.list
src/session.c
src/session.h

index 3103601cc6e0b3bc5662af31901b9364d6c57ef9..26a8817298373099219dea5ca16b8dbc389272c2 100644 (file)
@@ -13,6 +13,8 @@ lightdm_SOURCES = \
        display.h \
        display-manager.c \
        display-manager.h \
+       greeter.c \
+       greeter.h \
        lightdm.c \
        ldm-marshal.c \
        ldm-marshal.h \
index 458f7adc351b146a8d967200df0c05261d45f708..3b940a65d84e35fa92a37cb8a11f24e5563690fd 100644 (file)
 #include "pam-session.h"
 #include "theme.h"
 #include "ldm-marshal.h"
-#include "greeter-protocol.h"
+#include "greeter.h"
 
 /* Length of time in milliseconds to wait for a session to load */
 #define USER_SESSION_TIMEOUT 5000
 
-/* Length of time in milliseconds to wait for a greeter to quit */
-#define GREETER_QUIT_TIMEOUT 1000
-
 enum {
     START_GREETER,
     END_GREETER,
@@ -73,15 +70,8 @@ struct DisplayPrivate
     /* PAM service to authenticate against */
     gchar *pam_service;
 
-    /* Pipe to communicate to greeter */
-    int greeter_pipe[2];
-    gchar *read_buffer;
-    gsize n_read;
-
     /* Greeter session process */
-    Session *greeter_session;
-    gboolean greeter_connected;
-    guint greeter_quit_timeout;
+    Greeter *greeter_session;
     PAMSession *greeter_pam_session;
     gchar *greeter_ck_cookie;
 
@@ -556,7 +546,9 @@ start_user_session (Display *display, const gchar *session, const gchar *languag
                 session_command = g_strdup_printf ("%s '%s'", display->priv->session_wrapper, session_command);
                 g_free (old_command);
             }
-            display->priv->user_session = session_new (pam_session_get_username (display->priv->user_pam_session), session_command);
+            display->priv->user_session = session_new ();
+            session_set_username (display->priv->user_session, pam_session_get_username (display->priv->user_pam_session));
+            session_set_command (display->priv->user_session, session_command);
 
             g_signal_connect (G_OBJECT (display->priv->user_session), "exited", G_CALLBACK (user_session_exited_cb), display);
             g_signal_connect (G_OBJECT (display->priv->user_session), "terminated", G_CALLBACK (user_session_terminated_cb), display);
@@ -619,271 +611,21 @@ start_default_session (Display *display, const gchar *session, const gchar *lang
     start_user_session (display, session, language);
 }
 
-static void
-end_greeter_session (Display *display, gboolean clean_exit)
-{  
-    gboolean greeter_connected;
-  
-    if (display->priv->greeter_quit_timeout)
-    {
-        g_source_remove (display->priv->greeter_quit_timeout);
-        display->priv->greeter_quit_timeout = 0;
-    }
-
-    g_signal_emit (display, signals[END_GREETER], 0, display->priv->greeter_session);
-
-    greeter_connected = display->priv->greeter_connected;
-
-    g_object_unref (display->priv->greeter_session);
-    display->priv->greeter_session = NULL;
-    display->priv->greeter_connected = FALSE;
-
-    pam_session_end (display->priv->greeter_pam_session);
-    g_object_unref (display->priv->greeter_pam_session);
-    display->priv->greeter_pam_session = NULL;
-
-    end_ck_session (display->priv->greeter_ck_cookie);
-    g_free (display->priv->greeter_ck_cookie);
-    display->priv->greeter_ck_cookie = NULL;
-
-    if (!clean_exit)
-        g_warning ("Greeter failed");
-    else if (!greeter_connected)
-        g_warning ("Greeter quit before connecting");
-    else if (!display->priv->user_session)
-        g_warning ("Greeter quit before session started");
-    else
-        return;
-
-    // FIXME: Issue with greeter, don't want to start a new one, report error to user
-}
-
-static void
-write_int (Display *display, guint32 value)
-{
-    g_io_channel_write_chars (child_process_get_to_child_channel (CHILD_PROCESS (display->priv->greeter_session)), (const gchar *) &value, sizeof (value), NULL, NULL);
-}
-
-static void
-write_string (Display *display, const gchar *value)
-{
-    write_int (display, strlen (value));
-    g_io_channel_write_chars (child_process_get_to_child_channel (CHILD_PROCESS (display->priv->greeter_session)), value, -1, NULL, NULL);  
-}
-
-static void
-write_header (Display *display, guint32 id, guint32 length)
-{
-    write_int (display, id);
-    write_int (display, length);
-}
-
-static guint32
-int_length ()
-{
-    return sizeof (guint32);
-}
-
-static guint32
-string_length (const gchar *value)
-{
-    return int_length () + strlen (value);
-}
-
-static void
-flush (Display *display)
-{
-    g_io_channel_flush (child_process_get_to_child_channel (CHILD_PROCESS (display->priv->greeter_session)), NULL);
-}
-
-static void
-handle_connect (Display *display)
-{
-    gchar *theme;
-
-    if (!display->priv->greeter_connected)
-    {
-        display->priv->greeter_connected = TRUE;
-        g_debug ("Greeter connected");
-    }
-
-    theme = g_build_filename (THEME_DIR, display->priv->greeter_theme, "index.theme", NULL);
-
-    write_header (display, GREETER_MESSAGE_CONNECTED, string_length (theme) + string_length (display->priv->default_layout) + string_length (display->priv->default_session) + string_length (display->priv->default_user ? display->priv->default_user : "") + int_length ());
-    write_string (display, theme);
-    write_string (display, display->priv->default_layout);
-    write_string (display, display->priv->default_session);
-    write_string (display, display->priv->default_user ? display->priv->default_user : "");
-    write_int (display, display->priv->timeout);
-    flush (display);
-
-    g_free (theme);
-}
-
-static void
-pam_messages_cb (PAMSession *session, int num_msg, const struct pam_message **msg, Display *display)
-{
-    int i;
-    guint32 size;
-
-    /* Respond to d-bus query with messages */
-    g_debug ("Prompt greeter with %d message(s)", num_msg);
-    size = int_length ();
-    for (i = 0; i < num_msg; i++)
-        size += int_length () + string_length (msg[i]->msg);
-    write_header (display, GREETER_MESSAGE_PROMPT_AUTHENTICATION, size);
-    write_int (display, num_msg);
-    for (i = 0; i < num_msg; i++)
-    {
-        write_int (display, msg[i]->msg_style);
-        write_string (display, msg[i]->msg);
-    }
-    flush (display);  
-}
-
-static void
-authenticate_result_cb (PAMSession *session, int result, Display *display)
-{
-    g_debug ("Authenticate result for user %s: %s", pam_session_get_username (display->priv->user_pam_session), pam_session_strerror (display->priv->user_pam_session, result));
-
-    if (result == PAM_SUCCESS)
-    {
-        run_script ("PostLogin");
-        pam_session_authorize (session);
-    }
-
-    /* Respond to D-Bus request */
-    write_header (display, GREETER_MESSAGE_END_AUTHENTICATION, int_length ());
-    write_int (display, result);   
-    flush (display);
-}
-
-static void
-session_started_cb (PAMSession *session, Display *display)
-{
-    display->priv->user_ck_cookie = start_ck_session (display, "", pam_session_get_username (display->priv->user_pam_session));
-}
-
-static void
-handle_start_authentication (Display *display, const gchar *username)
-{
-    GError *error = NULL;
-
-    if (!display->priv->greeter_session || display->priv->user_session)
-        return;
-
-    /* Abort existing authentication */
-    if (display->priv->user_pam_session)
-    {
-        g_signal_handlers_disconnect_matched (display->priv->user_pam_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
-        pam_session_end (display->priv->user_pam_session);
-        g_object_unref (display->priv->user_pam_session);
-    }
-
-    g_debug ("Greeter start authentication for %s", username);
-
-    display->priv->user_pam_session = pam_session_new (display->priv->pam_service, username);
-    g_signal_connect (G_OBJECT (display->priv->user_pam_session), "got-messages", G_CALLBACK (pam_messages_cb), display);
-    g_signal_connect (G_OBJECT (display->priv->user_pam_session), "authentication-result", G_CALLBACK (authenticate_result_cb), display);
-    g_signal_connect (G_OBJECT (display->priv->user_pam_session), "started", G_CALLBACK (session_started_cb), display);
-
-    if (!pam_session_start (display->priv->user_pam_session, &error))
-        g_warning ("Failed to start authentication: %s", error->message);
-}
-
-static void
-handle_continue_authentication (Display *display, gchar **secrets)
-{
-    int num_messages;
-    const struct pam_message **messages;
-    struct pam_response *response;
-    int i, j, n_secrets = 0;
-
-    /* Not connected */
-    if (!display->priv->greeter_connected)
-        return;
-
-    /* Not in authorization */
-    if (display->priv->user_pam_session == NULL)
-        return;
-
-    num_messages = pam_session_get_num_messages (display->priv->user_pam_session);
-    messages = pam_session_get_messages (display->priv->user_pam_session);
-
-    /* Check correct number of responses */
-    for (i = 0; i < num_messages; i++)
-    {
-        int msg_style = messages[i]->msg_style;
-        if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
-            n_secrets++;
-    }
-    if (g_strv_length (secrets) != n_secrets)
-    {
-        pam_session_end (display->priv->user_pam_session);
-        return;
-    }
-
-    g_debug ("Continue authentication");
-
-    /* Build response */
-    response = calloc (num_messages, sizeof (struct pam_response));  
-    for (i = 0, j = 0; i < num_messages; i++)
-    {
-        int msg_style = messages[i]->msg_style;
-        if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
-        {
-            response[i].resp = strdup (secrets[j]); // FIXME: Need to convert from UTF-8
-            j++;
-        }
-    }
-
-    pam_session_respond (display->priv->user_pam_session, response);
-}
-
-static gboolean
-quit_greeter_cb (gpointer data)
-{
-    Display *display = data;
-    g_warning ("Greeter did not quit, sending kill signal");
-    session_stop (display->priv->greeter_session);
-    display->priv->greeter_quit_timeout = 0;
-    return TRUE;
-}
-
-static void
-quit_greeter (Display *display)
-{
-    write_header (display, GREETER_MESSAGE_QUIT, 0);
-    flush (display);
-
-    if (display->priv->greeter_quit_timeout)
-        g_source_remove (display->priv->greeter_quit_timeout);
-    display->priv->greeter_quit_timeout = g_timeout_add (GREETER_QUIT_TIMEOUT, quit_greeter_cb, display);
-}
-
 static gboolean
 session_timeout_cb (Display *display)
 {
     g_warning ("Session has not indicated it is ready, stopping greeter anyway");
 
     /* Stop the greeter */
-    quit_greeter (display);
+    greeter_quit (display->priv->greeter_session);
 
     display->priv->user_session_timer = 0;
     return FALSE;
 }
 
 static void
-handle_login (Display *display, gchar *username, gchar *session, gchar *language)
+greeter_login_cb (Greeter *greeter, const gchar *username, const gchar *session, const gchar *language, Display *display)
 {
-    if (display->priv->user_session != NULL)
-    {
-        g_warning ("Ignoring request to log in when already logged in");
-        return;
-    }
-
-    g_debug ("Greeter login for user %s on session %s", username, session);
-  
     /* Default session requested */
     if (strcmp (session, "") == 0)
         session = display->priv->default_session;
@@ -891,6 +633,9 @@ handle_login (Display *display, gchar *username, gchar *session, gchar *language
     /* Default language requested */
     if (strcmp (language, "") == 0)
         language = NULL;
+  
+    display->priv->user_pam_session = greeter_get_pam_session (greeter);
+    display->priv->user_ck_cookie = start_ck_session (display, "", pam_session_get_username (display->priv->user_pam_session));
 
     if (display->priv->default_user && strcmp (username, display->priv->default_user) == 0)
         start_default_session (display, session, language);
@@ -909,136 +654,24 @@ handle_login (Display *display, gchar *username, gchar *session, gchar *language
     if (display->priv->supports_transitions)
         display->priv->user_session_timer = g_timeout_add (USER_SESSION_TIMEOUT, (GSourceFunc) session_timeout_cb, display);
     else
-        quit_greeter (display);
-}
-
-#define HEADER_SIZE (sizeof (guint32) * 2)
-
-static guint32
-read_int (Display *display, gsize *offset)
-{
-    guint32 *value;
-    if (display->priv->n_read - *offset < sizeof (guint32))
-    {
-        g_warning ("Not enough space for int, need %zu, got %zu", sizeof (guint32), display->priv->n_read - *offset);
-        return 0;
-    }
-    value = (guint32 *) (display->priv->read_buffer + *offset);
-    *offset += sizeof (guint32);
-    return *value;
-}
-
-static gchar *
-read_string (Display *display, gsize *offset)
-{
-    guint32 length;
-    gchar *value;
-
-    length = read_int (display, offset);
-    if (display->priv->n_read - *offset < length)
-    {
-        g_warning ("Not enough space for string, need %u, got %zu", length, display->priv->n_read - *offset);
-        return g_strdup ("");
-    }
-
-    value = g_malloc (sizeof (gchar *) * (length + 1));
-    memcpy (value, display->priv->read_buffer + *offset, length);
-    value[length] = '\0';
-    *offset += length;
-
-    return value;
+        greeter_quit (display->priv->greeter_session);
 }
 
 static void
-greeter_data_cb (Session *session, Display *display)
+greeter_quit_cb (Greeter *greeter, Display *display)
 {
-    gsize n_to_read, n_read, offset;
-    GIOStatus status;
-    int message, n_secrets, i;
-    gchar *username, *session_name, *language;
-    gchar **secrets;
-    GError *error = NULL;
-
-    n_to_read = HEADER_SIZE;
-    if (display->priv->n_read >= HEADER_SIZE)
-        n_to_read += ((guint32 *) display->priv->read_buffer)[1];
-
-    status = g_io_channel_read_chars (child_process_get_from_child_channel (CHILD_PROCESS (session)),
-                                      display->priv->read_buffer + display->priv->n_read,
-                                      n_to_read - display->priv->n_read,
-                                      &n_read,
-                                      &error);
-    if (status != G_IO_STATUS_NORMAL)
-        g_warning ("Error reading from greeter: %s", error->message);
-    g_clear_error (&error);
-    if (status != G_IO_STATUS_NORMAL)
-        return;
-
-    display->priv->n_read += n_read;
-    if (display->priv->n_read != n_to_read)
-        return;
+    g_signal_emit (greeter, signals[END_GREETER], 0, display->priv->greeter_session);
 
-    /* If have header, rerun for content */
-    if (display->priv->n_read == HEADER_SIZE)
-    {
-        n_to_read = ((guint32 *) display->priv->read_buffer)[1];
-        if (n_to_read > 0)
-        {
-            display->priv->read_buffer = g_realloc (display->priv->read_buffer, HEADER_SIZE + n_to_read);
-            greeter_data_cb (session, display);
-            return;
-        }
-    }
-
-    offset = 0;
-    message = read_int (display, &offset);
-    read_int (display, &offset);
-    switch (message)
-    {
-    case GREETER_MESSAGE_CONNECT:
-        handle_connect (display);
-        break;
-    case GREETER_MESSAGE_START_AUTHENTICATION:
-        username = read_string (display, &offset);
-        handle_start_authentication (display, username);
-        g_free (username);
-        break;
-    case GREETER_MESSAGE_CONTINUE_AUTHENTICATION:
-        n_secrets = read_int (display, &offset);
-        secrets = g_malloc (sizeof (gchar *) * (n_secrets + 1));
-        for (i = 0; i < n_secrets; i++)
-            secrets[i] = read_string (display, &offset);
-        secrets[i] = NULL;
-        handle_continue_authentication (display, secrets);
-        g_strfreev (secrets);
-        break;
-    case GREETER_MESSAGE_LOGIN:
-        username = read_string (display, &offset);
-        session_name = read_string (display, &offset);
-        language = read_string (display, &offset);
-        handle_login (display, username, session_name, language);
-        g_free (username);
-        g_free (session_name);
-        g_free (language);
-        break;
-    default:
-        g_warning ("Unknown message from greeter: %d", message);
-        break;
-    }
-
-    display->priv->n_read = 0;
-}
+    pam_session_end (display->priv->greeter_pam_session);
+    g_object_unref (display->priv->greeter_pam_session);
+    display->priv->greeter_pam_session = NULL;
 
-static void
-greeter_session_exited_cb (Session *session, gint status, Display *display)
-{
-    end_greeter_session (display, status == 0);
-}
+    g_object_unref (display->priv->greeter_session);
+    display->priv->greeter_session = NULL;
 
-static void
-greeter_session_terminated_cb (Session *session, gint signum, Display *display)
-{
-    end_greeter_session (display, FALSE);
+    end_ck_session (display->priv->greeter_ck_cookie);
+    g_free (display->priv->greeter_ck_cookie);
+    display->priv->greeter_ck_cookie = NULL;  
 }
 
 static void
@@ -1080,22 +713,26 @@ start_greeter (Display *display)
         pam_session_authorize (display->priv->greeter_pam_session);
 
         display->priv->greeter_ck_cookie = start_ck_session (display,
-                                                              "LoginWindow",
-                                                              username);
-
-        display->priv->greeter_connected = FALSE;
-        display->priv->greeter_session = session_new (username, command);
-        g_signal_connect (G_OBJECT (display->priv->greeter_session), "got-data", G_CALLBACK (greeter_data_cb), display);      
-        g_signal_connect (G_OBJECT (display->priv->greeter_session), "exited", G_CALLBACK (greeter_session_exited_cb), display);
-        g_signal_connect (G_OBJECT (display->priv->greeter_session), "terminated", G_CALLBACK (greeter_session_terminated_cb), display);
+                                                             "LoginWindow",
+                                                             username);
+
+        display->priv->greeter_session = greeter_new ();
+        greeter_set_theme (display->priv->greeter_session, display->priv->greeter_theme);
+        greeter_set_default_user (display->priv->greeter_session, display->priv->default_user, display->priv->timeout);
+        greeter_set_layout (display->priv->greeter_session, display->priv->default_layout);
+        greeter_set_session (display->priv->greeter_session, display->priv->default_session);
+        g_signal_connect (G_OBJECT (display->priv->greeter_session), "login", G_CALLBACK (greeter_login_cb), display);
+        g_signal_connect (G_OBJECT (display->priv->greeter_session), "quit", G_CALLBACK (greeter_quit_cb), display);
+        session_set_username (SESSION (display->priv->greeter_session), username);
+        session_set_command (SESSION (display->priv->greeter_session), command);
         child_process_set_env (CHILD_PROCESS (display->priv->greeter_session), "DISPLAY", xserver_get_address (display->priv->xserver));
         if (display->priv->greeter_ck_cookie)
             child_process_set_env (CHILD_PROCESS (display->priv->greeter_session), "XDG_SESSION_COOKIE", display->priv->greeter_ck_cookie);
-        set_env_from_pam_session (display->priv->greeter_session, display->priv->greeter_pam_session);
+        set_env_from_pam_session (SESSION (display->priv->greeter_session), display->priv->greeter_pam_session);
 
         g_signal_emit (display, signals[START_GREETER], 0, display->priv->greeter_session);
 
-        session_start (display->priv->greeter_session, TRUE);
+        session_start (SESSION (display->priv->greeter_session), TRUE);
 
         g_free (command);
         g_key_file_free (theme);
@@ -1144,7 +781,6 @@ display_init (Display *display)
     display->priv->greeter_theme = g_strdup (GREETER_THEME);
     display->priv->default_layout = g_strdup ("us"); // FIXME: Is there a better default to get?
     display->priv->default_session = g_strdup (DEFAULT_SESSION);
-    display->priv->read_buffer = g_malloc (HEADER_SIZE);
 }
 
 static void
diff --git a/src/greeter.c b/src/greeter.c
new file mode 100644 (file)
index 0000000..194b753
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ * Copyright (C) 2010 Robert Ancell.
+ * Author: Robert Ancell <robert.ancell@canonical.com>
+ * 
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+#include <string.h>
+
+#include "greeter.h"
+#include "ldm-marshal.h"
+#include "greeter-protocol.h"
+
+/* Length of time in milliseconds to wait for a greeter to quit */
+#define GREETER_QUIT_TIMEOUT 1000
+
+enum {
+    LOGIN,
+    QUIT,
+    LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+struct GreeterPrivate
+{
+    gboolean connected;
+
+    /* Pipe to communicate to greeter */
+    int pipe[2];
+    gchar *read_buffer;
+    gsize n_read;
+  
+    gchar *theme;
+    gchar *layout;
+    gchar *session;
+    gchar *default_user;
+    gint autologin_timeout;
+
+    guint quit_timeout;
+  
+    PAMSession *pam_session;    
+};
+
+G_DEFINE_TYPE (Greeter, greeter, SESSION_TYPE);
+
+Greeter *
+greeter_new (void)
+{
+    return g_object_new (GREETER_TYPE, NULL);
+}
+
+void
+greeter_set_default_user (Greeter *greeter, const gchar *username, gint timeout)
+{
+    g_free (greeter->priv->default_user);
+    greeter->priv->default_user = g_strdup (username);
+    greeter->priv->autologin_timeout = timeout;
+}
+
+void
+greeter_set_theme (Greeter *greeter, const gchar *theme)
+{
+    g_free (greeter->priv->theme);
+    greeter->priv->theme = g_strdup (theme);
+}
+
+void
+greeter_set_layout (Greeter *greeter, const gchar *layout)
+{
+    g_free (greeter->priv->layout);
+    greeter->priv->layout = g_strdup (layout);
+}
+
+const gchar *
+greeter_get_layout (Greeter *greeter)
+{
+    return greeter->priv->layout;
+}
+
+void
+greeter_set_session (Greeter *greeter, const gchar *session)
+{
+    g_free (greeter->priv->session);
+    greeter->priv->session = g_strdup (session);
+}
+
+const gchar *
+greeter_get_session (Greeter *greeter)
+{
+    return greeter->priv->session;
+}
+
+PAMSession *
+greeter_get_pam_session (Greeter *greeter)
+{
+    return greeter->priv->pam_session;
+}
+
+static void
+write_int (Greeter *greeter, guint32 value)
+{
+    g_io_channel_write_chars (child_process_get_to_child_channel (CHILD_PROCESS (greeter)), (const gchar *) &value, sizeof (value), NULL, NULL);
+}
+
+static void
+write_string (Greeter *greeter, const gchar *value)
+{
+    write_int (greeter, strlen (value));
+    g_io_channel_write_chars (child_process_get_to_child_channel (CHILD_PROCESS (greeter)), value, -1, NULL, NULL);  
+}
+
+static void
+write_header (Greeter *greeter, guint32 id, guint32 length)
+{
+    write_int (greeter, id);
+    write_int (greeter, length);
+}
+
+static guint32
+int_length ()
+{
+    return sizeof (guint32);
+}
+
+static guint32
+string_length (const gchar *value)
+{
+    return int_length () + strlen (value);
+}
+
+static void
+flush (Greeter *greeter)
+{
+    g_io_channel_flush (child_process_get_to_child_channel (CHILD_PROCESS (greeter)), NULL);
+}
+
+static void
+handle_connect (Greeter *greeter)
+{
+    gchar *theme;
+
+    if (!greeter->priv->connected)
+    {
+        greeter->priv->connected = TRUE;
+        g_debug ("Greeter connected");
+    }
+
+    theme = g_build_filename (THEME_DIR, greeter->priv->theme, "index.theme", NULL);
+
+    write_header (greeter, GREETER_MESSAGE_CONNECTED, string_length (theme) + string_length (greeter->priv->layout) + string_length (greeter->priv->session) + string_length (greeter->priv->default_user ? greeter->priv->default_user : "") + int_length ());
+    write_string (greeter, theme);
+    write_string (greeter, greeter->priv->layout);
+    write_string (greeter, greeter->priv->session);
+    write_string (greeter, greeter->priv->default_user ? greeter->priv->default_user : "");
+    write_int (greeter, greeter->priv->autologin_timeout);
+    flush (greeter);
+
+    g_free (theme);
+}
+
+static void
+pam_messages_cb (PAMSession *session, int num_msg, const struct pam_message **msg, Greeter *greeter)
+{
+    int i;
+    guint32 size;
+
+    /* Respond to d-bus query with messages */
+    g_debug ("Prompt greeter with %d message(s)", num_msg);
+    size = int_length ();
+    for (i = 0; i < num_msg; i++)
+        size += int_length () + string_length (msg[i]->msg);
+    write_header (greeter, GREETER_MESSAGE_PROMPT_AUTHENTICATION, size);
+    write_int (greeter, num_msg);
+    for (i = 0; i < num_msg; i++)
+    {
+        write_int (greeter, msg[i]->msg_style);
+        write_string (greeter, msg[i]->msg);
+    }
+    flush (greeter);  
+}
+
+static void
+authenticate_result_cb (PAMSession *session, int result, Greeter *greeter)
+{
+    g_debug ("Authenticate result for user %s: %s", pam_session_get_username (greeter->priv->pam_session), pam_session_strerror (greeter->priv->pam_session, result));
+
+    if (result == PAM_SUCCESS)
+    {
+        //run_script ("PostLogin");
+        pam_session_authorize (session);
+    }
+
+    /* Respond to D-Bus request */
+    write_header (greeter, GREETER_MESSAGE_END_AUTHENTICATION, int_length ());
+    write_int (greeter, result);   
+    flush (greeter);
+}
+
+static void
+handle_start_authentication (Greeter *greeter, const gchar *username)
+{
+    GError *error = NULL;
+
+    // FIXME
+    //if (greeter->priv->user_session)
+    //    return;
+
+    /* Abort existing authentication */
+    if (greeter->priv->pam_session)
+    {
+        g_signal_handlers_disconnect_matched (greeter->priv->pam_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, greeter);
+        pam_session_end (greeter->priv->pam_session);
+        g_object_unref (greeter->priv->pam_session);
+    }
+
+    g_debug ("Greeter start authentication for %s", username);
+
+    greeter->priv->pam_session = pam_session_new ("lightdm"/*FIXMEgreeter->priv->pam_service*/, username);
+    g_signal_connect (G_OBJECT (greeter->priv->pam_session), "got-messages", G_CALLBACK (pam_messages_cb), greeter);
+    g_signal_connect (G_OBJECT (greeter->priv->pam_session), "authentication-result", G_CALLBACK (authenticate_result_cb), greeter);
+
+    if (!pam_session_start (greeter->priv->pam_session, &error))
+        g_warning ("Failed to start authentication: %s", error->message);
+}
+
+static void
+handle_continue_authentication (Greeter *greeter, gchar **secrets)
+{
+    int num_messages;
+    const struct pam_message **messages;
+    struct pam_response *response;
+    int i, j, n_secrets = 0;
+
+    /* Not connected */
+    if (!greeter->priv->connected)
+        return;
+
+    /* Not in authorization */
+    if (greeter->priv->pam_session == NULL)
+        return;
+
+    num_messages = pam_session_get_num_messages (greeter->priv->pam_session);
+    messages = pam_session_get_messages (greeter->priv->pam_session);
+
+    /* Check correct number of responses */
+    for (i = 0; i < num_messages; i++)
+    {
+        int msg_style = messages[i]->msg_style;
+        if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
+            n_secrets++;
+    }
+    if (g_strv_length (secrets) != n_secrets)
+    {
+        pam_session_end (greeter->priv->pam_session);
+        return;
+    }
+
+    g_debug ("Continue authentication");
+
+    /* Build response */
+    response = calloc (num_messages, sizeof (struct pam_response));  
+    for (i = 0, j = 0; i < num_messages; i++)
+    {
+        int msg_style = messages[i]->msg_style;
+        if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
+        {
+            response[i].resp = strdup (secrets[j]); // FIXME: Need to convert from UTF-8
+            j++;
+        }
+    }
+
+    pam_session_respond (greeter->priv->pam_session, response);
+}
+
+static gboolean
+quit_greeter_cb (gpointer data)
+{
+    Greeter *greeter = data;
+    g_warning ("Greeter did not quit, sending kill signal");
+    session_stop (SESSION (greeter));
+    greeter->priv->quit_timeout = 0;
+    return TRUE;
+}
+
+void
+greeter_quit (Greeter *greeter)
+{
+    write_header (greeter, GREETER_MESSAGE_QUIT, 0);
+    flush (greeter);
+
+    if (greeter->priv->quit_timeout)
+        g_source_remove (greeter->priv->quit_timeout);
+    greeter->priv->quit_timeout = g_timeout_add (GREETER_QUIT_TIMEOUT, quit_greeter_cb, greeter);
+}
+
+static void
+handle_login (Greeter *greeter, gchar *username, gchar *session, gchar *language)
+{
+    /*if (greeter->priv->user_session != NULL)
+    {
+        g_warning ("Ignoring request to log in when already logged in");
+        return;
+    }*/
+
+    g_debug ("Greeter login for user %s on session %s", username, session);
+
+    g_signal_emit (greeter, signals[LOGIN], 0, username, session, language);
+}
+
+#define HEADER_SIZE (sizeof (guint32) * 2)
+
+static guint32
+read_int (Greeter *greeter, gsize *offset)
+{
+    guint32 *value;
+    if (greeter->priv->n_read - *offset < sizeof (guint32))
+    {
+        g_warning ("Not enough space for int, need %zu, got %zu", sizeof (guint32), greeter->priv->n_read - *offset);
+        return 0;
+    }
+    value = (guint32 *) (greeter->priv->read_buffer + *offset);
+    *offset += sizeof (guint32);
+    return *value;
+}
+
+static gchar *
+read_string (Greeter *greeter, gsize *offset)
+{
+    guint32 length;
+    gchar *value;
+
+    length = read_int (greeter, offset);
+    if (greeter->priv->n_read - *offset < length)
+    {
+        g_warning ("Not enough space for string, need %u, got %zu", length, greeter->priv->n_read - *offset);
+        return g_strdup ("");
+    }
+
+    value = g_malloc (sizeof (gchar *) * (length + 1));
+    memcpy (value, greeter->priv->read_buffer + *offset, length);
+    value[length] = '\0';
+    *offset += length;
+
+    return value;
+}
+
+static void
+got_data_cb (Greeter *greeter)
+{
+    gsize n_to_read, n_read, offset;
+    GIOStatus status;
+    int message, n_secrets, i;
+    gchar *username, *session_name, *language;
+    gchar **secrets;
+    GError *error = NULL;
+
+    n_to_read = HEADER_SIZE;
+    if (greeter->priv->n_read >= HEADER_SIZE)
+        n_to_read += ((guint32 *) greeter->priv->read_buffer)[1];
+
+    status = g_io_channel_read_chars (child_process_get_from_child_channel (CHILD_PROCESS (greeter)),
+                                      greeter->priv->read_buffer + greeter->priv->n_read,
+                                      n_to_read - greeter->priv->n_read,
+                                      &n_read,
+                                      &error);
+    if (status != G_IO_STATUS_NORMAL)
+        g_warning ("Error reading from greeter: %s", error->message);
+    g_clear_error (&error);
+    if (status != G_IO_STATUS_NORMAL)
+        return;
+
+    greeter->priv->n_read += n_read;
+    if (greeter->priv->n_read != n_to_read)
+        return;
+
+    /* If have header, rerun for content */
+    if (greeter->priv->n_read == HEADER_SIZE)
+    {
+        n_to_read = ((guint32 *) greeter->priv->read_buffer)[1];
+        if (n_to_read > 0)
+        {
+            greeter->priv->read_buffer = g_realloc (greeter->priv->read_buffer, HEADER_SIZE + n_to_read);
+            got_data_cb (greeter);
+            return;
+        }
+    }
+
+    offset = 0;
+    message = read_int (greeter, &offset);
+    read_int (greeter, &offset);
+    switch (message)
+    {
+    case GREETER_MESSAGE_CONNECT:
+        handle_connect (greeter);
+        break;
+    case GREETER_MESSAGE_START_AUTHENTICATION:
+        username = read_string (greeter, &offset);
+        handle_start_authentication (greeter, username);
+        g_free (username);
+        break;
+    case GREETER_MESSAGE_CONTINUE_AUTHENTICATION:
+        n_secrets = read_int (greeter, &offset);
+        secrets = g_malloc (sizeof (gchar *) * (n_secrets + 1));
+        for (i = 0; i < n_secrets; i++)
+            secrets[i] = read_string (greeter, &offset);
+        secrets[i] = NULL;
+        handle_continue_authentication (greeter, secrets);
+        g_strfreev (secrets);
+        break;
+    case GREETER_MESSAGE_LOGIN:
+        username = read_string (greeter, &offset);
+        session_name = read_string (greeter, &offset);
+        language = read_string (greeter, &offset);
+        handle_login (greeter, username, session_name, language);
+        g_free (username);
+        g_free (session_name);
+        g_free (language);
+        break;
+    default:
+        g_warning ("Unknown message from greeter: %d", message);
+        break;
+    }
+
+    greeter->priv->n_read = 0;
+}
+
+static void
+end_session (Greeter *greeter, gboolean clean_exit)
+{  
+    if (greeter->priv->quit_timeout)
+    {
+        g_source_remove (greeter->priv->quit_timeout);
+        greeter->priv->quit_timeout = 0;
+    }
+
+    /*if (!clean_exit)
+        g_warning ("Greeter failed");
+    else if (!greeter_connected)
+        g_warning ("Greeter quit before connecting");
+    else if (!display->priv->user_session)
+        g_warning ("Greeter quit before session started");
+    else
+        return;*/
+
+    // FIXME: Issue with greeter, don't want to start a new one, report error to user
+
+    g_signal_emit (greeter, signals[QUIT], 0);
+}
+
+static void
+session_exited_cb (Greeter *greeter, gint status)
+{
+    end_session (greeter, status == 0);
+}
+
+static void
+session_terminated_cb (Greeter *greeter, gint signum)
+{
+    end_session (greeter, FALSE);
+}
+
+static void
+greeter_init (Greeter *greeter)
+{
+    greeter->priv = G_TYPE_INSTANCE_GET_PRIVATE (greeter, GREETER_TYPE, GreeterPrivate);
+    greeter->priv->read_buffer = g_malloc (HEADER_SIZE);
+    g_signal_connect (G_OBJECT (greeter), "got-data", G_CALLBACK (got_data_cb), NULL);
+    g_signal_connect (G_OBJECT (greeter), "exited", G_CALLBACK (session_exited_cb), NULL);
+    g_signal_connect (G_OBJECT (greeter), "terminated", G_CALLBACK (session_terminated_cb), NULL);
+}
+
+static void
+greeter_finalize (GObject *object)
+{
+    Greeter *self;
+
+    self = GREETER (object);
+  
+    g_free (self->priv->read_buffer);
+    g_free (self->priv->theme);
+    g_free (self->priv->layout);
+    g_free (self->priv->session);
+    g_free (self->priv->default_user);
+}
+
+static void
+greeter_class_init (GreeterClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    object_class->finalize = greeter_finalize;
+
+    signals[LOGIN] =
+        g_signal_new ("login",
+                      G_TYPE_FROM_CLASS (klass),
+                      G_SIGNAL_RUN_LAST,
+                      G_STRUCT_OFFSET (GreeterClass, login),
+                      NULL, NULL,
+                      ldm_marshal_VOID__STRING_STRING_STRING,
+                      G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+    signals[QUIT] =
+        g_signal_new ("quit",
+                      G_TYPE_FROM_CLASS (klass),
+                      G_SIGNAL_RUN_LAST,
+                      G_STRUCT_OFFSET (GreeterClass, quit),
+                      NULL, NULL,
+                      g_cclosure_marshal_VOID__VOID,
+                      G_TYPE_NONE, 0);
+
+    g_type_class_add_private (klass, sizeof (GreeterPrivate));
+}
diff --git a/src/greeter.h b/src/greeter.h
new file mode 100644 (file)
index 0000000..a586b8c
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 Robert Ancell.
+ * Author: Robert Ancell <robert.ancell@canonical.com>
+ * 
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+#ifndef _GREETER_H_
+#define _GREETER_H_
+
+#include "session.h"
+#include "pam-session.h"
+
+G_BEGIN_DECLS
+
+#define GREETER_TYPE (greeter_get_type())
+#define GREETER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GREETER_TYPE, Greeter))
+
+typedef struct GreeterPrivate GreeterPrivate;
+
+typedef struct
+{
+    Session         parent_instance;
+    GreeterPrivate *priv;
+} Greeter;
+
+typedef struct
+{
+    SessionClass parent_class;
+    void (*login)(Greeter *greeter, const gchar *username, const gchar *session, const gchar *language);
+    void (*quit)(Greeter *greeter);
+} GreeterClass;
+
+GType greeter_get_type (void);
+
+Greeter *greeter_new (void);
+
+void greeter_set_default_user (Greeter *greeter, const gchar *username, gint timeout);
+
+void greeter_set_theme (Greeter *greeter, const gchar *theme);
+
+void greeter_set_layout (Greeter *greeter, const gchar *layout);
+
+const gchar *greeter_get_layout (Greeter *greeter);
+
+void greeter_set_session (Greeter *greeter, const gchar *session);
+
+const gchar *greeter_get_session (Greeter *greeter);
+
+PAMSession *greeter_get_pam_session (Greeter *greeter);
+
+void greeter_quit (Greeter *greeter);
+
+G_END_DECLS
+
+#endif /* _GREETER_H_ */
index 599d93c8c1db5003bf5045f7a6ed97a0cf7e5bb3..27d287b4f3477be1948749d1fa91bb967ed343a8 100644 (file)
@@ -1,3 +1,4 @@
 BOOLEAN:OBJECT
 VOID:INT,POINTER
 VOID:OBJECT,BOOLEAN
+VOID:STRING,STRING,STRING
index 69f1f2702ec1af0bb1ac9a94a80acdd242b1428c..af19cd34b370113d0cf144179f2acb2c26680a65 100644 (file)
@@ -44,14 +44,15 @@ struct SessionPrivate
 G_DEFINE_TYPE (Session, session, CHILD_PROCESS_TYPE);
 
 Session *
-session_new (const char *username, const char *command)
+session_new ()
 {
-    Session *self = g_object_new (SESSION_TYPE, NULL);
-
-    self->priv->username = g_strdup (username);
-    self->priv->command = g_strdup (command);
+    return g_object_new (SESSION_TYPE, NULL);
+}
 
-    return self;
+void
+session_set_username (Session *session, const gchar *username)
+{
+    session->priv->username = g_strdup (username);
 }
 
 const gchar *
@@ -60,6 +61,12 @@ session_get_username (Session *session)
     return session->priv->username;
 }
 
+void
+session_set_command (Session *session, const gchar *command)
+{
+    session->priv->command = g_strdup (command);
+}
+
 const gchar *
 session_get_command (Session *session)
 {
@@ -88,6 +95,7 @@ session_start (Session *session, gboolean create_pipe)
     GError *error = NULL;
   
     //g_return_val_if_fail (session->priv->pid == 0, FALSE);
+    g_return_val_if_fail (session->priv->command != NULL, FALSE);
 
     errno = 0;
     if (session->priv->username)
index c5935cd09357aee8fb3829e001247f1a0e941268..8524a864b49aca5cae6695d80269b4ddd5d3dfa0 100644 (file)
@@ -18,7 +18,7 @@
 G_BEGIN_DECLS
 
 #define SESSION_TYPE (session_get_type())
-#define SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SESSION_TYPE, Session));
+#define SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SESSION_TYPE, Session))
 
 typedef struct SessionPrivate SessionPrivate;
 
@@ -35,10 +35,14 @@ typedef struct
 
 GType session_get_type (void);
 
-Session *session_new (const char *username, const char *command);
+Session *session_new (void);
+
+void session_set_username (Session *session, const gchar *username);
 
 const gchar *session_get_username (Session *session);
 
+void session_set_command (Session *session, const gchar *command);
+
 const gchar *session_get_command (Session *session);
 
 void session_set_authorization (Session *session, XAuthorization *authorization, const gchar *path);