]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blobdiff - liblightdm-gobject/greeter.c
Don't access unreffed value
[sojka/lightdm.git] / liblightdm-gobject / greeter.c
index d02890cda604819303f0e5186d0a7e6cc5fa8022..5e6996d3e0eeea02cac78009889eeaaa07637620 100644 (file)
@@ -125,6 +125,9 @@ typedef enum
 typedef struct
 {
     GObject parent_instance;
+    GCancellable *cancellable;
+    GAsyncReadyCallback callback;
+    gpointer user_data;
     gboolean complete;
     guint32 return_code;
     gchar *dir;
@@ -134,8 +137,44 @@ typedef struct
     GObjectClass parent_class;
 } RequestClass;
 GType request_get_type (void);
+static void request_iface_init (GAsyncResultIface *iface);
 #define REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), request_get_type (), Request))
-G_DEFINE_TYPE (Request, request, G_TYPE_OBJECT);
+G_DEFINE_TYPE_WITH_CODE (Request, request, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, request_iface_init));
+
+GType
+lightdm_prompt_type_get_type (void)
+{
+    static GType enum_type = 0;
+  
+    if (G_UNLIKELY(enum_type == 0)) {
+        static const GEnumValue values[] = {
+            { LIGHTDM_PROMPT_TYPE_QUESTION, "LIGHTDM_PROMPT_TYPE_QUESTION", "question" },
+            { LIGHTDM_PROMPT_TYPE_SECRET, "LIGHTDM_PROMPT_TYPE_SECRET", "secret" },
+            { 0, NULL, NULL }
+        };
+        enum_type = g_enum_register_static (g_intern_static_string ("LightDMPromptType"), values);
+    }
+
+    return enum_type;
+}
+
+GType
+lightdm_message_type_get_type (void)
+{
+    static GType enum_type = 0;
+  
+    if (G_UNLIKELY(enum_type == 0)) {
+        static const GEnumValue values[] = {
+            { LIGHTDM_MESSAGE_TYPE_INFO, "LIGHTDM_MESSAGE_TYPE_INFO", "info" },
+            { LIGHTDM_MESSAGE_TYPE_ERROR, "LIGHTDM_MESSAGE_TYPE_ERROR", "error" },
+            { 0, NULL, NULL }
+        };
+        enum_type = g_enum_register_static (g_intern_static_string ("LightDMMessageType"), values);
+    }
+
+    return enum_type;
+}
+
 
 /**
  * lightdm_greeter_new:
@@ -172,15 +211,33 @@ lightdm_greeter_set_resettable (LightDMGreeter *greeter, gboolean resettable)
 }
 
 static Request *
-request_new (void)
+request_new (GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
 {
     Request *request;
 
     request = g_object_new (request_get_type (), NULL);
+    if (cancellable)
+        request->cancellable = g_object_ref (cancellable);
+    request->callback = callback;
+    request->user_data = user_data;
 
     return request;
 }
 
+static void
+request_complete (Request *request, GObject *object)
+{
+    request->complete = TRUE;
+
+    if (!request->callback)
+        return;
+
+    if (request->cancellable && g_cancellable_is_cancelled (request->cancellable))
+        return;
+
+    request->callback (object, G_ASYNC_RESULT (request), request->user_data);
+}
+
 static gboolean
 timed_login_cb (gpointer data)
 {
@@ -221,7 +278,8 @@ write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *off
     write_int (buffer, buffer_length, length, offset);
     if (*offset + length >= buffer_length)
         return;
-    memcpy (buffer + *offset, value, length);
+    if (value)
+        memcpy (buffer + *offset, value, length);
     *offset += length;
 }
 
@@ -288,14 +346,18 @@ get_message_length (guint8 *message, gsize message_length)
     return read_int (message, message_length, &offset);
 }
 
-static void
-write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
+static gboolean
+send_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
 {
     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
-    GIOStatus status;
+    gchar *data;
+    gsize data_length;
     GError *error = NULL;
     guint32 stated_length;
 
+    if (!priv->to_server_channel)
+        return FALSE;
+
     /* Double check that we're sending well-formed messages.  If we say we're
        sending more than we do, we end up DOS'ing lightdm as it waits for the
        rest.  If we say we're sending less than we do, we confuse the heck out
@@ -305,16 +367,33 @@ write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
     if (stated_length != message_length)
     {
         g_warning ("Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu", stated_length, message_length);
-        return;
+        return FALSE;
+    }
+
+    data = (gchar *) message;
+    data_length = message_length;
+    while (data_length > 0)
+    {
+        GIOStatus status;
+        gsize n_written;
+
+        status = g_io_channel_write_chars (priv->to_server_channel, data, data_length, &n_written, &error);
+        if (error)
+            g_warning ("Error writing to daemon: %s", error->message);
+        g_clear_error (&error);
+        if (status != G_IO_STATUS_NORMAL)
+            return FALSE;
+        data_length -= n_written;
+        data += n_written;
     }
 
-    status = g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, &error);
+    g_debug ("Wrote %zi bytes to daemon", message_length);
+    g_io_channel_flush (priv->to_server_channel, &error);
     if (error)
-        g_warning ("Error writing to daemon: %s", error->message);
+        g_warning ("Failed to flush data to daemon: %s", error->message);
     g_clear_error (&error);
-    if (status == G_IO_STATUS_NORMAL)
-        g_debug ("Wrote %zi bytes to daemon", message_length);
-    g_io_channel_flush (priv->to_server_channel, NULL);
+
+    return TRUE;
 }
 
 static void
@@ -331,7 +410,7 @@ handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length
     while (*offset < message_length)
     {
         gchar *name, *value;
-      
+
         name = read_string (message, message_length, offset);
         value = read_string (message, message_length, offset);
         g_hash_table_insert (priv->hints, name, value);
@@ -351,10 +430,11 @@ handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length
         priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
     }
 
+    /* Notify asynchronous caller */
     request = g_list_nth_data (priv->connect_requests, 0);
     if (request)
     {
-        request->complete = TRUE;
+        request_complete (request, G_OBJECT (greeter));
         priv->connect_requests = g_list_remove (priv->connect_requests, request);
         g_object_unref (request);
     }
