Back to index

lightdm  1.3.2
greeter.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010-2011 Robert Ancell.
00003  * Author: Robert Ancell <robert.ancell@canonical.com>
00004  * 
00005  * This program is free software: you can redistribute it and/or modify it under
00006  * the terms of the GNU General Public License as published by the Free Software
00007  * Foundation, either version 3 of the License, or (at your option) any later
00008  * version. See http://www.gnu.org/copyleft/gpl.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 <errno.h>
00017 #include <fcntl.h>
00018 
00019 #include "greeter.h"
00020 #include "ldm-marshal.h"
00021 
00022 enum {
00023     CONNECTED,
00024     START_AUTHENTICATION,
00025     START_SESSION,
00026     LAST_SIGNAL
00027 };
00028 static guint signals[LAST_SIGNAL] = { 0 };
00029 
00030 struct GreeterPrivate
00031 {
00032     /* Session running on */
00033     Session *session;
00034 
00035     /* PAM service to authenticate with */
00036     gchar *pam_service;
00037 
00038     /* Buffer for data read from greeter */
00039     guint8 *read_buffer;
00040     gsize n_read;
00041   
00042     /* Hints for the greeter */
00043     GHashTable *hints;
00044 
00045     /* Default session to use */   
00046     gchar *default_session;
00047 
00048     /* Sequence number of current PAM session */
00049     guint32 authentication_sequence_number;
00050 
00051     /* PAM session being constructed by the greeter */
00052     Session *authentication_session;
00053 
00054     /* TRUE if a user has been authenticated and the session requested to start */
00055     gboolean start_session;
00056 
00057     /* TRUE if can log into guest accounts */
00058     gboolean allow_guest;
00059 
00060     /* TRUE if logging into guest session */
00061     gboolean guest_account_authenticated;
00062 
00063     /* Communication channels to communicate with */
00064     GIOChannel *to_greeter_channel;
00065     GIOChannel *from_greeter_channel;
00066 };
00067 
00068 G_DEFINE_TYPE (Greeter, greeter, G_TYPE_OBJECT);
00069 
00070 /* Messages from the greeter to the server */
00071 typedef enum
00072 {
00073     GREETER_MESSAGE_CONNECT = 0,
00074     GREETER_MESSAGE_AUTHENTICATE,
00075     GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
00076     GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
00077     GREETER_MESSAGE_START_SESSION,
00078     GREETER_MESSAGE_CANCEL_AUTHENTICATION,
00079     GREETER_MESSAGE_SET_LANGUAGE
00080 } GreeterMessage;
00081 
00082 /* Messages from the server to the greeter */
00083 typedef enum
00084 {
00085     SERVER_MESSAGE_CONNECTED = 0,
00086     SERVER_MESSAGE_PROMPT_AUTHENTICATION,
00087     SERVER_MESSAGE_END_AUTHENTICATION,
00088     SERVER_MESSAGE_SESSION_RESULT
00089 } ServerMessage;
00090 
00091 static gboolean read_cb (GIOChannel *source, GIOCondition condition, gpointer data);
00092 
00093 Greeter *
00094 greeter_new (Session *session, const gchar *pam_service)
00095 {
00096     Greeter *greeter;
00097 
00098     greeter = g_object_new (GREETER_TYPE, NULL);
00099     greeter->priv->session = g_object_ref (session);
00100     greeter->priv->pam_service = g_strdup (pam_service);
00101 
00102     return greeter;
00103 }
00104 
00105 void
00106 greeter_set_allow_guest (Greeter *greeter, gboolean allow_guest)
00107 {
00108     greeter->priv->allow_guest = allow_guest;
00109 }
00110 
00111 void
00112 greeter_set_hint (Greeter *greeter, const gchar *name, const gchar *value)
00113 {
00114     g_hash_table_insert (greeter->priv->hints, g_strdup (name), g_strdup (value));
00115 }
00116 
00117 static guint32
00118 int_length ()
00119 {
00120     return 4;
00121 }
00122 
00123 #define HEADER_SIZE (sizeof (guint32) * 2)
00124 #define MAX_MESSAGE_LENGTH 1024
00125 
00126 static void
00127 write_message (Greeter *greeter, guint8 *message, gsize message_length)
00128 {
00129     GError *error = NULL;
00130 
00131     g_io_channel_write_chars (greeter->priv->to_greeter_channel, (gchar *) message, message_length, NULL, &error);
00132     if (error)
00133         g_warning ("Error writing to greeter: %s", error->message);
00134     g_clear_error (&error);
00135     g_io_channel_flush (greeter->priv->to_greeter_channel, NULL);
00136 }
00137 
00138 static void
00139 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
00140 {
00141     if (*offset + 4 >= buffer_length)
00142         return;
00143     buffer[*offset] = value >> 24;
00144     buffer[*offset+1] = (value >> 16) & 0xFF;
00145     buffer[*offset+2] = (value >> 8) & 0xFF;
00146     buffer[*offset+3] = value & 0xFF;
00147     *offset += 4;
00148 }
00149 
00150 static void
00151 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
00152 {
00153     gint length;
00154   
00155     if (value)
00156         length = strlen (value);
00157     else
00158         length = 0;
00159     write_int (buffer, buffer_length, length, offset);
00160     if (*offset + length >= buffer_length)
00161         return;
00162     if (length > 0)
00163     {
00164         memcpy (buffer + *offset, value, length);
00165         *offset += length;
00166     }
00167 }
00168 
00169 static void
00170 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
00171 {
00172     write_int (buffer, buffer_length, id, offset);
00173     write_int (buffer, buffer_length, length, offset);
00174 }
00175 
00176 static guint32
00177 string_length (const gchar *value)
00178 {
00179     if (value == NULL)
00180         return int_length ();
00181     else
00182         return int_length () + strlen (value);
00183 }
00184 
00185 static void
00186 handle_connect (Greeter *greeter, const gchar *version)
00187 {
00188     guint8 message[MAX_MESSAGE_LENGTH];
00189     gsize offset = 0;
00190     guint32 length;
00191     GHashTableIter iter;
00192     gpointer key, value;
00193 
00194     g_debug ("Greeter connected version=%s", version);
00195 
00196     length = string_length (VERSION);
00197     g_hash_table_iter_init (&iter, greeter->priv->hints);
00198     while (g_hash_table_iter_next (&iter, &key, &value))
00199         length += string_length (key) + string_length (value);
00200 
00201     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_CONNECTED, length, &offset);
00202     write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
00203     g_hash_table_iter_init (&iter, greeter->priv->hints);
00204     while (g_hash_table_iter_next (&iter, &key, &value))
00205     {
00206         write_string (message, MAX_MESSAGE_LENGTH, key, &offset);
00207         write_string (message, MAX_MESSAGE_LENGTH, value, &offset);
00208     }
00209     write_message (greeter, message, offset);
00210 
00211     g_signal_emit (greeter, signals[CONNECTED], 0);
00212 }
00213 
00214 static void
00215 pam_messages_cb (Session *session, Greeter *greeter)
00216 {
00217     int i;
00218     guint32 size;
00219     guint8 message[MAX_MESSAGE_LENGTH];
00220     const struct pam_message *messages;
00221     int messages_length;
00222     gsize offset = 0;
00223     int n_prompts = 0;
00224 
00225     messages = session_get_messages (session);
00226     messages_length = session_get_messages_length (session);
00227 
00228     /* Respond to d-bus query with messages */
00229     g_debug ("Prompt greeter with %d message(s)", messages_length);
00230     size = int_length () + string_length (session_get_username (session)) + int_length ();
00231     for (i = 0; i < messages_length; i++)
00232         size += int_length () + string_length (messages[i].msg);
00233   
00234     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_PROMPT_AUTHENTICATION, size, &offset);
00235     write_int (message, MAX_MESSAGE_LENGTH, greeter->priv->authentication_sequence_number, &offset);
00236     write_string (message, MAX_MESSAGE_LENGTH, session_get_username (session), &offset);
00237     write_int (message, MAX_MESSAGE_LENGTH, messages_length, &offset);
00238     for (i = 0; i < messages_length; i++)
00239     {
00240         write_int (message, MAX_MESSAGE_LENGTH, messages[i].msg_style, &offset);
00241         write_string (message, MAX_MESSAGE_LENGTH, messages[i].msg, &offset);
00242 
00243         if (messages[i].msg_style == PAM_PROMPT_ECHO_OFF || messages[i].msg_style == PAM_PROMPT_ECHO_ON)
00244             n_prompts++;
00245     }
00246     write_message (greeter, message, offset);
00247 
00248     /* Continue immediately if nothing to respond with */
00249     // FIXME: Should probably give the greeter a chance to ack the message
00250     if (n_prompts == 0)
00251     {
00252         struct pam_response *response;
00253         response = calloc (messages_length, sizeof (struct pam_response));
00254         session_respond (greeter->priv->authentication_session, response);
00255     }
00256 }
00257 
00258 static void
00259 send_end_authentication (Greeter *greeter, guint32 sequence_number, const gchar *username, int result)
00260 {
00261     guint8 message[MAX_MESSAGE_LENGTH];
00262     gsize offset = 0;
00263 
00264     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_END_AUTHENTICATION, int_length () + string_length (username) + int_length (), &offset);
00265     write_int (message, MAX_MESSAGE_LENGTH, sequence_number, &offset);
00266     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
00267     write_int (message, MAX_MESSAGE_LENGTH, result, &offset);
00268     write_message (greeter, message, offset); 
00269 }
00270 
00271 static void
00272 authentication_complete_cb (Session *session, Greeter *greeter)
00273 {
00274     int result;
00275 
00276     g_debug ("Authenticate result for user %s: %s", session_get_username (session), session_get_authentication_result_string (session));
00277 
00278     result = session_get_authentication_result (session);
00279     if (session_get_is_authenticated (session))
00280     {
00281         if (session_get_user (session))
00282             g_debug ("User %s authorized", session_get_username (session));
00283         else
00284         {
00285             g_debug ("User %s authorized, but no account of that name exists", session_get_username (session));          
00286             result = PAM_USER_UNKNOWN;
00287         }
00288     }
00289 
00290     send_end_authentication (greeter, greeter->priv->authentication_sequence_number, session_get_username (session), result);
00291 }
00292 
00293 static void
00294 reset_session (Greeter *greeter)
00295 {
00296     if (greeter->priv->authentication_session)
00297     {
00298         g_signal_handlers_disconnect_matched (greeter->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, greeter);
00299         session_stop (greeter->priv->authentication_session);
00300         g_object_unref (greeter->priv->authentication_session);
00301         greeter->priv->authentication_session = NULL;
00302     }
00303 
00304     greeter->priv->guest_account_authenticated = FALSE;
00305 }
00306 
00307 static void
00308 handle_login (Greeter *greeter, guint32 sequence_number, const gchar *username)
00309 {
00310     if (username[0] == '\0')
00311     {
00312         g_debug ("Greeter start authentication");
00313         username = NULL;
00314     }
00315     else
00316         g_debug ("Greeter start authentication for %s", username);
00317 
00318     reset_session (greeter);
00319 
00320     greeter->priv->authentication_sequence_number = sequence_number;
00321     g_signal_emit (greeter, signals[START_AUTHENTICATION], 0, username, &greeter->priv->authentication_session);
00322     if (!greeter->priv->authentication_session)
00323     {
00324         send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN);
00325         return;
00326     }
00327 
00328     g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "got-messages", G_CALLBACK (pam_messages_cb), greeter);
00329     g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "authentication-complete", G_CALLBACK (authentication_complete_cb), greeter);
00330 
00331     /* Run the session process */
00332     session_start (greeter->priv->authentication_session, greeter->priv->pam_service, username, TRUE, TRUE);
00333 }
00334 
00335 static void
00336 handle_login_as_guest (Greeter *greeter, guint32 sequence_number)
00337 {
00338     g_debug ("Greeter start authentication for guest account");
00339 
00340     reset_session (greeter);
00341 
00342     if (!greeter->priv->allow_guest)
00343     {
00344         g_debug ("Guest account is disabled");
00345         send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN);
00346         return;
00347     }
00348 
00349     greeter->priv->guest_account_authenticated = TRUE;  
00350     send_end_authentication (greeter, sequence_number, "", PAM_SUCCESS);
00351 }
00352 
00353 static void
00354 handle_continue_authentication (Greeter *greeter, gchar **secrets)
00355 {
00356     int messages_length;
00357     const struct pam_message *messages;
00358     struct pam_response *response;
00359     int i, j, n_prompts = 0;
00360 
00361     /* Not in authentication */
00362     if (greeter->priv->authentication_session == NULL)
00363         return;
00364 
00365     messages_length = session_get_messages_length (greeter->priv->authentication_session);
00366     messages = session_get_messages (greeter->priv->authentication_session);
00367 
00368     /* Check correct number of responses */
00369     for (i = 0; i < messages_length; i++)
00370     {
00371         int msg_style = messages[i].msg_style;
00372         if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
00373             n_prompts++;
00374     }
00375     if (g_strv_length (secrets) != n_prompts)
00376     {
00377         session_respond_error (greeter->priv->authentication_session, PAM_CONV_ERR);
00378         return;
00379     }
00380 
00381     g_debug ("Continue authentication");
00382 
00383     /* Build response */
00384     response = calloc (messages_length, sizeof (struct pam_response));
00385     for (i = 0, j = 0; i < messages_length; i++)
00386     {
00387         int msg_style = messages[i].msg_style;
00388         if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
00389         {
00390             response[i].resp = strdup (secrets[j]); // FIXME: Need to convert from UTF-8
00391             j++;
00392         }
00393     }
00394 
00395     session_respond (greeter->priv->authentication_session, response);
00396 }
00397 
00398 static void
00399 handle_cancel_authentication (Greeter *greeter)
00400 {
00401     /* Not in authentication */
00402     if (greeter->priv->authentication_session == NULL)
00403         return;
00404 
00405     g_debug ("Cancel authentication");
00406     reset_session (greeter);
00407 }
00408 
00409 static void
00410 handle_start_session (Greeter *greeter, const gchar *session)
00411 {
00412     gboolean result;
00413     guint8 message[MAX_MESSAGE_LENGTH];
00414     gsize offset = 0;
00415 
00416     if (strcmp (session, "") == 0)
00417         session = NULL;
00418 
00419     if (greeter->priv->guest_account_authenticated || session_get_is_authenticated (greeter->priv->authentication_session))
00420     {
00421         if (session)
00422             g_debug ("Greeter requests session %s", session);
00423         else
00424             g_debug ("Greeter requests default session");
00425         greeter->priv->start_session = TRUE;
00426         g_signal_emit (greeter, signals[START_SESSION], 0, session, &result);
00427     }
00428     else
00429     {
00430         g_debug ("Ignoring start session request, user is not authorized");
00431         result = FALSE;
00432     }
00433 
00434     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_SESSION_RESULT, int_length (), &offset);
00435     write_int (message, MAX_MESSAGE_LENGTH, result ? 0 : 1, &offset);
00436     write_message (greeter, message, offset);
00437 }
00438 
00439 static void
00440 handle_set_language (Greeter *greeter, const gchar *language)
00441 {
00442     User *user;
00443 
00444     if (!greeter->priv->guest_account_authenticated && !session_get_is_authenticated (greeter->priv->authentication_session))
00445     {
00446         g_debug ("Ignoring set language request, user is not authorized");
00447         return;
00448     }
00449 
00450     // FIXME: Could use this
00451     if (greeter->priv->guest_account_authenticated)
00452     {
00453         g_debug ("Ignoring set language request for guest user");
00454         return;
00455     }
00456 
00457     g_debug ("Greeter sets language %s", language);
00458     user = session_get_user (greeter->priv->authentication_session);
00459     user_set_language (user, language);
00460 }
00461 
00462 static guint32
00463 read_int (Greeter *greeter, gsize *offset)
00464 {
00465     guint32 value;
00466     guint8 *buffer;
00467     if (greeter->priv->n_read - *offset < sizeof (guint32))
00468     {
00469         g_warning ("Not enough space for int, need %zu, got %zu", sizeof (guint32), greeter->priv->n_read - *offset);
00470         return 0;
00471     }
00472     buffer = greeter->priv->read_buffer + *offset;
00473     value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
00474     *offset += int_length ();
00475     return value;
00476 }
00477 
00478 static gchar *
00479 read_string (Greeter *greeter, gsize *offset)
00480 {
00481     guint32 length;
00482     gchar *value;
00483 
00484     length = read_int (greeter, offset);
00485     if (greeter->priv->n_read - *offset < length)
00486     {
00487         g_warning ("Not enough space for string, need %u, got %zu", length, greeter->priv->n_read - *offset);
00488         return g_strdup ("");
00489     }
00490 
00491     value = g_malloc (sizeof (gchar *) * (length + 1));
00492     memcpy (value, greeter->priv->read_buffer + *offset, length);
00493     value[length] = '\0';
00494     *offset += length;
00495 
00496     return value;
00497 }
00498 
00499 static gboolean
00500 read_cb (GIOChannel *source, GIOCondition condition, gpointer data)
00501 {
00502     Greeter *greeter = data;
00503     gsize n_to_read, n_read, offset;
00504     GIOStatus status;
00505     int id, n_secrets, i;
00506     guint32 sequence_number;
00507     gchar *version, *username, *session_name, *language;
00508     gchar **secrets;
00509     GError *error = NULL;
00510 
00511     if (condition == G_IO_HUP)
00512     {
00513         g_debug ("Greeter closed communication channel");
00514         return FALSE;
00515     }
00516   
00517     n_to_read = HEADER_SIZE;
00518     if (greeter->priv->n_read >= HEADER_SIZE)
00519     {
00520         offset = int_length ();
00521         n_to_read += read_int (greeter, &offset);
00522     }
00523 
00524     status = g_io_channel_read_chars (greeter->priv->from_greeter_channel,
00525                                       (gchar *) greeter->priv->read_buffer + greeter->priv->n_read,
00526                                       n_to_read - greeter->priv->n_read,
00527                                       &n_read,
00528                                       &error);
00529     if (error)
00530         g_warning ("Error reading from greeter: %s", error->message);
00531     g_clear_error (&error);
00532     if (status != G_IO_STATUS_NORMAL)
00533         return TRUE;
00534 
00535     greeter->priv->n_read += n_read;
00536     if (greeter->priv->n_read != n_to_read)
00537         return TRUE;
00538 
00539     /* If have header, rerun for content */
00540     if (greeter->priv->n_read == HEADER_SIZE)
00541     {
00542         gsize offset = int_length ();
00543         n_to_read = read_int (greeter, &offset);
00544         if (n_to_read > 0)
00545         {
00546             greeter->priv->read_buffer = g_realloc (greeter->priv->read_buffer, HEADER_SIZE + n_to_read);
00547             read_cb (source, condition, greeter);
00548             return TRUE;
00549         }
00550     }
00551   
00552     offset = 0;
00553     id = read_int (greeter, &offset);
00554     read_int (greeter, &offset);
00555     switch (id)
00556     {
00557     case GREETER_MESSAGE_CONNECT:
00558         version = read_string (greeter, &offset);
00559         handle_connect (greeter, version);
00560         g_free (version);
00561         break;
00562     case GREETER_MESSAGE_AUTHENTICATE:
00563         sequence_number = read_int (greeter, &offset);
00564         username = read_string (greeter, &offset);
00565         handle_login (greeter, sequence_number, username);
00566         g_free (username);
00567         break;
00568     case GREETER_MESSAGE_AUTHENTICATE_AS_GUEST:
00569         sequence_number = read_int (greeter, &offset);
00570         handle_login_as_guest (greeter, sequence_number);
00571         break;
00572     case GREETER_MESSAGE_CONTINUE_AUTHENTICATION:
00573         n_secrets = read_int (greeter, &offset);
00574         secrets = g_malloc (sizeof (gchar *) * (n_secrets + 1));
00575         for (i = 0; i < n_secrets; i++)
00576             secrets[i] = read_string (greeter, &offset);
00577         secrets[i] = NULL;
00578         handle_continue_authentication (greeter, secrets);
00579         g_strfreev (secrets);
00580         break;
00581     case GREETER_MESSAGE_CANCEL_AUTHENTICATION:
00582         handle_cancel_authentication (greeter);
00583         break;
00584     case GREETER_MESSAGE_START_SESSION:
00585         session_name = read_string (greeter, &offset);
00586         handle_start_session (greeter, session_name);
00587         g_free (session_name);
00588         break;
00589     case GREETER_MESSAGE_SET_LANGUAGE:
00590         language = read_string (greeter, &offset);
00591         handle_set_language (greeter, language);
00592         g_free (language);
00593         break;
00594     default:
00595         g_warning ("Unknown message from greeter: %d", id);
00596         break;
00597     }
00598 
00599     greeter->priv->n_read = 0;
00600 
00601     return TRUE;
00602 }
00603 
00604 gboolean
00605 greeter_get_guest_authenticated (Greeter *greeter)
00606 {
00607     g_return_val_if_fail (greeter != NULL, FALSE);
00608     return greeter->priv->guest_account_authenticated;
00609 }
00610 
00611 Session *
00612 greeter_get_authentication_session (Greeter *greeter)
00613 {
00614     g_return_val_if_fail (greeter != NULL, NULL);
00615     return greeter->priv->authentication_session;
00616 }
00617 
00618 gboolean
00619 greeter_get_start_session (Greeter *greeter)
00620 {
00621     g_return_val_if_fail (greeter != NULL, FALSE);
00622     return greeter->priv->start_session;
00623 }
00624 
00625 gboolean
00626 greeter_start (Greeter *greeter, const gchar *service, const gchar *username)
00627 {
00628     int to_greeter_pipe[2], from_greeter_pipe[2];
00629     gboolean result = FALSE;
00630     gchar *value;
00631 
00632     /* Create a pipe to talk with the greeter */
00633     if (pipe (to_greeter_pipe) != 0 || pipe (from_greeter_pipe) != 0)
00634     {
00635         g_warning ("Failed to create pipes: %s", strerror (errno));
00636         return FALSE;
00637     }
00638     greeter->priv->to_greeter_channel = g_io_channel_unix_new (to_greeter_pipe[1]);
00639     g_io_channel_set_encoding (greeter->priv->to_greeter_channel, NULL, NULL);
00640     greeter->priv->from_greeter_channel = g_io_channel_unix_new (from_greeter_pipe[0]);
00641     g_io_channel_set_encoding (greeter->priv->from_greeter_channel, NULL, NULL);
00642     g_io_channel_set_buffered (greeter->priv->from_greeter_channel, FALSE);
00643     g_io_add_watch (greeter->priv->from_greeter_channel, G_IO_IN | G_IO_HUP, read_cb, greeter);
00644 
00645     /* Let the greeter session know how to communicate with the daemon */
00646     value = g_strdup_printf ("%d", from_greeter_pipe[1]);
00647     session_set_env (greeter->priv->session, "LIGHTDM_TO_SERVER_FD", value);
00648     g_free (value);
00649     value = g_strdup_printf ("%d", to_greeter_pipe[0]);
00650     session_set_env (greeter->priv->session, "LIGHTDM_FROM_SERVER_FD", value);
00651     g_free (value);
00652 
00653     /* Don't allow the daemon end of the pipes to be accessed in child processes */
00654     fcntl (to_greeter_pipe[1], F_SETFD, FD_CLOEXEC);
00655     fcntl (from_greeter_pipe[0], F_SETFD, FD_CLOEXEC);
00656 
00657     result = session_start (greeter->priv->session, service, username, FALSE, FALSE);
00658 
00659     /* Close the session ends of the pipe */
00660     close (to_greeter_pipe[0]);
00661     close (from_greeter_pipe[1]);
00662 
00663     return result;
00664 }
00665 
00666 static Session *
00667 greeter_real_start_authentication (Greeter *greeter, const gchar *username)
00668 {
00669     return NULL;
00670 }
00671 
00672 static gboolean
00673 greeter_real_start_session (Greeter *greeter, const gchar *session, gboolean is_guest)
00674 {
00675     return FALSE;
00676 }
00677 
00678 static void
00679 greeter_init (Greeter *greeter)
00680 {
00681     greeter->priv = G_TYPE_INSTANCE_GET_PRIVATE (greeter, GREETER_TYPE, GreeterPrivate);
00682     greeter->priv->read_buffer = g_malloc (HEADER_SIZE);
00683     greeter->priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
00684 }
00685 
00686 static void
00687 greeter_finalize (GObject *object)
00688 {
00689     Greeter *self;
00690 
00691     self = GREETER (object);
00692 
00693     g_signal_handlers_disconnect_matched (self->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);    
00694     g_object_unref (self->priv->session);
00695     g_free (self->priv->pam_service);
00696     g_free (self->priv->read_buffer);
00697     g_hash_table_unref (self->priv->hints);
00698     if (self->priv->authentication_session)
00699     {
00700         g_signal_handlers_disconnect_matched (self->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
00701         g_object_unref (self->priv->authentication_session);
00702     }
00703     if (self->priv->to_greeter_channel)
00704         g_io_channel_unref (self->priv->to_greeter_channel);
00705     if (self->priv->from_greeter_channel)
00706         g_io_channel_unref (self->priv->from_greeter_channel);
00707 
00708     G_OBJECT_CLASS (greeter_parent_class)->finalize (object);
00709 }
00710 
00711 static void
00712 greeter_class_init (GreeterClass *klass)
00713 {
00714     GObjectClass *object_class = G_OBJECT_CLASS (klass);
00715 
00716     klass->start_authentication = greeter_real_start_authentication;
00717     klass->start_session = greeter_real_start_session;
00718     object_class->finalize = greeter_finalize;
00719 
00720     signals[CONNECTED] =
00721         g_signal_new ("connected",
00722                       G_TYPE_FROM_CLASS (klass),
00723                       G_SIGNAL_RUN_LAST,
00724                       G_STRUCT_OFFSET (GreeterClass, connected),
00725                       NULL, NULL,
00726                       g_cclosure_marshal_VOID__VOID,
00727                       G_TYPE_NONE, 0);
00728 
00729     signals[START_AUTHENTICATION] =
00730         g_signal_new ("start-authentication",
00731                       G_TYPE_FROM_CLASS (klass),
00732                       G_SIGNAL_RUN_LAST,
00733                       G_STRUCT_OFFSET (GreeterClass, start_authentication),
00734                       g_signal_accumulator_first_wins,
00735                       NULL,
00736                       ldm_marshal_OBJECT__STRING,
00737                       SESSION_TYPE, 1, G_TYPE_STRING);
00738 
00739     signals[START_SESSION] =
00740         g_signal_new ("start-session",
00741                       G_TYPE_FROM_CLASS (klass),
00742                       G_SIGNAL_RUN_LAST,
00743                       G_STRUCT_OFFSET (GreeterClass, start_session),
00744                       g_signal_accumulator_true_handled,
00745                       NULL,
00746                       ldm_marshal_BOOLEAN__STRING,
00747                       G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
00748 
00749     g_type_class_add_private (klass, sizeof (GreeterPrivate));
00750 }