Back to index

lightdm  1.3.2
greeter.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010 Robert Ancell.
00003  * Author: Robert Ancell <robert.ancell@canonical.com>
00004  *
00005  * This library is free software; you can redistribute it and/or modify it under
00006  * the terms of the GNU Lesser General Public License as published by the Free
00007  * Software Foundation; either version 3 of the License, or (at your option) any
00008  * later version. See http://www.gnu.org/copyleft/lgpl.html the full text of the
00009  * license.
00010  */
00011 
00012 #include <config.h>
00013 
00014 #include <stdlib.h>
00015 #include <string.h>
00016 #include <security/pam_appl.h>
00017 
00018 #include "lightdm/greeter.h"
00019 
00020 enum {
00021     PROP_0,
00022     PROP_DEFAULT_SESSION_HINT,
00023     PROP_HIDE_USERS_HINT,
00024     PROP_SHOW_MANUAL_LOGIN_HINT,
00025     PROP_LOCK_HINT,
00026     PROP_HAS_GUEST_ACCOUNT_HINT,
00027     PROP_SELECT_USER_HINT,
00028     PROP_SELECT_GUEST_HINT,
00029     PROP_AUTOLOGIN_USER_HINT,
00030     PROP_AUTOLOGIN_GUEST_HINT,
00031     PROP_AUTOLOGIN_TIMEOUT_HINT,
00032     PROP_AUTHENTICATION_USER,
00033     PROP_IN_AUTHENTICATION,
00034     PROP_IS_AUTHENTICATED,
00035 };
00036 
00037 enum {
00038     SHOW_PROMPT,
00039     SHOW_MESSAGE,
00040     AUTHENTICATION_COMPLETE,
00041     AUTOLOGIN_TIMER_EXPIRED,
00042     LAST_SIGNAL
00043 };
00044 static guint signals[LAST_SIGNAL] = { 0 };
00045 
00046 typedef struct
00047 {
00048     gboolean connected;
00049 
00050     GIOChannel *to_server_channel, *from_server_channel;
00051     guint8 *read_buffer;
00052     gsize n_read;
00053 
00054     GHashTable *hints;
00055     guint autologin_timeout;
00056 
00057     gchar *authentication_user;
00058     gboolean in_authentication;
00059     gboolean is_authenticated;
00060     guint32 authenticate_sequence_number;
00061     gboolean cancelling_authentication;
00062 } LightDMGreeterPrivate;
00063 
00064 G_DEFINE_TYPE (LightDMGreeter, lightdm_greeter, G_TYPE_OBJECT);
00065 
00066 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_GREETER, LightDMGreeterPrivate)
00067 
00068 #define HEADER_SIZE 8
00069 #define MAX_MESSAGE_LENGTH 1024
00070 
00071 /* Messages from the greeter to the server */
00072 typedef enum
00073 {
00074     GREETER_MESSAGE_CONNECT = 0,
00075     GREETER_MESSAGE_AUTHENTICATE,
00076     GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
00077     GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
00078     GREETER_MESSAGE_START_SESSION,
00079     GREETER_MESSAGE_CANCEL_AUTHENTICATION,
00080     GREETER_MESSAGE_SET_LANGUAGE
00081 } GreeterMessage;
00082 
00083 /* Messages from the server to the greeter */
00084 typedef enum
00085 {
00086     SERVER_MESSAGE_CONNECTED = 0,
00087     SERVER_MESSAGE_PROMPT_AUTHENTICATION,
00088     SERVER_MESSAGE_END_AUTHENTICATION,
00089     SERVER_MESSAGE_SESSION_RESULT
00090 } ServerMessage;
00091 
00099 LightDMGreeter *
00100 lightdm_greeter_new ()
00101 {
00102     return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
00103 }
00104 
00105 static gboolean
00106 timed_login_cb (gpointer data)
00107 {
00108     LightDMGreeter *greeter = data;
00109     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
00110 
00111     priv->autologin_timeout = 0;
00112     g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
00113 
00114     return FALSE;
00115 }
00116 
00117 static guint32
00118 int_length ()
00119 {
00120     return 4;
00121 }
00122 
00123 static void
00124 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
00125 {
00126     if (*offset + 4 >= buffer_length)
00127         return;
00128     buffer[*offset] = value >> 24;
00129     buffer[*offset+1] = (value >> 16) & 0xFF;
00130     buffer[*offset+2] = (value >> 8) & 0xFF;
00131     buffer[*offset+3] = value & 0xFF;
00132     *offset += 4;
00133 }
00134 
00135 static void
00136 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
00137 {
00138     gint length = 0;
00139 
00140     if (value)
00141         length = strlen (value);
00142     write_int (buffer, buffer_length, length, offset);
00143     if (*offset + length >= buffer_length)
00144         return;
00145     memcpy (buffer + *offset, value, length);
00146     *offset += length;
00147 }
00148 
00149 static guint32
00150 read_int (guint8 *message, gsize message_length, gsize *offset)
00151 {
00152     guint32 value;
00153     guint8 *buffer;
00154 
00155     if (message_length - *offset < int_length ())
00156     {
00157         g_warning ("Not enough space for int, need %i, got %zi", int_length (), message_length - *offset);
00158         return 0;
00159     }
00160 
00161     buffer = message + *offset;
00162     value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
00163     *offset += int_length ();
00164 
00165     return value;
00166 }
00167 
00168 static gchar *
00169 read_string (guint8 *message, gsize message_length, gsize *offset)
00170 {
00171     guint32 length;
00172     gchar *value;
00173 
00174     length = read_int (message, message_length, offset);
00175     if (message_length - *offset < length)
00176     {
00177         g_warning ("Not enough space for string, need %u, got %zu", length, message_length - *offset);
00178         return g_strdup ("");
00179     }
00180 
00181     value = g_malloc (sizeof (gchar) * (length + 1));
00182     memcpy (value, message + *offset, length);
00183     value[length] = '\0';
00184     *offset += length;
00185 
00186     return value;
00187 }
00188 
00189 static guint32
00190 string_length (const gchar *value)
00191 {
00192     if (value)
00193         return int_length () + strlen (value);
00194     else
00195         return int_length ();
00196 }
00197 
00198 static void
00199 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
00200 {
00201     write_int (buffer, buffer_length, id, offset);
00202     write_int (buffer, buffer_length, length, offset);
00203 }
00204 
00205 static guint32
00206 get_message_length (guint8 *message, gsize message_length)
00207 {
00208     gsize offset = 4;
00209     return read_int (message, message_length, &offset);
00210 }
00211 
00212 static void
00213 write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
00214 {
00215     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
00216     GIOStatus status;
00217     GError *error = NULL;
00218     guint32 stated_length;
00219 
00220     /* Double check that we're sending well-formed messages.  If we say we're
00221        sending more than we do, we end up DOS'ing lightdm as it waits for the
00222        rest.  If we say we're sending less than we do, we confuse the heck out
00223        of lightdm, as it starts reading headers from the middle of our
00224        messages. */
00225     stated_length = HEADER_SIZE + get_message_length (message, message_length);
00226     if (stated_length != message_length)
00227     {
00228         g_warning ("Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu", stated_length, message_length);
00229         return;
00230     }
00231 
00232     status = g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, &error);
00233     if (error)
00234         g_warning ("Error writing to daemon: %s", error->message);
00235     g_clear_error (&error);
00236     if (status == G_IO_STATUS_NORMAL)
00237         g_debug ("Wrote %zi bytes to daemon", message_length);
00238     g_io_channel_flush (priv->to_server_channel, NULL);
00239 }
00240 
00241 static void
00242 handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
00243 {
00244     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
00245     gchar *version;
00246     GString *hint_string;
00247     int timeout;
00248 
00249     version = read_string (message, message_length, offset);
00250     hint_string = g_string_new ("");
00251     while (*offset < message_length)
00252     {
00253         gchar *name, *value;
00254       
00255         name = read_string (message, message_length, offset);
00256         value = read_string (message, message_length, offset);
00257         g_hash_table_insert (priv->hints, name, value);
00258         g_string_append_printf (hint_string, " %s=%s", name, value);
00259     }
00260 
00261     g_debug ("Connected version=%s%s", version, hint_string->str);
00262     g_free (version);
00263     g_string_free (hint_string, TRUE);
00264 
00265     /* Set timeout for default login */
00266     timeout = lightdm_greeter_get_autologin_timeout_hint (greeter);
00267     if (timeout)
00268     {
00269         g_debug ("Setting autologin timer for %d seconds", timeout);
00270         priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
00271     }
00272 }
00273 
00274 static void
00275 handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
00276 {
00277     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
00278     guint32 sequence_number, n_messages, i;
00279     gchar *username;
00280 
00281     sequence_number = read_int (message, message_length, offset);
00282     if (sequence_number != priv->authenticate_sequence_number)
00283     {
00284         g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
00285         return;
00286     }
00287 
00288     if (priv->cancelling_authentication)
00289     {
00290         g_debug ("Ignoring prompt authentication as waiting for it to cancel");
00291         return;
00292     }
00293 
00294     /* Update username */
00295     username = read_string (message, message_length, offset);
00296     if (strcmp (username, "") == 0)
00297     {
00298         g_free (username);
00299         username = NULL;
00300     }
00301     g_free (priv->authentication_user);
00302     priv->authentication_user = username;
00303 
00304     n_messages = read_int (message, message_length, offset);
00305     g_debug ("Prompt user with %d message(s)", n_messages);
00306 
00307     for (i = 0; i < n_messages; i++)
00308     {
00309         int style;
00310         gchar *text;
00311 
00312         style = read_int (message, message_length, offset);
00313         text = read_string (message, message_length, offset);
00314 
00315         // FIXME: Should stop on prompts?
00316         switch (style)
00317         {
00318         case PAM_PROMPT_ECHO_OFF:
00319             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_SECRET);
00320             break;
00321         case PAM_PROMPT_ECHO_ON:
00322             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_QUESTION);
00323             break;
00324         case PAM_ERROR_MSG:
00325             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_ERROR);
00326             break;
00327         case PAM_TEXT_INFO:
00328             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_INFO);
00329             break;
00330         }
00331 
00332         g_free (text);
00333     }
00334 }
00335 
00336 static void
00337 handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
00338 {
00339     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
00340     guint32 sequence_number, return_code;
00341     gchar *username;
00342 
00343     sequence_number = read_int (message, message_length, offset);
00344 
00345     if (sequence_number != priv->authenticate_sequence_number)
00346     {
00347         g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
00348         return;
00349     }
00350 
00351     username = read_string (message, message_length, offset);
00352     return_code = read_int (message, message_length, offset);
00353 
00354     g_debug ("Authentication complete for user %s with return code %d", username, return_code);
00355 
00356     /* Update username */
00357     if (strcmp (username, "") == 0)
00358     {
00359         g_free (username);
00360         username = NULL;
00361     }
00362     g_free (priv->authentication_user);
00363     priv->authentication_user = username;
00364 
00365     priv->cancelling_authentication = FALSE;
00366     priv->is_authenticated = (return_code == 0);
00367 
00368     priv->in_authentication = FALSE;
00369     g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
00370 }
00371 
00372 static guint8 *
00373 read_message (LightDMGreeter *greeter, gsize *length, gboolean block)
00374 {
00375     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
00376     gsize n_to_read, n_read;
00377     guint8 *buffer;
00378     GError *error = NULL;
00379 
00380     /* Read the header, or the whole message if we already have that */
00381     n_to_read = HEADER_SIZE;
00382     if (priv->n_read >= HEADER_SIZE)
00383         n_to_read += get_message_length (priv->read_buffer, priv->n_read);
00384 
00385     do
00386     {
00387         GIOStatus status;
00388         status = g_io_channel_read_chars (priv->from_server_channel,
00389                                           (gchar *) priv->read_buffer + priv->n_read,
00390                                           n_to_read - priv->n_read,
00391                                           &n_read,
00392                                           &error);
00393         if (error)
00394             g_warning ("Error reading from server: %s", error->message);
00395         g_clear_error (&error);
00396         if (status != G_IO_STATUS_NORMAL)
00397             break;
00398 
00399         g_debug ("Read %zi bytes from daemon", n_read);
00400 
00401         priv->n_read += n_read;
00402     } while (priv->n_read < n_to_read && block);
00403 
00404     /* Stop if haven't got all the data we want */
00405     if (priv->n_read != n_to_read)
00406         return FALSE;
00407 
00408     /* If have header, rerun for content */
00409     if (priv->n_read == HEADER_SIZE)
00410     {
00411         n_to_read = get_message_length (priv->read_buffer, priv->n_read);
00412         if (n_to_read > 0)
00413         {
00414             priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
00415             return read_message (greeter, length, block);
00416         }
00417     }
00418 
00419     buffer = priv->read_buffer;
00420     *length = priv->n_read;
00421 
00422     priv->read_buffer = g_malloc (priv->n_read);
00423     priv->n_read = 0;
00424 
00425     return buffer;
00426 }
00427 
00428 static gboolean
00429 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
00430 {
00431     LightDMGreeter *greeter = data;
00432     guint8 *message;
00433     gsize message_length, offset;
00434     guint32 id;
00435 
00436     message = read_message (greeter, &message_length, FALSE);
00437     if (!message)
00438         return TRUE;
00439 
00440     offset = 0;
00441     id = read_int (message, message_length, &offset);
00442     read_int (message, message_length, &offset);
00443     switch (id)
00444     {
00445     case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
00446         handle_prompt_authentication (greeter, message, message_length, &offset);
00447         break;
00448     case SERVER_MESSAGE_END_AUTHENTICATION:
00449         handle_end_authentication (greeter, message, message_length, &offset);
00450         break;
00451     default:
00452         g_warning ("Unknown message from server: %d", id);
00453         break;
00454     }
00455     g_free (message);
00456 
00457     return TRUE;
00458 }
00459 
00469 gboolean
00470 lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
00471 {
00472     LightDMGreeterPrivate *priv;
00473     const gchar *fd;
00474     guint8 message[MAX_MESSAGE_LENGTH];
00475     guint8 *response;
00476     gsize response_length, offset = 0;
00477     guint32 id;
00478 
00479     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
00480 
00481     priv = GET_PRIVATE (greeter);
00482 
00483     fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
00484     if (!fd)
00485     {
00486         g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
00487         return FALSE;
00488     }
00489     priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
00490     g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
00491 
00492     fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
00493     if (!fd)
00494     {
00495         g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
00496         return FALSE;
00497     }
00498     priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
00499     g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
00500     g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
00501 
00502     g_debug ("Connecting to display manager...");
00503     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
00504     write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
00505     write_message (greeter, message, offset);
00506 
00507     response = read_message (greeter, &response_length, TRUE);
00508     if (!response)
00509         return FALSE;
00510 
00511     offset = 0;
00512     id = read_int (response, response_length, &offset);
00513     read_int (response, response_length, &offset);
00514     if (id == SERVER_MESSAGE_CONNECTED)
00515         handle_connected (greeter, response, response_length, &offset);
00516     g_free (response);
00517     if (id != SERVER_MESSAGE_CONNECTED)
00518     {
00519         g_warning ("Expected CONNECTED message, got %d", id);
00520         return FALSE;
00521     }
00522 
00523     priv->connected = TRUE;
00524 
00525     return TRUE;
00526 }
00527 
00537 const gchar *
00538 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
00539 {
00540     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
00541     return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
00542 }
00543 
00552 const gchar *
00553 lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
00554 {
00555     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
00556     return lightdm_greeter_get_hint (greeter, "default-session");
00557 }
00558 
00573 gboolean
00574 lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
00575 {
00576     const gchar *value;
00577 
00578     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
00579     value = lightdm_greeter_get_hint (greeter, "hide-users");
00580 
00581     return g_strcmp0 (value, "true") == 0;
00582 }
00583 
00595 gboolean
00596 lightdm_greeter_get_show_manual_login_hint (LightDMGreeter *greeter)
00597 {
00598     const gchar *value;
00599 
00600     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
00601     value = lightdm_greeter_get_hint (greeter, "show-manual-login");
00602 
00603     return g_strcmp0 (value, "true") == 0;
00604 }
00605 
00614 gboolean
00615 lightdm_greeter_get_lock_hint (LightDMGreeter *greeter)
00616 {
00617     const gchar *value;
00618 
00619     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
00620     value = lightdm_greeter_get_hint (greeter, "lock-screen");
00621 
00622     return g_strcmp0 (value, "true") == 0;
00623 }
00624 
00633 gboolean
00634 lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
00635 {
00636     const gchar *value;
00637 
00638     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
00639     value = lightdm_greeter_get_hint (greeter, "has-guest-account");
00640   
00641     return g_strcmp0 (value, "true") == 0;
00642 }
00643 
00652 const gchar *
00653 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
00654 {
00655     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
00656     return lightdm_greeter_get_hint (greeter, "select-user");
00657 }
00658 
00667 gboolean
00668 lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
00669 {
00670     const gchar *value;
00671 
00672     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
00673     value = lightdm_greeter_get_hint (greeter, "select-guest");
00674   
00675     return g_strcmp0 (value, "true") == 0;
00676 }
00677 
00686 const gchar *
00687 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
00688 {
00689     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
00690     return lightdm_greeter_get_hint (greeter, "autologin-user");
00691 }
00692 
00701 gboolean
00702 lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
00703 {
00704     const gchar *value;
00705 
00706     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
00707     value = lightdm_greeter_get_hint (greeter, "autologin-guest");
00708   
00709     return g_strcmp0 (value, "true") == 0;
00710 }
00711 
00720 gint
00721 lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
00722 {
00723     const gchar *value;
00724     gint timeout = 0;
00725 
00726     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
00727     value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
00728     if (value)
00729         timeout = atoi (value);
00730     if (timeout < 0)
00731         timeout = 0;
00732 
00733     return timeout;
00734 }
00735 
00742 void
00743 lightdm_greeter_cancel_autologin (LightDMGreeter *greeter)
00744 {
00745     LightDMGreeterPrivate *priv;
00746 
00747     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
00748 
00749     priv = GET_PRIVATE (greeter);
00750 
00751     if (priv->autologin_timeout)
00752        g_source_remove (priv->autologin_timeout);
00753     priv->autologin_timeout = 0;
00754 }
00755 
00763 void
00764 lightdm_greeter_authenticate (LightDMGreeter *greeter, const char *username)
00765 {
00766     LightDMGreeterPrivate *priv;
00767     guint8 message[MAX_MESSAGE_LENGTH];
00768     gsize offset = 0;
00769 
00770     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
00771 
00772     priv = GET_PRIVATE (greeter);
00773 
00774     g_return_if_fail (priv->connected);
00775 
00776     priv->cancelling_authentication = FALSE;
00777     priv->authenticate_sequence_number++;
00778     priv->in_authentication = TRUE;  
00779     priv->is_authenticated = FALSE;
00780     if (username != priv->authentication_user)
00781     {
00782         g_free (priv->authentication_user);
00783         priv->authentication_user = g_strdup (username);
00784     }
00785 
00786     g_debug ("Starting authentication for user %s...", username);
00787     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset);
00788     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
00789     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
00790     write_message (greeter, message, offset);
00791 }
00792 
00799 void
00800 lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter)
00801 {
00802     LightDMGreeterPrivate *priv;
00803     guint8 message[MAX_MESSAGE_LENGTH];
00804     gsize offset = 0;
00805 
00806     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
00807 
00808     priv = GET_PRIVATE (greeter);
00809 
00810     g_return_if_fail (priv->connected);
00811 
00812     priv->cancelling_authentication = FALSE;
00813     priv->authenticate_sequence_number++;
00814     priv->in_authentication = TRUE;
00815     priv->is_authenticated = FALSE;
00816     g_free (priv->authentication_user);
00817     priv->authentication_user = NULL;
00818 
00819     g_debug ("Starting authentication for guest account...");
00820     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset);
00821     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
00822     write_message (greeter, message, offset);
00823 }
00824 
00832 void
00833 lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response)
00834 {
00835     LightDMGreeterPrivate *priv;
00836     guint8 message[MAX_MESSAGE_LENGTH];
00837     gsize offset = 0;
00838 
00839     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
00840     g_return_if_fail (response != NULL);
00841 
00842     priv = GET_PRIVATE (greeter);
00843 
00844     g_return_if_fail (priv->connected);
00845 
00846     g_debug ("Providing response to display manager");
00847     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, int_length () + string_length (response), &offset);
00848     // FIXME: Could be multiple responses required
00849     write_int (message, MAX_MESSAGE_LENGTH, 1, &offset);
00850     write_string (message, MAX_MESSAGE_LENGTH, response, &offset);
00851     write_message (greeter, message, offset);
00852 }
00853 
00860 void
00861 lightdm_greeter_cancel_authentication (LightDMGreeter *greeter)
00862 {
00863     LightDMGreeterPrivate *priv;
00864     guint8 message[MAX_MESSAGE_LENGTH];
00865     gsize offset = 0;
00866 
00867     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
00868 
00869     priv = GET_PRIVATE (greeter);
00870 
00871     g_return_if_fail (priv->connected);
00872 
00873     priv->cancelling_authentication = TRUE;
00874     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
00875     write_message (greeter, message, offset);
00876 }
00877 
00886 gboolean
00887 lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
00888 {
00889     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
00890     return GET_PRIVATE (greeter)->in_authentication;
00891 }
00892 
00901 gboolean
00902 lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
00903 {
00904     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
00905     return GET_PRIVATE (greeter)->is_authenticated;
00906 }
00907 
00916 const gchar *
00917 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
00918 {
00919     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
00920     return GET_PRIVATE (greeter)->authentication_user;
00921 }
00922 
00930 void
00931 lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language)
00932 {
00933     LightDMGreeterPrivate *priv;
00934     guint8 message[MAX_MESSAGE_LENGTH];
00935     gsize offset = 0;
00936 
00937     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
00938 
00939     priv = GET_PRIVATE (greeter);
00940 
00941     g_return_if_fail (priv->connected);
00942 
00943     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset);
00944     write_string (message, MAX_MESSAGE_LENGTH, language, &offset);
00945     write_message (greeter, message, offset);
00946 }
00947 
00958 gboolean
00959 lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
00960 {
00961     LightDMGreeterPrivate *priv;
00962     guint8 message[MAX_MESSAGE_LENGTH];
00963     guint8 *response;
00964     gsize response_length, offset = 0;
00965     guint32 id, return_code = 1;
00966 
00967     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
00968 
00969     priv = GET_PRIVATE (greeter);
00970 
00971     g_return_val_if_fail (priv->connected, FALSE);
00972     g_return_val_if_fail (priv->is_authenticated, FALSE);
00973 
00974     if (session)
00975         g_debug ("Starting session %s", session);
00976     else
00977         g_debug ("Starting default session");
00978 
00979     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
00980     write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
00981     write_message (greeter, message, offset);
00982 
00983     response = read_message (greeter, &response_length, TRUE);
00984     if (!response)
00985         return FALSE;
00986 
00987     offset = 0;
00988     id = read_int (response, response_length, &offset);
00989     read_int (response, response_length, &offset);
00990     if (id == SERVER_MESSAGE_SESSION_RESULT)
00991         return_code = read_int (response, response_length, &offset);
00992     else
00993         g_warning ("Expected SESSION_RESULT message, got %d", id);
00994 
00995     g_free (response);
00996 
00997     return return_code == 0;
00998 }
00999 
01000 static void
01001 lightdm_greeter_init (LightDMGreeter *greeter)
01002 {
01003     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
01004 
01005     priv->read_buffer = g_malloc (HEADER_SIZE);
01006     priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
01007 }
01008 
01009 static void
01010 lightdm_greeter_set_property (GObject      *object,
01011                           guint         prop_id,
01012                           const GValue *value,
01013                           GParamSpec   *pspec)
01014 {
01015     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01016 }
01017 
01018 static void
01019 lightdm_greeter_get_property (GObject    *object,
01020                           guint       prop_id,
01021                           GValue     *value,
01022                           GParamSpec *pspec)
01023 {
01024     LightDMGreeter *self;
01025 
01026     self = LIGHTDM_GREETER (object);
01027 
01028     switch (prop_id) {
01029     case PROP_DEFAULT_SESSION_HINT:
01030         g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
01031         break;
01032     case PROP_HIDE_USERS_HINT:
01033         g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
01034         break;
01035     case PROP_SHOW_MANUAL_LOGIN_HINT:
01036         g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
01037         break;
01038     case PROP_LOCK_HINT:
01039         g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
01040         break;
01041     case PROP_HAS_GUEST_ACCOUNT_HINT:
01042         g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
01043         break;
01044     case PROP_SELECT_USER_HINT:
01045         g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
01046         break;
01047     case PROP_SELECT_GUEST_HINT:
01048         g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
01049         break;
01050     case PROP_AUTOLOGIN_USER_HINT:
01051         g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
01052         break;
01053     case PROP_AUTOLOGIN_GUEST_HINT:
01054         g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
01055         break;
01056     case PROP_AUTOLOGIN_TIMEOUT_HINT:
01057         g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
01058         break;
01059     case PROP_AUTHENTICATION_USER:
01060         g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
01061         break;
01062     case PROP_IN_AUTHENTICATION:
01063         g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
01064         break;
01065     case PROP_IS_AUTHENTICATED:
01066         g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
01067         break;
01068     default:
01069         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01070         break;
01071     }
01072 }
01073 
01074 static void
01075 marshal_VOID__STRING_INT (GClosure     *closure,
01076                           GValue       *return_value G_GNUC_UNUSED,
01077                           guint         n_param_values,
01078                           const GValue *param_values,
01079                           gpointer      invocation_hint G_GNUC_UNUSED,
01080                           gpointer      marshal_data)
01081 {
01082     typedef void (*GMarshalFunc_VOID__STRING_INT) (gpointer     data1,
01083                                                    gpointer     arg_1,
01084                                                    gint         arg_2,
01085                                                    gpointer     data2);
01086     register GMarshalFunc_VOID__STRING_INT callback;
01087     register GCClosure *cc = (GCClosure*) closure;
01088     register gpointer data1, data2;
01089 
01090     g_return_if_fail (n_param_values == 3);
01091 
01092     if (G_CCLOSURE_SWAP_DATA (closure))
01093     {
01094         data1 = closure->data;
01095         data2 = g_value_peek_pointer (param_values + 0);
01096     }
01097     else
01098     {
01099         data1 = g_value_peek_pointer (param_values + 0);
01100         data2 = closure->data;
01101     }
01102     callback = (GMarshalFunc_VOID__STRING_INT) (marshal_data ? marshal_data : cc->callback);
01103 
01104     callback (data1,
01105               (param_values + 1)->data[0].v_pointer,
01106               (param_values + 2)->data[0].v_int,
01107               data2);
01108 }
01109 
01110 static void
01111 lightdm_greeter_finalize (GObject *object)
01112 {
01113     LightDMGreeter *self = LIGHTDM_GREETER (object);
01114     LightDMGreeterPrivate *priv = GET_PRIVATE (self);
01115 
01116     if (priv->to_server_channel)
01117         g_io_channel_unref (priv->to_server_channel);
01118     if (priv->from_server_channel)
01119         g_io_channel_unref (priv->from_server_channel);
01120     g_free (priv->authentication_user);
01121     g_hash_table_unref (priv->hints);
01122 
01123     G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
01124 }
01125 
01126 static void
01127 lightdm_greeter_class_init (LightDMGreeterClass *klass)
01128 {
01129     GObjectClass *object_class = G_OBJECT_CLASS (klass);
01130 
01131     g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
01132 
01133     object_class->set_property = lightdm_greeter_set_property;
01134     object_class->get_property = lightdm_greeter_get_property;
01135     object_class->finalize = lightdm_greeter_finalize;
01136 
01137     g_object_class_install_property (object_class,
01138                                      PROP_DEFAULT_SESSION_HINT,
01139                                      g_param_spec_string ("default-session-hint",
01140                                                           "default-session-hint",
01141                                                           "Default session hint",
01142                                                           NULL,
01143                                                           G_PARAM_READWRITE));
01144 
01145     g_object_class_install_property (object_class,
01146                                      PROP_HIDE_USERS_HINT,
01147                                      g_param_spec_boolean ("hide-users-hint",
01148                                                            "hide-users-hint",
01149                                                            "Hide users hint",
01150                                                            FALSE,
01151                                                            G_PARAM_READABLE));
01152 
01153     g_object_class_install_property (object_class,
01154                                      PROP_SHOW_MANUAL_LOGIN_HINT,
01155                                      g_param_spec_boolean ("show-manual-login-hint",
01156                                                            "show-manual-login-hint",
01157                                                            "Show manual login hint",
01158                                                            FALSE,
01159                                                            G_PARAM_READABLE));
01160 
01161     g_object_class_install_property (object_class,
01162                                      PROP_LOCK_HINT,
01163                                      g_param_spec_boolean ("lock-hint",
01164                                                            "lock-hint",
01165                                                            "Lock hint",
01166                                                            FALSE,
01167                                                            G_PARAM_READABLE));
01168 
01169     g_object_class_install_property (object_class,
01170                                      PROP_HAS_GUEST_ACCOUNT_HINT,
01171                                      g_param_spec_boolean ("has-guest-account-hint",
01172                                                            "has-guest-account-hint",
01173                                                            "Has guest account hint",
01174                                                            FALSE,
01175                                                            G_PARAM_READABLE));
01176 
01177     g_object_class_install_property (object_class,
01178                                      PROP_SELECT_USER_HINT,
01179                                      g_param_spec_string ("select-user-hint",
01180                                                           "select-user-hint",
01181                                                           "Select user hint",
01182                                                           NULL,
01183                                                           G_PARAM_READABLE));
01184 
01185     g_object_class_install_property (object_class,
01186                                      PROP_SELECT_GUEST_HINT,
01187                                      g_param_spec_boolean ("select-guest-hint",
01188                                                            "select-guest-hint",
01189                                                            "Select guest account hint",
01190                                                            FALSE,
01191                                                            G_PARAM_READABLE));
01192 
01193     g_object_class_install_property (object_class,
01194                                      PROP_AUTOLOGIN_USER_HINT,
01195                                      g_param_spec_string ("autologin-user-hint",
01196                                                           "autologin-user-hint",
01197                                                           "Autologin user hint",
01198                                                           NULL,
01199                                                           G_PARAM_READABLE));
01200 
01201     g_object_class_install_property (object_class,
01202                                      PROP_AUTOLOGIN_GUEST_HINT,
01203                                      g_param_spec_boolean ("autologin-guest-hint",
01204                                                            "autologin-guest-hint",
01205                                                            "Autologin guest account hint",
01206                                                            FALSE,
01207                                                            G_PARAM_READABLE));
01208 
01209     g_object_class_install_property (object_class,
01210                                      PROP_AUTOLOGIN_TIMEOUT_HINT,
01211                                      g_param_spec_int ("autologin-timeout-hint",
01212                                                        "autologin-timeout-hint",
01213                                                        "Autologin timeout hint",
01214                                                        0, G_MAXINT, 0,
01215                                                        G_PARAM_READABLE));
01216 
01217     g_object_class_install_property (object_class,
01218                                      PROP_AUTHENTICATION_USER,
01219                                      g_param_spec_string ("authentication-user",
01220                                                           "authentication-user",
01221                                                           "The user being authenticated",
01222                                                           NULL,
01223                                                           G_PARAM_READABLE));
01224     g_object_class_install_property (object_class,
01225                                      PROP_IN_AUTHENTICATION,
01226                                      g_param_spec_boolean ("in-authentication",
01227                                                            "in-authentication",
01228                                                            "TRUE if a user is being authenticated",
01229                                                            FALSE,
01230                                                            G_PARAM_READABLE));
01231     g_object_class_install_property (object_class,
01232                                      PROP_IS_AUTHENTICATED,
01233                                      g_param_spec_boolean ("is-authenticated",
01234                                                            "is-authenticated",
01235                                                            "TRUE if the selected user is authenticated",
01236                                                            FALSE,
01237                                                            G_PARAM_READABLE));
01238 
01252     signals[SHOW_PROMPT] =
01253         g_signal_new ("show-prompt",
01254                       G_TYPE_FROM_CLASS (klass),
01255                       G_SIGNAL_RUN_LAST,
01256                       G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
01257                       NULL, NULL,
01258                       marshal_VOID__STRING_INT,
01259                       G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
01260 
01270     signals[SHOW_MESSAGE] =
01271         g_signal_new ("show-message",
01272                       G_TYPE_FROM_CLASS (klass),
01273                       G_SIGNAL_RUN_LAST,
01274                       G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
01275                       NULL, NULL,
01276                       marshal_VOID__STRING_INT,
01277                       G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
01278 
01289     signals[AUTHENTICATION_COMPLETE] =
01290         g_signal_new ("authentication-complete",
01291                       G_TYPE_FROM_CLASS (klass),
01292                       G_SIGNAL_RUN_LAST,
01293                       G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
01294                       NULL, NULL,
01295                       g_cclosure_marshal_VOID__VOID,
01296                       G_TYPE_NONE, 0);
01297 
01305     signals[AUTOLOGIN_TIMER_EXPIRED] =
01306         g_signal_new ("autologin-timer-expired",
01307                       G_TYPE_FROM_CLASS (klass),
01308                       G_SIGNAL_RUN_LAST,
01309                       G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),
01310                       NULL, NULL,
01311                       g_cclosure_marshal_VOID__VOID,
01312                       G_TYPE_NONE, 0);
01313 }