@@ -501,11 +581,12 @@ handle_session_result (LightDMGreeter *greeter, guint8 *message, gsize message_l
     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
     Request *request;
 
+    /* Notify asynchronous caller */
     request = g_list_nth_data (priv->start_session_requests, 0);
     if (request)
     {
         request->return_code = read_int (message, message_length, offset);
-        request->complete = TRUE;
+        request_complete (request, G_OBJECT (greeter));
         priv->start_session_requests = g_list_remove (priv->start_session_requests, request);
         g_object_unref (request);
     }
@@ -517,6 +598,7 @@ handle_shared_dir_result (LightDMGreeter *greeter, guint8 *message, gsize messag
     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
     Request *request;
 
+    /* Notify asynchronous caller */
     request = g_list_nth_data (priv->ensure_shared_data_dir_requests, 0);
     if (request)
     {
@@ -527,7 +609,7 @@ handle_shared_dir_result (LightDMGreeter *greeter, guint8 *message, gsize messag
             g_free (request->dir);
             request->dir = NULL;
         }
-        request->complete = TRUE;
+        request_complete (request, G_OBJECT (greeter));
         priv->ensure_shared_data_dir_requests = g_list_remove (priv->ensure_shared_data_dir_requests, request);
         g_object_unref (request);
     }
@@ -571,13 +653,16 @@ handle_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
 }
 
 static guint8 *
-read_message (LightDMGreeter *greeter, gsize *length, gboolean block)
+recv_message (LightDMGreeter *greeter, gsize *length, gboolean block)
 {
     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
     gsize n_to_read, n_read;
     guint8 *buffer;
     GError *error = NULL;
 
+    if (!priv->from_server_channel)
+        return NULL;
+
     /* Read the header, or the whole message if we already have that */
     n_to_read = HEADER_SIZE;
     if (priv->n_read >= HEADER_SIZE)
@@ -613,7 +698,7 @@ read_message (LightDMGreeter *greeter, gsize *length, gboolean block)
         if (n_to_read > 0)
         {
             priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
-            return read_message (greeter, length, block);
+            return recv_message (greeter, length, block);
         }
     }
 
@@ -634,7 +719,7 @@ from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
     gsize message_length;
 
     /* Read one message and process it */
-    message = read_message (greeter, &message_length, FALSE);
+    message = recv_message (greeter, &message_length, FALSE);
     if (message)
     {
         handle_message (greeter, message, message_length);
@@ -644,7 +729,7 @@ from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
     return TRUE;
 }
 
-static void
+static gboolean
 send_connect (LightDMGreeter *greeter, gboolean resettable)
 {
     guint8 message[MAX_MESSAGE_LENGTH];
@@ -654,10 +739,11 @@ send_connect (LightDMGreeter *greeter, gboolean resettable)
     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION) + int_length (), &offset);
     write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
     write_int (message, MAX_MESSAGE_LENGTH, resettable ? 1 : 0, &offset);
-    write_message (greeter, message, offset);
+
+    return send_message (greeter, message, offset);
 }
 
-static void
+static gboolean
 send_start_session (LightDMGreeter *greeter, const gchar *session)
 {
     guint8 message[MAX_MESSAGE_LENGTH];
@@ -670,10 +756,10 @@ send_start_session (LightDMGreeter *greeter, const gchar *session)
 
     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
     write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
-    write_message (greeter, message, offset);
+    return send_message (greeter, message, offset);
 }
 
-static void
+static gboolean
 send_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username)
 {
     guint8 message[MAX_MESSAGE_LENGTH];
@@ -683,11 +769,56 @@ send_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username)
 
     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_ENSURE_SHARED_DIR, string_length (username), &offset);
     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
-    write_message (greeter, message, offset);
+    return send_message (greeter, message, offset);
 }
 
 /**
- * lightdm_greeter_connect_sync:
+ * lightdm_greeter_connect_to_daemon:
+ * @greeter: The greeter to connect
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
+ * @user_data: (allow-none): data to pass to the @callback or %NULL.
+ *
+ * Asynchronously connects the greeter to the display manager.
+ *
+ * When the operation is finished, @callback will be invoked. You can then call lightdm_greeter_connect_to_daemon_finish() to get the result of the operation.
+ *
+ * See lightdm_greeter_connect_to_daemon_sync() for the synchronous version.
+ **/
+void
+lightdm_greeter_connect_to_daemon (LightDMGreeter *greeter, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+    LightDMGreeterPrivate *priv;
+    Request *request;
+
+    g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
+
+    priv = GET_PRIVATE (greeter);
+
+    request = request_new (cancellable, callback, user_data);
+    priv->connect_requests = g_list_append (priv->connect_requests, request);
+    send_connect (greeter, priv->resettable);
+}
+
+/**
+ * lightdm_greeter_connect_to_daemon_finish:
+ * @greeter: The greeter the the request was done with
+ * @result: A #GAsyncResult.
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes an operation started with lightdm_greeter_connect_to_daemon().
+ *
+ * Return value: #TRUE if successfully connected
+ **/
+gboolean
+lightdm_greeter_connect_to_daemon_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error)
+{
+    g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+    return REQUEST (result)->complete;
+}
+
+/**
+ * lightdm_greeter_connect_to_daemon_sync:
  * @greeter: The greeter to connect
  * @error: return location for a #GError, or %NULL
  *
@@ -696,54 +827,53 @@ send_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username)
  * Return value: #TRUE if successfully connected
  **/
 gboolean
-lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
+lightdm_greeter_connect_to_daemon_sync (LightDMGreeter *greeter, GError **error)
 {
     LightDMGreeterPrivate *priv;
-    const gchar *fd;
     Request *request;
+    gboolean result;
 
     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
 
     priv = GET_PRIVATE (greeter);
 
-    fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
-    if (!fd)
-    {
-        g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
-        return FALSE;
-    }
-    priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
-    g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
-
-    fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
-    if (!fd)
-    {
-        g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
-        return FALSE;
-    }
-    priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
-    g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
-    g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
-
     /* Read until we are connected */
     send_connect (greeter, priv->resettable);
-    request = request_new ();
+    request = request_new (NULL, NULL, NULL);
     priv->connect_requests = g_list_append (priv->connect_requests, g_object_ref (request));
     do
     {
         guint8 *message;
         gsize message_length;
 
-        message = read_message (greeter, &message_length, TRUE);
+        message = recv_message (greeter, &message_length, TRUE);
         if (!message)
             break;
         handle_message (greeter, message, message_length);
         g_free (message);
     } while (!request->complete);
 
+    result = request->complete;
     g_object_unref (request);
 
-    return request->complete;
+    return result;
+}
+
+/**
+ * lightdm_greeter_connect_sync:
+ * @greeter: The greeter to connect
+ * @error: return location for a #GError, or %NULL
+ *
+ * Connects the greeter to the display manager.  Will block until connected.
+ *
+ * Return value: #TRUE if successfully connected
+ *
+ * Deprecated: 1.11.1: Use lightdm_greeter_connect_to_daemon_sync() instead
+ **/
+gboolean
+lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
+{
+    return lightdm_greeter_connect_to_daemon_sync (greeter, error);
 }
 
 /**
@@ -753,7 +883,7 @@ lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
  *
  * Get a hint.
  *
- * Return value: The value for this hint or #NULL if not set.
+ * Return value: (nullable): The value for this hint or #NULL if not set.
  **/
 const gchar *
 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
@@ -785,7 +915,7 @@ lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
  * accounts should be taken from #LightDMUserList and displayed in the greeter
  * for the user to choose from.  Note that this list can be empty and it is
  * recommended you show a method for the user to enter a username manually.
- * 
+ *
  * If this option is shown the greeter should only allow these users to be
  * chosen for login unless the manual login hint is set.
  *
@@ -878,7 +1008,7 @@ lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
 
     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
     value = lightdm_greeter_get_hint (greeter, "has-guest-account");
-  
+
     return g_strcmp0 (value, "true") == 0;
 }
 
@@ -888,7 +1018,7 @@ lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
  *
  * Get the user to select by default.
  *
- * Return value: A username
+ * Return value: (nullable): A username or %NULL if no particular user should be selected.
  */
 const gchar *
 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
@@ -912,7 +1042,7 @@ lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
 
     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
     value = lightdm_greeter_get_hint (greeter, "select-guest");
-  
+
     return g_strcmp0 (value, "true") == 0;
 }
 
@@ -920,9 +1050,9 @@ lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
  * lightdm_greeter_get_autologin_user_hint:
  * @greeter: A #LightDMGreeter
  *
- * Get the user account to automatically logg into when the timer expires.
+ * Get the user account to automatically log into when the timer expires.
  *
- * Return value: The user account to automatically log into.
+ * Return value: (nullable): The user account to automatically log into or %NULL if none configured.
  */
 const gchar *
 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
@@ -946,7 +1076,7 @@ lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
 
     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
     value = lightdm_greeter_get_hint (greeter, "autologin-guest");
-  
+
     return g_strcmp0 (value, "true") == 0;
 }
 
@@ -1016,7 +1146,7 @@ lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username)
 
     priv->cancelling_authentication = FALSE;
     priv->authenticate_sequence_number++;
-    priv->in_authentication = TRUE;  
+    priv->in_authentication = TRUE;
     priv->is_authenticated = FALSE;
     if (username != priv->authentication_user)
     {
@@ -1028,7 +1158,7 @@ lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username)
     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset);
     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
-    write_message (greeter, message, offset);
+    send_message (greeter, message, offset);
 }
 
 /**
@@ -1060,7 +1190,7 @@ lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter)
     g_debug ("Starting authentication for guest account...");
     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset);
     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
-    write_message (greeter, message, offset);
+    send_message (greeter, message, offset);
 }
 
 /**
@@ -1117,7 +1247,7 @@ lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *sessi
     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
     write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
-    write_message (greeter, message, offset);
+    send_message (greeter, message, offset);
 }
 
 /**
@@ -1160,7 +1290,7 @@ lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response)
         write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset);
         for (iter = priv->responses_received; iter; iter = iter->next)
             write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset);
-        write_message (greeter, message, offset);
+        send_message (greeter, message, offset);
 
         g_list_free_full (priv->responses_received, g_free);
         priv->responses_received = NULL;
@@ -1188,7 +1318,7 @@ lightdm_greeter_cancel_authentication (LightDMGreeter *greeter)
 
     priv->cancelling_authentication = TRUE;
     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
-    write_message (greeter, message, offset);
+    send_message (greeter, message, offset);
 }
 
 /**
@@ -1227,7 +1357,7 @@ lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
  *
  * Get the user that is being authenticated.
  *
- * Return value: The username of the authentication user being authenticated or #NULL if no authentication in progress.
+ * Return value: (nullable): The username of the authentication user being authenticated or #NULL if no authentication in progress.
  */
 const gchar *
 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
@@ -1258,7 +1388,53 @@ lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language)
 
     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset);
     write_string (message, MAX_MESSAGE_LENGTH, language, &offset);
-    write_message (greeter, message, offset);
+    send_message (greeter, message, offset);
+}
+
+/**
+ * lightdm_greeter_start_session:
+ * @greeter: A #LightDMGreeter
+ * @session: (allow-none): The session to log into or #NULL to use the default.
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
+ * @user_data: (allow-none): data to pass to the @callback or %NULL.
+ *
+ * Asynchronously start a session for the authenticated user.
+ *
+ * When the operation is finished, @callback will be invoked. You can then call lightdm_greeter_start_session_finish() to get the result of the operation.
+ *
+ * See lightdm_greeter_start_session_sync() for the synchronous version.
+ **/
+void
+lightdm_greeter_start_session (LightDMGreeter *greeter, const gchar *session, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+    LightDMGreeterPrivate *priv;
+    Request *request;
+
+    g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
+
+    priv = GET_PRIVATE (greeter);
+
+    send_start_session (greeter, session);
+    request = request_new (cancellable, callback, user_data);
+    priv->start_session_requests = g_list_append (priv->start_session_requests, request);
+}
+
+/**
+ * lightdm_greeter_start_session_finish:
+ * @greeter: A #LightDMGreeter
+ * @result: A #GAsyncResult.
+ * @error: return location for a #GError, or %NULL
+ *
+ * Start a session for the authenticated user.
+ *
+ * Return value: TRUE if the session was started.
+ **/
+gboolean
+lightdm_greeter_start_session_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error)
+{
+    g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+    return REQUEST (result)->return_code == 0;
 }
 
 /**
@@ -1287,14 +1463,14 @@ lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *sessio
 
     /* Read until the session is started */
     send_start_session (greeter, session);
-    request = request_new ();
+    request = request_new (NULL, NULL, NULL);
     priv->start_session_requests = g_list_append (priv->start_session_requests, g_object_ref (request));
     do
     {
         guint8 *message;
         gsize message_length;
 
-        message = read_message (greeter, &message_length, TRUE);
+        message = recv_message (greeter, &message_length, TRUE);
         if (!message)
             break;
         handle_message (greeter, message, message_length);
@@ -1307,6 +1483,56 @@ lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *sessio
     return return_code == 0;
 }
 
+/**
+ * lightdm_greeter_ensure_shared_data_dir:
+ * @greeter: A #LightDMGreeter
+ * @username: A username
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
+ * @user_data: (allow-none): data to pass to the @callback or %NULL.
+ *
+ * Ensure that a shared data dir for the given user is available.  Both the
+ * greeter user and @username will have write access to that folder.  The
+ * intention is that larger pieces of shared data would be stored there (files
+ * that the greeter creates but wants to give to a user -- like camera
+ * photos -- or files that the user creates but wants the greeter to
+ * see -- like contact avatars).
+ *
+ * LightDM will automatically create these if the user actually logs in, so
+ * greeters only need to call this method if they want to store something in
+ * the directory themselves.
+ **/
+void
+lightdm_greeter_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+    LightDMGreeterPrivate *priv;
+    Request *request;
+
+    g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
+
+    priv = GET_PRIVATE (greeter);
+
+    send_ensure_shared_data_dir (greeter, username);
+    request = request_new (cancellable, callback, user_data);
+    priv->ensure_shared_data_dir_requests = g_list_append (priv->ensure_shared_data_dir_requests, request);
+}
+
+/**
+ * lightdm_greeter_ensure_shared_data_dir_finish:
+ * @result: A #GAsyncResult.
+ * @greeter: A #LightDMGreeter
+ *
+ * Function to call from lightdm_greeter_ensure_shared_data_dir callback.
+ *
+ * Return value: The path to the shared directory, free with g_free.
+ **/
+gchar *
+lightdm_greeter_ensure_shared_data_dir_finish (LightDMGreeter *greeter, GAsyncResult *result)
+{
+    g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
+    return g_strdup (REQUEST (result)->dir);
+}
+
 /**
  * lightdm_greeter_ensure_shared_data_dir_sync:
  * @greeter: A #LightDMGreeter
@@ -1323,7 +1549,7 @@ lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *sessio
  * greeters only need to call this method if they want to store something in
  * the directory themselves.
  *
- * Return value: The path to the shared directory, free with g_free
+ * Return value: The path to the shared directory, free with g_free.
  **/
 gchar *
 lightdm_greeter_ensure_shared_data_dir_sync (LightDMGreeter *greeter, const gchar *username)
@@ -1340,14 +1566,14 @@ lightdm_greeter_ensure_shared_data_dir_sync (LightDMGreeter *greeter, const gcha
 
     /* Read until a response */
     send_ensure_shared_data_dir (greeter, username);
-    request = request_new ();
+    request = request_new (NULL, NULL, NULL);
     priv->ensure_shared_data_dir_requests = g_list_append (priv->ensure_shared_data_dir_requests, g_object_ref (request));
     do
     {
         guint8 *message;
         gsize message_length;
 
-        message = read_message (greeter, &message_length, TRUE);
+        message = recv_message (greeter, &message_length, TRUE);
         if (!message)
             break;
         handle_message (greeter, message, message_length);
@@ -1364,9 +1590,39 @@ static void
 lightdm_greeter_init (LightDMGreeter *greeter)
 {
     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
+    const gchar *fd;
 
     priv->read_buffer = g_malloc (HEADER_SIZE);
     priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+    fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
+    if (fd)
+    {
+        GError *error = NULL;
+
+        priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
+        g_io_channel_set_encoding (priv->to_server_channel, NULL, &error);
+        if (error)
+            g_warning ("Failed to set encoding on to server channel to binary: %s\n", error->message);
+        g_clear_error (&error);
+    }
+    else
+        g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
+
+    fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
+    if (fd)
+    {
+        GError *error = NULL;
+
+        priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
+        g_io_channel_set_encoding (priv->from_server_channel, NULL, &error);
+        if (error)
+            g_warning ("Failed to set encoding on from server channel to binary: %s\n", error->message);
+        g_clear_error (&error);
+        g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
+    }
+    else
+        g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
 }
 
 static void
@@ -1470,7 +1726,7 @@ lightdm_greeter_class_init (LightDMGreeterClass *klass)
                                                           "default-session-hint",
                                                           "Default session hint",
                                                           NULL,
-                                                          G_PARAM_READWRITE));
+                                                          G_PARAM_READABLE));
 
     g_object_class_install_property (object_class,
                                      PROP_HIDE_USERS_HINT,
@@ -1588,13 +1844,13 @@ lightdm_greeter_class_init (LightDMGreeterClass *klass)
      * lightdm_greeter_cancel_authentication() to abort the authentication.
      **/
     signals[SHOW_PROMPT] =
-        g_signal_new ("show-prompt",
+        g_signal_new (LIGHTDM_GREETER_SIGNAL_SHOW_PROMPT,
                       G_TYPE_FROM_CLASS (klass),
                       G_SIGNAL_RUN_LAST,
                       G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
                       NULL, NULL,
                       NULL,
-                      G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
+                      G_TYPE_NONE, 2, G_TYPE_STRING, lightdm_prompt_type_get_type ());
 
     /**
      * LightDMGreeter::show-message:
@@ -1606,13 +1862,13 @@ lightdm_greeter_class_init (LightDMGreeterClass *klass)
      * should show a message to the user.
      **/
     signals[SHOW_MESSAGE] =
-        g_signal_new ("show-message",
+        g_signal_new (LIGHTDM_GREETER_SIGNAL_SHOW_MESSAGE,
                       G_TYPE_FROM_CLASS (klass),
                       G_SIGNAL_RUN_LAST,
                       G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
                       NULL, NULL,
                       NULL,
-                      G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
+                      G_TYPE_NONE, 2, G_TYPE_STRING, lightdm_message_type_get_type ());
 
     /**
      * LightDMGreeter::authentication-complete:
@@ -1625,7 +1881,7 @@ lightdm_greeter_class_init (LightDMGreeterClass *klass)
      * was successful.
      **/
     signals[AUTHENTICATION_COMPLETE] =
-        g_signal_new ("authentication-complete",
+        g_signal_new (LIGHTDM_GREETER_SIGNAL_AUTHENTICATION_COMPLETE,
                       G_TYPE_FROM_CLASS (klass),
                       G_SIGNAL_RUN_LAST,
                       G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
@@ -1641,7 +1897,7 @@ lightdm_greeter_class_init (LightDMGreeterClass *klass)
      * The application should then call lightdm_greeter_login().
      **/
     signals[AUTOLOGIN_TIMER_EXPIRED] =
-        g_signal_new ("autologin-timer-expired",
+        g_signal_new (LIGHTDM_GREETER_SIGNAL_AUTOLOGIN_TIMER_EXPIRED,
                       G_TYPE_FROM_CLASS (klass),
                       G_SIGNAL_RUN_LAST,
                       G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),
@@ -1660,7 +1916,7 @@ lightdm_greeter_class_init (LightDMGreeterClass *klass)
      * resettable using lightdm_greeter_set_resettable().
      **/
     signals[IDLE] =
-        g_signal_new ("idle",
+        g_signal_new (LIGHTDM_GREETER_SIGNAL_IDLE,
                       G_TYPE_FROM_CLASS (klass),
                       G_SIGNAL_RUN_LAST,
                       G_STRUCT_OFFSET (LightDMGreeterClass, idle),
@@ -1679,7 +1935,7 @@ lightdm_greeter_class_init (LightDMGreeterClass *klass)
      * resettable using lightdm_greeter_set_resettable().
      **/
     signals[RESET] =
-        g_signal_new ("reset",
+        g_signal_new (LIGHTDM_GREETER_SIGNAL_RESET,
                       G_TYPE_FROM_CLASS (klass),
                       G_SIGNAL_RUN_LAST,
                       G_STRUCT_OFFSET (LightDMGreeterClass, reset),
@@ -1699,6 +1955,7 @@ request_finalize (GObject *object)
     Request *request = REQUEST (object);
 
     g_free (request->dir);
+    g_clear_object (&request->cancellable);
 
     G_OBJECT_CLASS (request_parent_class)->finalize (object);
 }
@@ -1709,3 +1966,22 @@ request_class_init (RequestClass *klass)
     GObjectClass *object_class = G_OBJECT_CLASS (klass);
     object_class->finalize = request_finalize;
 }
+
+static gpointer
+request_get_user_data (GAsyncResult *result)
+{
+    return REQUEST (result)->user_data;
+}
+
+static GObject *
+request_get_source_object (GAsyncResult *res)
+{
+    return NULL;
+}
+
+static void
+request_iface_init (GAsyncResultIface *iface)
+{
+    iface->get_user_data = request_get_user_data;
+    iface->get_source_object = request_get_source_object;
+}