]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - liblightdm-gobject/greeter.c
Rename ldm_greeter_provide_secret to ldm_greeter_respond - responses may not be secrets
[sojka/lightdm.git] / liblightdm-gobject / greeter.c
1 /*
2  * Copyright (C) 2010 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  *
5  * This library is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU Lesser General Public License as published by the Free
7  * Software Foundation; either version 3 of the License, or (at your option) any
8  * later version. See http://www.gnu.org/copyleft/lgpl.html the full text of the
9  * license.
10  */
11
12 #include <stdlib.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <locale.h>
16 #include <sys/utsname.h>
17 #include <pwd.h>
18 #include <gio/gdesktopappinfo.h>
19 #include <security/pam_appl.h>
20 #include <libxklavier/xklavier.h>
21
22 #include "lightdm/greeter.h"
23 #include "user-private.h"
24 #include "greeter-protocol.h"
25
26 enum {
27     PROP_0,
28     PROP_HOSTNAME,
29     PROP_NUM_USERS,
30     PROP_USERS,
31     PROP_DEFAULT_LANGUAGE,
32     PROP_LAYOUTS,
33     PROP_LAYOUT,
34     PROP_SESSIONS,
35     PROP_DEFAULT_SESSION,
36     PROP_TIMED_LOGIN_USER,
37     PROP_TIMED_LOGIN_DELAY,
38     PROP_AUTHENTICATION_USER,
39     PROP_IN_AUTHENTICATION,
40     PROP_IS_AUTHENTICATED,
41     PROP_CAN_SUSPEND,
42     PROP_CAN_HIBERNATE,
43     PROP_CAN_RESTART,
44     PROP_CAN_SHUTDOWN
45 };
46
47 enum {
48     CONNECTED,
49     SHOW_PROMPT,
50     SHOW_MESSAGE,
51     SHOW_ERROR,
52     AUTHENTICATION_COMPLETE,
53     TIMED_LOGIN,
54     USER_ADDED,
55     USER_CHANGED,
56     USER_REMOVED,
57     QUIT,
58     LAST_SIGNAL
59 };
60 static guint signals[LAST_SIGNAL] = { 0 };
61
62 struct _LdmGreeterPrivate
63 {
64     GDBusConnection *lightdm_bus;
65
66     GDBusConnection *system_bus;
67
68     GDBusProxy *lightdm_proxy;
69
70     GIOChannel *to_server_channel, *from_server_channel;
71     guint8 *read_buffer;
72     gsize n_read;
73
74     Display *display;
75
76     gchar *hostname;
77
78     /* Configuration file */
79     GKeyFile *config;
80
81     gchar *theme;
82     GKeyFile *theme_file;
83
84     /* File monitor for password file */
85     GFileMonitor *passwd_monitor;
86
87     /* TRUE if have scanned users */
88     gboolean have_users;
89
90     /* List of users */
91     GList *users;
92
93     gboolean have_languages;
94     GList *languages;
95
96     XklEngine *xkl_engine;
97     XklConfigRec *xkl_config;
98     gboolean have_layouts;
99     GList *layouts;
100     gchar *layout;
101
102     gboolean have_sessions;
103     GList *sessions;
104     gchar *default_session;
105
106     gchar *authentication_user;
107     gboolean in_authentication;
108     gboolean is_authenticated;
109
110     gchar *timed_user;
111     gint login_delay;
112     guint login_timeout;
113     gboolean guest_account_supported;
114     guint greeter_count;
115 };
116
117 G_DEFINE_TYPE (LdmGreeter, ldm_greeter, G_TYPE_OBJECT);
118
119 #define HEADER_SIZE 8
120 #define MAX_MESSAGE_LENGTH 1024
121
122 /**
123  * ldm_greeter_new:
124  *
125  * Create a new greeter.
126  *
127  * Return value: the new #LdmGreeter
128  **/
129 LdmGreeter *
130 ldm_greeter_new ()
131 {
132     return g_object_new (LDM_TYPE_GREETER, NULL);
133 }
134
135 static gboolean
136 timed_login_cb (gpointer data)
137 {
138     LdmGreeter *greeter = data;
139
140     greeter->priv->login_timeout = 0;
141     g_signal_emit (G_OBJECT (greeter), signals[TIMED_LOGIN], 0, greeter->priv->timed_user);
142
143     return FALSE;
144 }
145
146 static guint32
147 int_length ()
148 {
149     return 4;
150 }
151
152 static void
153 write_message (LdmGreeter *greeter, guint8 *message, gint message_length)
154 {
155     GError *error = NULL;
156     if (g_io_channel_write_chars (greeter->priv->to_server_channel, (gchar *) message, message_length, NULL, NULL) != G_IO_STATUS_NORMAL)
157         g_warning ("Error writing to daemon: %s", error->message);
158     g_clear_error (&error);
159     g_io_channel_flush (greeter->priv->to_server_channel, NULL);
160 }
161
162 static void
163 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
164 {
165     if (*offset + 4 >= buffer_length)
166         return;
167     buffer[*offset] = value >> 24;
168     buffer[*offset+1] = (value >> 16) & 0xFF;
169     buffer[*offset+2] = (value >> 8) & 0xFF;
170     buffer[*offset+3] = value & 0xFF;
171     *offset += 4;
172 }
173
174 static void
175 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
176 {
177     gint length = strlen (value);
178     write_int (buffer, buffer_length, length, offset);
179     if (*offset + length >= buffer_length)
180         return;
181     memcpy (buffer + *offset, value, length);
182     *offset += length;
183 }
184
185 static guint32
186 read_int (LdmGreeter *greeter, gsize *offset)
187 {
188     guint32 value;
189     guint8 *buffer;
190     if (greeter->priv->n_read - *offset < int_length ())
191     {
192         g_warning ("Not enough space for int, need %i, got %zi", int_length (), greeter->priv->n_read - *offset);
193         return 0;
194     }
195     buffer = greeter->priv->read_buffer + *offset;
196     value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
197     *offset += int_length ();
198     return value;
199 }
200
201 static gchar *
202 read_string (LdmGreeter *greeter, gsize *offset)
203 {
204     guint32 length;
205     gchar *value;
206
207     length = read_int (greeter, offset);
208     if (greeter->priv->n_read - *offset < length)
209     {
210         g_warning ("Not enough space for string, need %u, got %zu", length, greeter->priv->n_read - *offset);
211         return g_strdup ("");
212     }
213
214     value = g_malloc (sizeof (gchar) * (length + 1));
215     memcpy (value, greeter->priv->read_buffer + *offset, length);
216     value[length] = '\0';
217     *offset += length;
218
219     return value;
220 }
221
222 static guint32
223 string_length (const gchar *value)
224 {
225     return int_length () + strlen (value);
226 }
227
228 static void
229 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
230 {
231     write_int (buffer, buffer_length, id, offset);
232     write_int (buffer, buffer_length, length, offset);
233 }
234
235 static guint32 get_packet_length (LdmGreeter *greeter)
236 {
237     gsize offset = 4;
238     return read_int (greeter, &offset);
239 }
240
241 static void
242 handle_prompt_authentication (LdmGreeter *greeter, gsize *offset)
243 {
244     int n_messages, i;
245
246     n_messages = read_int (greeter, offset);
247     g_debug ("Prompt user with %d message(s)", n_messages);
248
249     for (i = 0; i < n_messages; i++)
250     {
251         int msg_style;
252         gchar *msg;
253
254         msg_style = read_int (greeter, offset);
255         msg = read_string (greeter, offset);
256
257         // FIXME: Should stop on prompts?
258         switch (msg_style)
259         {
260         case PAM_PROMPT_ECHO_OFF:
261         case PAM_PROMPT_ECHO_ON:
262             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, msg);
263             break;
264         case PAM_ERROR_MSG:
265             g_signal_emit (G_OBJECT (greeter), signals[SHOW_ERROR], 0, msg);
266             break;
267         case PAM_TEXT_INFO:
268             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, msg);
269             break;
270         }
271
272         g_free (msg);
273     }
274 }
275
276 static gboolean
277 read_packet (LdmGreeter *greeter, gboolean block)
278 {
279     gsize n_to_read, n_read;
280     GError *error = NULL;
281
282     /* Read the header, or the whole packet if we already have that */
283     n_to_read = HEADER_SIZE;
284     if (greeter->priv->n_read >= HEADER_SIZE)
285         n_to_read += get_packet_length (greeter);
286
287     do
288     {
289         GIOStatus status;
290         status = g_io_channel_read_chars (greeter->priv->from_server_channel,
291                                           (gchar *) greeter->priv->read_buffer + greeter->priv->n_read,
292                                           n_to_read - greeter->priv->n_read,
293                                           &n_read,
294                                           &error);
295         if (status == G_IO_STATUS_ERROR)
296             g_warning ("Error reading from server: %s", error->message);
297         g_clear_error (&error);
298         if (status != G_IO_STATUS_NORMAL)
299             break;
300
301         greeter->priv->n_read += n_read;
302     } while (greeter->priv->n_read < n_to_read && block);
303
304     /* Stop if haven't got all the data we want */
305     if (greeter->priv->n_read != n_to_read)
306         return FALSE;
307
308     /* If have header, rerun for content */
309     if (greeter->priv->n_read == HEADER_SIZE)
310     {
311         n_to_read = get_packet_length (greeter);
312         if (n_to_read > 0)
313         {
314             greeter->priv->read_buffer = g_realloc (greeter->priv->read_buffer, HEADER_SIZE + n_to_read);
315             return read_packet (greeter, block);
316         }
317     }
318
319     return TRUE;
320 }
321
322 static gboolean
323 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
324 {
325     LdmGreeter *greeter = data;
326     gsize offset;
327     guint32 id, return_code;
328   
329     if (!read_packet (greeter, FALSE))
330         return TRUE;
331
332     offset = 0;
333     id = read_int (greeter, &offset);
334     read_int (greeter, &offset);
335     switch (id)
336     {
337     case GREETER_MESSAGE_CONNECTED:
338         greeter->priv->theme = read_string (greeter, &offset);
339         greeter->priv->default_session = read_string (greeter, &offset);
340         greeter->priv->timed_user = read_string (greeter, &offset);
341         greeter->priv->login_delay = read_int (greeter, &offset);
342         greeter->priv->guest_account_supported = read_int (greeter, &offset) != 0;
343         greeter->priv->greeter_count = read_int (greeter, &offset);
344
345         g_debug ("Connected theme=%s default-session=%s timed-user=%s login-delay=%d guest-account-supported=%s greeter-count=%d",
346                  greeter->priv->theme,
347                  greeter->priv->default_session,
348                  greeter->priv->timed_user, greeter->priv->login_delay,
349                  greeter->priv->guest_account_supported ? "true" : "false",
350                  greeter->priv->greeter_count);
351
352         /* Set timeout for default login */
353         if (greeter->priv->timed_user[0] != '\0' && greeter->priv->login_delay > 0)
354         {
355             g_debug ("Logging in as %s in %d seconds", greeter->priv->timed_user, greeter->priv->login_delay);
356             greeter->priv->login_timeout = g_timeout_add (greeter->priv->login_delay * 1000, timed_login_cb, greeter);
357         }
358         g_signal_emit (G_OBJECT (greeter), signals[CONNECTED], 0);
359         break;
360     case GREETER_MESSAGE_QUIT:
361         g_debug ("Got quit request from server");
362         g_signal_emit (G_OBJECT (greeter), signals[QUIT], 0);
363         break;
364     case GREETER_MESSAGE_PROMPT_AUTHENTICATION:
365         handle_prompt_authentication (greeter, &offset);
366         break;
367     case GREETER_MESSAGE_END_AUTHENTICATION:
368         return_code = read_int (greeter, &offset);
369         g_debug ("Authentication complete with return code %d", return_code);
370         greeter->priv->is_authenticated = (return_code == 0);
371         if (!greeter->priv->is_authenticated)
372         {
373             g_free (greeter->priv->authentication_user);
374             greeter->priv->authentication_user = NULL;
375         }
376         g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
377         greeter->priv->in_authentication = FALSE;
378         break;
379     default:
380         g_warning ("Unknown message from server: %d", id);
381         break;
382     }
383
384     greeter->priv->n_read = 0;
385
386     return TRUE;
387 }
388
389 /**
390  * ldm_greeter_connect_to_server:
391  * @greeter: The greeter to connect
392  *
393  * Connects the greeter to the display manager.
394  *
395  * Return value: TRUE if successfully connected
396  **/
397 gboolean
398 ldm_greeter_connect_to_server (LdmGreeter *greeter)
399 {
400     GError *error = NULL;
401     const gchar *bus_address, *fd;
402     guint8 message[MAX_MESSAGE_LENGTH];
403     gsize offset = 0;
404     GBusType bus_type = G_BUS_TYPE_SYSTEM;
405
406     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
407
408     greeter->priv->system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
409     if (!greeter->priv->system_bus)
410         g_warning ("Failed to connect to system bus: %s", error->message);
411     g_clear_error (&error);
412
413     bus_address = getenv ("LDM_BUS");
414     if (bus_address && strcmp (bus_address, "SESSION") == 0)
415         bus_type = G_BUS_TYPE_SESSION;
416
417     greeter->priv->lightdm_bus = g_bus_get_sync (bus_type, NULL, &error);
418     if (!greeter->priv->lightdm_bus)
419         g_warning ("Failed to connect to LightDM bus: %s", error->message);
420     g_clear_error (&error);
421     if (!greeter->priv->lightdm_bus)
422         return FALSE;
423
424     fd = getenv ("LDM_TO_SERVER_FD");
425     if (!fd)
426     {
427         g_warning ("No LDM_TO_SERVER_FD environment variable");
428         return FALSE;
429     }
430     greeter->priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
431     g_io_channel_set_encoding (greeter->priv->to_server_channel, NULL, NULL);
432
433     fd = getenv ("LDM_FROM_SERVER_FD");
434     if (!fd)
435     {
436         g_warning ("No LDM_FROM_SERVER_FD environment variable");
437         return FALSE;
438     }
439     greeter->priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
440     g_io_channel_set_encoding (greeter->priv->from_server_channel, NULL, NULL);
441     g_io_add_watch (greeter->priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
442
443     greeter->priv->lightdm_proxy = g_dbus_proxy_new_sync (greeter->priv->lightdm_bus,
444                                                           G_DBUS_PROXY_FLAGS_NONE,
445                                                           NULL,
446                                                           "org.freedesktop.DisplayManager",
447                                                           "/org/freedesktop/DisplayManager",
448                                                           "org.freedesktop.DisplayManager",
449                                                           NULL, NULL);
450
451     g_debug ("Connecting to display manager...");
452     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, 0, &offset);
453     write_message (greeter, message, offset);
454
455     return TRUE;
456 }
457
458 /**
459  * ldm_greeter_get_hostname:
460  * @greeter: a #LdmGreeter
461  *
462  * Return value: The host this greeter is displaying
463  **/
464 const gchar *
465 ldm_greeter_get_hostname (LdmGreeter *greeter)
466 {
467     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
468
469     if (!greeter->priv->hostname)
470     {
471         struct utsname info;
472         uname (&info);
473         greeter->priv->hostname = g_strdup (info.nodename);
474     }
475
476     return greeter->priv->hostname;
477 }
478
479 /**
480  * ldm_greeter_get_theme:
481  * @greeter: a #LdmGreeter
482  *
483  * Return value: The theme this greeter is using
484  **/
485 const gchar *
486 ldm_greeter_get_theme (LdmGreeter *greeter)
487 {
488     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
489     return greeter->priv->theme;
490 }
491
492 static void
493 load_theme (LdmGreeter *greeter)
494 {
495     GError *error = NULL;
496
497     if (greeter->priv->theme_file)
498         return;
499
500     greeter->priv->theme_file = g_key_file_new ();
501     if (!g_key_file_load_from_file (greeter->priv->theme_file, greeter->priv->theme, G_KEY_FILE_NONE, &error))
502         g_warning ("Failed to read theme file: %s", error->message);
503     g_clear_error (&error);
504 }
505
506 /**
507  * ldm_greeter_get_string_property:
508  * @greeter: a #LdmGreeter
509  * @name: the name of the property to get
510  *
511  * Return value: The value of this property or NULL if it is not defined
512  **/
513 gchar *
514 ldm_greeter_get_string_property (LdmGreeter *greeter, const gchar *name)
515 {
516     GError *error = NULL;
517     gchar *result;
518
519     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
520     g_return_val_if_fail (name != NULL, NULL);
521
522     load_theme (greeter);
523
524     result = g_key_file_get_string (greeter->priv->theme_file, "theme", name, &error);
525     if (!result)
526         g_warning ("Error reading theme property: %s", error->message); // FIXME: Can handle G_KEY_FILE_ERROR_KEY_NOT_FOUND and G_KEY_FILE_ERROR_GROUP_NOT_FOUND
527     g_clear_error (&error);
528
529     return result;
530 }
531
532 /**
533  * ldm_greeter_get_integer_property:
534  * @greeter: a #LdmGreeter
535  * @name: the name of the property to get
536  *
537  * Return value: The value of this property or 0 if it is not defined
538  **/
539 gint
540 ldm_greeter_get_integer_property (LdmGreeter *greeter, const gchar *name)
541 {
542     GError *error = NULL;
543     gint result;
544
545     g_return_val_if_fail (LDM_IS_GREETER (greeter), 0);
546     g_return_val_if_fail (name != NULL, 0);
547
548     load_theme (greeter);
549
550     result = g_key_file_get_integer (greeter->priv->theme_file, "theme", name, &error);
551     if (!result)
552         g_warning ("Error reading theme property: %s", error->message); // FIXME: Can handle G_KEY_FILE_ERROR_KEY_NOT_FOUND and G_KEY_FILE_ERROR_GROUP_NOT_FOUND
553     g_clear_error (&error);
554
555     return result;
556 }
557
558 /**
559  * ldm_greeter_get_boolean_property:
560  * @greeter: a #LdmGreeter
561  * @name: the name of the property to get
562  *
563  * Return value: The value of this property or FALSE if it is not defined
564  **/
565 gboolean
566 ldm_greeter_get_boolean_property (LdmGreeter *greeter, const gchar *name)
567 {
568     GError *error = NULL;
569     gboolean result;
570
571     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
572     g_return_val_if_fail (name != NULL, FALSE);
573
574     load_theme (greeter);
575
576     result = g_key_file_get_boolean (greeter->priv->theme_file, "theme", name, &error);
577     if (!result)
578         g_warning ("Error reading theme property: %s", error->message); // FIXME: Can handle G_KEY_FILE_ERROR_KEY_NOT_FOUND and G_KEY_FILE_ERROR_GROUP_NOT_FOUND
579     g_clear_error (&error);
580
581     return result;
582 }
583
584 static LdmUser *
585 get_user_by_name (LdmGreeter *greeter, const gchar *username)
586 {
587     GList *link;
588   
589     for (link = greeter->priv->users; link; link = link->next)
590     {
591         LdmUser *user = link->data;
592         if (strcmp (ldm_user_get_name (user), username) == 0)
593             return user;
594     }
595
596     return NULL;
597 }
598   
599 static gint
600 compare_user (gconstpointer a, gconstpointer b)
601 {
602     LdmUser *user_a = (LdmUser *) a, *user_b = (LdmUser *) b;
603     return strcmp (ldm_user_get_display_name (user_a), ldm_user_get_display_name (user_b));
604 }
605
606 static void
607 load_config (LdmGreeter *greeter)
608 {
609     GVariant *result;
610     const gchar *config_path = NULL;
611
612     if (greeter->priv->config)
613         return;
614
615     result = g_dbus_proxy_get_cached_property (greeter->priv->lightdm_proxy,
616                                                "ConfigFile");
617     if (!result)
618     {
619         g_warning ("No ConfigFile property");
620         return;
621     }
622
623     if (g_variant_is_of_type (result, G_VARIANT_TYPE_STRING))
624         config_path = g_variant_get_string (result, NULL);
625     else
626         g_warning ("Invalid type for config file: %s, expected string", g_variant_get_type_string (result));
627
628     if (config_path)
629     {
630         GError *error = NULL;
631
632         g_debug ("Loading config from %s", config_path);
633
634         greeter->priv->config = g_key_file_new ();
635         if (!g_key_file_load_from_file (greeter->priv->config, config_path, G_KEY_FILE_NONE, &error))
636             g_warning ("Failed to load configuration from %s: %s", config_path, error->message); // FIXME: Don't make warning on no file, just info
637         g_clear_error (&error);
638     }
639
640     g_variant_unref (result);
641 }
642   
643 static void
644 load_users (LdmGreeter *greeter)
645 {
646     gchar **hidden_users, **hidden_shells;
647     gchar *value;
648     gint minimum_uid;
649     GList *users = NULL, *old_users, *new_users = NULL, *changed_users = NULL, *link;
650
651     load_config (greeter);
652
653     if (g_key_file_has_key (greeter->priv->config, "UserManager", "minimum-uid", NULL))
654         minimum_uid = g_key_file_get_integer (greeter->priv->config, "UserManager", "minimum-uid", NULL);
655     else
656         minimum_uid = 500;
657
658     value = g_key_file_get_string (greeter->priv->config, "UserManager", "hidden-users", NULL);
659     if (!value)
660         value = g_strdup ("nobody nobody4 noaccess");
661     hidden_users = g_strsplit (value, " ", -1);
662     g_free (value);
663
664     value = g_key_file_get_string (greeter->priv->config, "UserManager", "hidden-shells", NULL);
665     if (!value)
666         value = g_strdup ("/bin/false /usr/sbin/nologin");
667     hidden_shells = g_strsplit (value, " ", -1);
668     g_free (value);
669
670     setpwent ();
671
672     while (TRUE)
673     {
674         struct passwd *entry;
675         LdmUser *user;
676         char **tokens;
677         gchar *real_name, *image_path, *image;
678         int i;
679
680         errno = 0;
681         entry = getpwent ();
682         if (!entry)
683             break;
684
685         /* Ignore system users */
686         if (entry->pw_uid < minimum_uid)
687             continue;
688
689         /* Ignore users disabled by shell */
690         if (entry->pw_shell)
691         {
692             for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++);
693             if (hidden_shells[i])
694                 continue;
695         }
696
697         /* Ignore certain users */
698         for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++);
699         if (hidden_users[i])
700             continue;
701
702         tokens = g_strsplit (entry->pw_gecos, ",", -1);
703         if (tokens[0] != NULL && tokens[0][0] != '\0')
704             real_name = g_strdup (tokens[0]);
705         else
706             real_name = NULL;
707         g_strfreev (tokens);
708       
709         image_path = g_build_filename (entry->pw_dir, ".face", NULL);
710         if (!g_file_test (image_path, G_FILE_TEST_EXISTS))
711         {
712             g_free (image_path);
713             image_path = g_build_filename (entry->pw_dir, ".face.icon", NULL);
714             if (!g_file_test (image_path, G_FILE_TEST_EXISTS))
715             {
716                 g_free (image_path);
717                 image_path = NULL;
718             }
719         }
720         if (image_path)
721             image = g_filename_to_uri (image_path, NULL, NULL);
722         else
723             image = NULL;
724         g_free (image_path);
725
726         user = ldm_user_new (greeter, entry->pw_name, real_name, entry->pw_dir, image, FALSE);
727         g_free (real_name);
728         g_free (image);
729
730         /* Update existing users if have them */
731         for (link = greeter->priv->users; link; link = link->next)
732         {
733             LdmUser *info = link->data;
734             if (strcmp (ldm_user_get_name (info), ldm_user_get_name (user)) == 0)
735             {
736                 if (ldm_user_update (info, ldm_user_get_real_name (user), ldm_user_get_home_directory (user), ldm_user_get_image (user), ldm_user_get_logged_in (user)))
737                     changed_users = g_list_insert_sorted (changed_users, info, compare_user);
738                 g_object_unref (user);
739                 user = info;
740                 break;
741             }
742         }
743         if (!link)
744         {
745             /* Only notify once we have loaded the user list */
746             if (greeter->priv->have_users)
747                 new_users = g_list_insert_sorted (new_users, user, compare_user);
748         }
749         users = g_list_insert_sorted (users, user, compare_user);
750     }
751     g_strfreev (hidden_users);
752     g_strfreev (hidden_shells);
753
754     if (errno != 0)
755         g_warning ("Failed to read password database: %s", strerror (errno));
756
757     endpwent ();
758
759     /* Use new user list */
760     old_users = greeter->priv->users;
761     greeter->priv->users = users;
762   
763     /* Notify of changes */
764     for (link = new_users; link; link = link->next)
765     {
766         LdmUser *info = link->data;
767         g_debug ("User %s added", ldm_user_get_name (info));
768         g_signal_emit (greeter, signals[USER_ADDED], 0, info);
769     }
770     g_list_free (new_users);
771     for (link = changed_users; link; link = link->next)
772     {
773         LdmUser *info = link->data;
774         g_debug ("User %s changed", ldm_user_get_name (info));
775         g_signal_emit (greeter, signals[USER_CHANGED], 0, info);
776     }
777     g_list_free (changed_users);
778     for (link = old_users; link; link = link->next)
779     {
780         GList *new_link;
781
782         /* See if this user is in the current list */
783         for (new_link = greeter->priv->users; new_link; new_link = new_link->next)
784         {
785             if (new_link->data == link->data)
786                 break;
787         }
788
789         if (!new_link)
790         {
791             LdmUser *info = link->data;
792             g_debug ("User %s removed", ldm_user_get_name (info));
793             g_signal_emit (greeter, signals[USER_REMOVED], 0, info);
794             g_object_unref (info);
795         }
796     }
797     g_list_free (old_users);
798 }
799
800 static void
801 passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, LdmGreeter *greeter)
802 {
803     if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
804     {
805         g_debug ("%s changed, reloading user list", g_file_get_path (file));
806         load_users (greeter);
807     }
808 }
809
810 static void
811 update_users (LdmGreeter *greeter)
812 {
813     GFile *passwd_file;
814     GError *error = NULL;
815
816     if (greeter->priv->have_users)
817         return;
818
819     load_config (greeter);
820
821     /* User listing is disabled */
822     if (g_key_file_has_key (greeter->priv->config, "UserManager", "load-users", NULL) &&
823         !g_key_file_get_boolean (greeter->priv->config, "UserManager", "load-users", NULL))
824     {
825         greeter->priv->have_users = TRUE;
826         return;
827     }
828
829     load_users (greeter);
830
831     /* Watch for changes to user list */
832     passwd_file = g_file_new_for_path ("/etc/passwd");
833     greeter->priv->passwd_monitor = g_file_monitor (passwd_file, G_FILE_MONITOR_NONE, NULL, &error);
834     g_object_unref (passwd_file);
835     if (!greeter->priv->passwd_monitor)
836         g_warning ("Error monitoring /etc/passwd: %s", error->message);
837     else
838         g_signal_connect (greeter->priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), greeter);
839     g_clear_error (&error);
840
841     greeter->priv->have_users = TRUE;
842 }
843
844 /**
845  * ldm_greeter_get_num_users:
846  * @greeter: a #LdmGreeter
847  *
848  * Return value: The number of users able to log in
849  **/
850 gint
851 ldm_greeter_get_num_users (LdmGreeter *greeter)
852 {
853     g_return_val_if_fail (LDM_IS_GREETER (greeter), 0);
854     update_users (greeter);
855     return g_list_length (greeter->priv->users);
856 }
857
858 /**
859  * ldm_greeter_get_users:
860  * @greeter: A #LdmGreeter
861  *
862  * Get a list of users to present to the user.  This list may be a subset of the
863  * available users and may be empty depending on the server configuration.
864  *
865  * Return value: (element-type LdmUser): A list of #LdmUser that should be presented to the user.
866  **/
867 const GList *
868 ldm_greeter_get_users (LdmGreeter *greeter)
869 {
870     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
871     update_users (greeter);
872     return greeter->priv->users;
873 }
874
875 /**
876  * ldm_greeter_get_user_by_name:
877  * @greeter: A #LdmGreeter
878  * @username: Name of user to get.
879  *
880  * Get infomation about a given user or NULL if this user doesn't exist.
881  *
882  * Return value: (allow-none): A #LdmUser entry for the given user.
883  **/
884 const LdmUser *
885 ldm_greeter_get_user_by_name (LdmGreeter *greeter, const gchar *username)
886 {
887     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
888
889     update_users (greeter);
890
891     return get_user_by_name (greeter, username);
892 }
893
894 static void
895 update_languages (LdmGreeter *greeter)
896 {
897     gchar *stdout_text = NULL, *stderr_text = NULL;
898     gint exit_status;
899     gboolean result;
900     GError *error = NULL;
901
902     if (greeter->priv->have_languages)
903         return;
904
905     result = g_spawn_command_line_sync ("locale -a", &stdout_text, &stderr_text, &exit_status, &error);
906     if (!result || exit_status != 0)
907         g_warning ("Failed to get languages, locale -a returned %d: %s", exit_status, error->message);
908     else
909     {
910         gchar **tokens;
911         int i;
912
913         tokens = g_strsplit_set (stdout_text, "\n\r", -1);
914         for (i = 0; tokens[i]; i++)
915         {
916             LdmLanguage *language;
917             gchar *code;
918
919             code = g_strchug (tokens[i]);
920             if (code[0] == '\0')
921                 continue;
922
923             /* Ignore the non-interesting languages */
924             if (strcmp (code, "C") == 0 || strcmp (code, "POSIX") == 0)
925                 continue;
926
927             language = ldm_language_new (code);
928             greeter->priv->languages = g_list_append (greeter->priv->languages, language);
929         }
930
931         g_strfreev (tokens);
932     }
933
934     g_clear_error (&error);
935     g_free (stdout_text);
936     g_free (stderr_text);
937
938     greeter->priv->have_languages = TRUE;
939 }
940
941 /**
942  * ldm_greeter_get_default_language:
943  * @greeter: A #LdmGreeter
944  *
945  * Get the default language.
946  *
947  * Return value: The default language.
948  **/
949 const gchar *
950 ldm_greeter_get_default_language (LdmGreeter *greeter)
951 {
952     gchar *lang;
953     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
954     lang = getenv ("LANG");
955     if (lang)
956         return lang;
957     else
958         return "C";
959 }
960
961 /**
962  * ldm_greeter_get_languages:
963  * @greeter: A #LdmGreeter
964  *
965  * Get a list of languages to present to the user.
966  *
967  * Return value: (element-type LdmLanguage): A list of #LdmLanguage that should be presented to the user.
968  **/
969 const GList *
970 ldm_greeter_get_languages (LdmGreeter *greeter)
971 {
972     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
973     update_languages (greeter);
974     return greeter->priv->languages;
975 }
976
977 static void
978 layout_cb (XklConfigRegistry *config,
979            const XklConfigItem *item,
980            gpointer data)
981 {
982     LdmGreeter *greeter = data;
983     LdmLayout *layout;
984
985     layout = ldm_layout_new (item->name, item->short_description, item->description);
986     greeter->priv->layouts = g_list_append (greeter->priv->layouts, layout);
987 }
988
989 static void
990 setup_display (LdmGreeter *greeter)
991 {
992     if (!greeter->priv->display)
993         greeter->priv->display = XOpenDisplay (NULL);
994 }
995
996 static void
997 setup_xkl (LdmGreeter *greeter)
998 {
999     setup_display (greeter);
1000     greeter->priv->xkl_engine = xkl_engine_get_instance (greeter->priv->display);
1001     greeter->priv->xkl_config = xkl_config_rec_new ();
1002     if (!xkl_config_rec_get_from_server (greeter->priv->xkl_config, greeter->priv->xkl_engine))
1003         g_warning ("Failed to get Xkl configuration from server");
1004     greeter->priv->layout = g_strdup (greeter->priv->xkl_config->layouts[0]);
1005 }
1006
1007 /**
1008  * ldm_greeter_get_layouts:
1009  * @greeter: A #LdmGreeter
1010  *
1011  * Get a list of keyboard layouts to present to the user.
1012  *
1013  * Return value: (element-type LdmLayout): A list of #LdmLayout that should be presented to the user.
1014  **/
1015 const GList *
1016 ldm_greeter_get_layouts (LdmGreeter *greeter)
1017 {
1018     XklConfigRegistry *registry;
1019
1020     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
1021
1022     if (greeter->priv->have_layouts)
1023         return greeter->priv->layouts;
1024
1025     setup_xkl (greeter);
1026
1027     registry = xkl_config_registry_get_instance (greeter->priv->xkl_engine);
1028     xkl_config_registry_load (registry, FALSE);
1029     xkl_config_registry_foreach_layout (registry, layout_cb, greeter);
1030     g_object_unref (registry);
1031     greeter->priv->have_layouts = TRUE;
1032
1033     return greeter->priv->layouts;
1034 }
1035
1036 /**
1037  * ldm_greeter_set_layout:
1038  * @greeter: A #LdmGreeter
1039  * @layout: The layout to use
1040  *
1041  * Set the layout for this session.
1042  **/
1043 void
1044 ldm_greeter_set_layout (LdmGreeter *greeter, const gchar *layout)
1045 {
1046     XklConfigRec *config;
1047
1048     g_return_if_fail (LDM_IS_GREETER (greeter));
1049     g_return_if_fail (layout != NULL);
1050
1051     g_debug ("Setting keyboard layout to %s", layout);
1052
1053     setup_xkl (greeter);
1054
1055     config = xkl_config_rec_new ();
1056     config->layouts = g_malloc (sizeof (gchar *) * 2);
1057     config->model = g_strdup (greeter->priv->xkl_config->model);
1058     config->layouts[0] = g_strdup (layout);
1059     config->layouts[1] = NULL;
1060     if (!xkl_config_rec_activate (config, greeter->priv->xkl_engine))
1061         g_warning ("Failed to activate XKL config");
1062     else
1063         greeter->priv->layout = g_strdup (layout);
1064     g_object_unref (config);
1065 }
1066
1067 /**
1068  * ldm_greeter_get_layout:
1069  * @greeter: A #LdmGreeter
1070  *
1071  * Get the current keyboard layout.
1072  *
1073  * Return value: The currently active layout for this user.
1074  **/
1075 const gchar *
1076 ldm_greeter_get_layout (LdmGreeter *greeter)
1077 {
1078     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
1079     setup_xkl (greeter);
1080     return greeter->priv->layout;
1081 }
1082
1083 static void
1084 update_sessions (LdmGreeter *greeter)
1085 {
1086     GDir *directory;
1087     GError *error = NULL;
1088
1089     if (greeter->priv->have_sessions)
1090         return;
1091
1092     directory = g_dir_open (XSESSIONS_DIR, 0, &error);
1093     if (!directory)
1094         g_warning ("Failed to open sessions directory: %s", error->message);
1095     g_clear_error (&error);
1096     if (!directory)
1097         return;
1098
1099     while (TRUE)
1100     {
1101         const gchar *filename;
1102         GKeyFile *key_file;
1103         gchar *key, *path;
1104         gboolean result;
1105
1106         filename = g_dir_read_name (directory);
1107         if (filename == NULL)
1108             break;
1109
1110         if (!g_str_has_suffix (filename, ".desktop"))
1111             continue;
1112
1113         key = g_strndup (filename, strlen (filename) - strlen (".desktop"));
1114         path = g_build_filename (XSESSIONS_DIR, filename, NULL);
1115         g_debug ("Loading session %s", path);
1116
1117         key_file = g_key_file_new ();
1118         result = g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error);
1119         if (!result)
1120             g_warning ("Failed to load session file %s: %s:", path, error->message);
1121         g_clear_error (&error);
1122
1123         if (result && !g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL))
1124         {
1125             gchar *domain, *name, *comment;
1126
1127 #ifdef G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN
1128             domain = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN, NULL);
1129 #else
1130             domain = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GNOME-Gettext-Domain", NULL);
1131 #endif
1132             name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, domain, NULL);
1133             comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, domain, NULL);
1134             if (!comment)
1135                 comment = g_strdup ("");
1136             if (name)
1137             {
1138                 g_debug ("Loaded session %s (%s, %s)", key, name, comment);
1139                 greeter->priv->sessions = g_list_append (greeter->priv->sessions, ldm_session_new (key, name, comment));
1140             }
1141             else
1142                 g_warning ("Invalid session %s: %s", path, error->message);
1143             g_clear_error (&error);
1144             g_free (domain);
1145             g_free (name);
1146             g_free (comment);
1147         }
1148
1149         g_free (key);
1150         g_free (path);
1151         g_key_file_free (key_file);
1152     }
1153
1154     g_dir_close (directory);
1155
1156     greeter->priv->have_sessions = TRUE;
1157 }
1158
1159 /**
1160  * ldm_greeter_get_sessions:
1161  * @greeter: A #LdmGreeter
1162  *
1163  * Get the available sessions.
1164  *
1165  * Return value: (element-type LdmSession): A list of #LdmSession
1166  **/
1167 const GList *
1168 ldm_greeter_get_sessions (LdmGreeter *greeter)
1169 {
1170     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
1171     update_sessions (greeter);
1172     return greeter->priv->sessions;
1173 }
1174
1175 /**
1176  * ldm_greeter_get_default_session:
1177  * @greeter: A #LdmGreeter
1178  *
1179  * Get the default session to use.
1180  *
1181  * Return value: The session name
1182  **/
1183 const gchar *
1184 ldm_greeter_get_default_session (LdmGreeter *greeter)
1185 {
1186     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
1187     return greeter->priv->default_session;
1188 }
1189
1190 /**
1191  * ldm_greeter_get_has_guest_session:
1192  * @greeter: A #LdmGreeter
1193  *
1194  * Check if guest sessions are supported.
1195  *
1196  * Return value: TRUE if guest sessions are supported.
1197  */
1198 gboolean
1199 ldm_greeter_get_has_guest_session (LdmGreeter *greeter)
1200 {
1201     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1202     return greeter->priv->guest_account_supported;
1203 }
1204
1205 /**
1206  * ldm_greeter_get_is_first:
1207  * @greeter: A #LdmGreeter
1208  *
1209  * Check if this is the first time a greeter has been shown on this display.
1210  *
1211  * Return value: TRUE if this is the first greeter on this display.
1212  */
1213 gboolean
1214 ldm_greeter_get_is_first (LdmGreeter *greeter)
1215 {
1216     g_return_val_if_fail (LDM_IS_GREETER (greeter), 0);
1217     return greeter->priv->greeter_count == 0;
1218 }
1219
1220 /**
1221  * ldm_greeter_get_timed_login_user:
1222  * @greeter: A #LdmGreeter
1223  *
1224  * Get the user to log in by as default.
1225  *
1226  * Return value: A username
1227  */
1228 const gchar *
1229 ldm_greeter_get_timed_login_user (LdmGreeter *greeter)
1230 {
1231     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
1232     return greeter->priv->timed_user;
1233 }
1234
1235 /**
1236  * ldm_greeter_get_timed_login_delay:
1237  * @greeter: A #LdmGreeter
1238  *
1239  * Get the number of seconds to wait until logging in as the default user.
1240  *
1241  * Return value: The number of seconds before logging in as the default user
1242  */
1243 gint
1244 ldm_greeter_get_timed_login_delay (LdmGreeter *greeter)
1245 {
1246     g_return_val_if_fail (LDM_IS_GREETER (greeter), 0);
1247     return greeter->priv->login_delay;
1248 }
1249
1250 /**
1251  * ldm_greeter_cancel_timed_login:
1252  * @greeter: A #LdmGreeter
1253  *
1254  * Cancel the login as the default user.
1255  */
1256 void
1257 ldm_greeter_cancel_timed_login (LdmGreeter *greeter)
1258 {
1259     g_return_if_fail (LDM_IS_GREETER (greeter));
1260
1261     if (greeter->priv->login_timeout)
1262        g_source_remove (greeter->priv->login_timeout);
1263     greeter->priv->login_timeout = 0;
1264 }
1265
1266 /**
1267  * ldm_greeter_login:
1268  * @greeter: A #LdmGreeter
1269  * @username: (allow-none): A username or NULL to prompt for a username.
1270  *
1271  * Starts the authentication procedure for a user.
1272  **/
1273 void
1274 ldm_greeter_login (LdmGreeter *greeter, const char *username)
1275 {
1276     guint8 message[MAX_MESSAGE_LENGTH];
1277     gsize offset = 0;
1278
1279     g_return_if_fail (LDM_IS_GREETER (greeter));
1280
1281     if (!username)
1282         username = "";
1283
1284     greeter->priv->in_authentication = TRUE;  
1285     greeter->priv->is_authenticated = FALSE;
1286     g_free (greeter->priv->authentication_user);
1287     greeter->priv->authentication_user = g_strdup (username);
1288     g_debug ("Starting authentication for user %s...", username);
1289     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_LOGIN, string_length (username), &offset);
1290     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
1291     write_message (greeter, message, offset);
1292 }
1293
1294 /**
1295  * ldm_greeter_login_with_user_promp:
1296  * @greeter: A #LdmGreeter
1297  *
1298  * Starts the authentication procedure, prompting the greeter for a username.
1299  **/
1300 void
1301 ldm_greeter_login_with_user_prompt (LdmGreeter *greeter)
1302 {
1303     ldm_greeter_login (greeter, NULL);
1304 }
1305
1306 /**
1307  * ldm_greeter_login_as_guest:
1308  * @greeter: A #LdmGreeter
1309  *
1310  * Starts the authentication procedure for the guest user.
1311  **/
1312 void
1313 ldm_greeter_login_as_guest (LdmGreeter *greeter)
1314 {
1315     guint8 message[MAX_MESSAGE_LENGTH];
1316     gsize offset = 0;
1317
1318     g_return_if_fail (LDM_IS_GREETER (greeter));
1319
1320     greeter->priv->in_authentication = TRUE;
1321     greeter->priv->is_authenticated = FALSE;
1322     g_free (greeter->priv->authentication_user);
1323     greeter->priv->authentication_user = NULL;
1324     g_debug ("Starting authentication for guest account...");
1325     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_LOGIN_AS_GUEST, 0, &offset);
1326     write_message (greeter, message, offset);
1327 }
1328
1329 /**
1330  * ldm_greeter_respond:
1331  * @greeter: A #LdmGreeter
1332  * @response: Response to a prompt
1333  *
1334  * Provide response to a prompt.
1335  **/
1336 void
1337 ldm_greeter_respond (LdmGreeter *greeter, const gchar *response)
1338 {
1339     guint8 message[MAX_MESSAGE_LENGTH];
1340     gsize offset = 0;
1341
1342     g_return_if_fail (LDM_IS_GREETER (greeter));
1343     g_return_if_fail (response != NULL);
1344
1345     g_debug ("Providing response to display manager");
1346     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, int_length () + string_length (response), &offset);
1347     // FIXME: Could be multiple responses required
1348     write_int (message, MAX_MESSAGE_LENGTH, 1, &offset);
1349     write_string (message, MAX_MESSAGE_LENGTH, response, &offset);
1350     write_message (greeter, message, offset);
1351 }
1352
1353 /**
1354  * ldm_greeter_cancel_authentication:
1355  * @greeter: A #LdmGreeter
1356  *
1357  * Cancel the current user authentication.
1358  **/
1359 void
1360 ldm_greeter_cancel_authentication (LdmGreeter *greeter)
1361 {
1362     guint8 message[MAX_MESSAGE_LENGTH];
1363     gsize offset = 0;
1364
1365     g_return_if_fail (LDM_IS_GREETER (greeter));
1366
1367     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
1368     write_message (greeter, message, offset);
1369 }
1370
1371 /**
1372  * ldm_greeter_get_in_authentication:
1373  * @greeter: A #LdmGreeter
1374  *
1375  * Checks if the greeter is in the process of authenticating.
1376  *
1377  * Return value: TRUE if the greeter is authenticating a user.
1378  **/
1379 gboolean
1380 ldm_greeter_get_in_authentication (LdmGreeter *greeter)
1381 {
1382     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1383     return greeter->priv->in_authentication;
1384 }
1385
1386 /**
1387  * ldm_greeter_get_is_authenticated:
1388  * @greeter: A #LdmGreeter
1389  *
1390  * Checks if the greeter has successfully authenticated.
1391  *
1392  * Return value: TRUE if the greeter is authenticated for login.
1393  **/
1394 gboolean
1395 ldm_greeter_get_is_authenticated (LdmGreeter *greeter)
1396 {
1397     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1398     return greeter->priv->is_authenticated;
1399 }
1400
1401 /**
1402  * ldm_greeter_get_authentication_user:
1403  * @greeter: A #LdmGreeter
1404  *
1405  * Get the user that is being authenticated.
1406  *
1407  * Return value: The username of the authentication user being authenticated or NULL if no authentication in progress.
1408  */
1409 const gchar *
1410 ldm_greeter_get_authentication_user (LdmGreeter *greeter)
1411 {
1412     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
1413     return greeter->priv->authentication_user;
1414 }
1415
1416 /**
1417  * ldm_greeter_start_session:
1418  * @greeter: A #LdmGreeter
1419  * @session: (allow-none): The session to log into or NULL to use the default
1420  *
1421  * Start a session for the logged in user.
1422  **/
1423 void
1424 ldm_greeter_start_session (LdmGreeter *greeter, const gchar *session)
1425 {
1426     guint8 message[MAX_MESSAGE_LENGTH];
1427     gsize offset = 0;
1428
1429     g_return_if_fail (LDM_IS_GREETER (greeter));
1430   
1431     if (!session)
1432         session = "";
1433
1434     g_debug ("Starting session %s", session);
1435     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
1436     write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
1437     write_message (greeter, message, offset);
1438 }
1439
1440 /**
1441  * ldm_greeter_start_session_with_defaults:
1442  * @greeter: A #LdmGreeter
1443  *
1444  * Login a user to a session using default settings for that user.
1445  **/
1446 void
1447 ldm_greeter_start_default_session (LdmGreeter *greeter)
1448 {
1449     ldm_greeter_start_session (greeter, NULL);
1450 }
1451
1452 static gboolean
1453 upower_call_function (LdmGreeter *greeter, const gchar *function, gboolean has_result)
1454 {
1455     GDBusProxy *proxy;
1456     GVariant *result;
1457     GError *error = NULL;
1458     gboolean function_result = FALSE;
1459   
1460     if (!greeter->priv->system_bus)
1461         return FALSE;
1462
1463     proxy = g_dbus_proxy_new_sync (greeter->priv->system_bus,
1464                                    G_DBUS_PROXY_FLAGS_NONE,
1465                                    NULL,
1466                                    "org.freedesktop.UPower",
1467                                    "/org/freedesktop/UPower",
1468                                    "org.freedesktop.UPower",
1469                                    NULL, NULL);
1470     result = g_dbus_proxy_call_sync (proxy,
1471                                      function,
1472                                      NULL,
1473                                      G_DBUS_CALL_FLAGS_NONE,
1474                                      -1,
1475                                      NULL,
1476                                      &error);
1477     g_object_unref (proxy);
1478
1479     if (!result)
1480         g_warning ("Error calling UPower function %s: %s", function, error->message);
1481     g_clear_error (&error);
1482     if (!result)
1483         return FALSE;
1484
1485     if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(b)")))
1486         g_variant_get (result, "(b)", &function_result);
1487
1488     g_variant_unref (result);
1489     return function_result;
1490 }
1491
1492 /**
1493  * ldm_greeter_get_can_suspend:
1494  * @greeter: A #LdmGreeter
1495  *
1496  * Checks if the greeter is authorized to do a system suspend.
1497  *
1498  * Return value: TRUE if the greeter can suspend the system
1499  **/
1500 gboolean
1501 ldm_greeter_get_can_suspend (LdmGreeter *greeter)
1502 {
1503     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1504     return upower_call_function (greeter, "SuspendAllowed", TRUE);
1505 }
1506
1507 /**
1508  * ldm_greeter_suspend:
1509  * @greeter: A #LdmGreeter
1510  *
1511  * Triggers a system suspend.
1512  **/
1513 void
1514 ldm_greeter_suspend (LdmGreeter *greeter)
1515 {
1516     g_return_if_fail (LDM_IS_GREETER (greeter));
1517     upower_call_function (greeter, "Suspend", FALSE);
1518 }
1519
1520 /**
1521  * ldm_greeter_get_can_hibernate:
1522  * @greeter: A #LdmGreeter
1523  *
1524  * Checks if the greeter is authorized to do a system hibernate.
1525  *
1526  * Return value: TRUE if the greeter can hibernate the system
1527  **/
1528 gboolean
1529 ldm_greeter_get_can_hibernate (LdmGreeter *greeter)
1530 {
1531     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1532     return upower_call_function (greeter, "HibernateAllowed", TRUE);
1533 }
1534
1535 /**
1536  * ldm_greeter_hibernate:
1537  * @greeter: A #LdmGreeter
1538  *
1539  * Triggers a system hibernate.
1540  **/
1541 void
1542 ldm_greeter_hibernate (LdmGreeter *greeter)
1543 {
1544     g_return_if_fail (LDM_IS_GREETER (greeter));
1545     upower_call_function (greeter, "Hibernate", FALSE);
1546 }
1547
1548 static gboolean
1549 ck_call_function (LdmGreeter *greeter, const gchar *function, gboolean has_result)
1550 {
1551     GDBusProxy *proxy;
1552     GVariant *result;
1553     GError *error = NULL;
1554     gboolean function_result = FALSE;
1555
1556     if (!greeter->priv->system_bus)
1557         return FALSE;
1558
1559     proxy = g_dbus_proxy_new_sync (greeter->priv->system_bus,
1560                                    G_DBUS_PROXY_FLAGS_NONE,
1561                                    NULL,
1562                                    "org.freedesktop.ConsoleKit",
1563                                    "/org/freedesktop/ConsoleKit/Manager",
1564                                    "org.freedesktop.ConsoleKit.Manager",
1565                                    NULL, NULL);
1566     result = g_dbus_proxy_call_sync (proxy,
1567                                      function,
1568                                      NULL,
1569                                      G_DBUS_CALL_FLAGS_NONE,
1570                                      -1,
1571                                      NULL,
1572                                      &error);
1573     g_object_unref (proxy);
1574
1575     if (!result)
1576         g_warning ("Error calling ConsoleKit function %s: %s", function, error->message);
1577     g_clear_error (&error);
1578     if (!result)
1579         return FALSE;
1580
1581     if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(b)")))
1582         g_variant_get (result, "(b)", &function_result);
1583
1584     g_variant_unref (result);
1585     return function_result;
1586 }
1587
1588 /**
1589  * ldm_greeter_get_can_restart:
1590  * @greeter: A #LdmGreeter
1591  *
1592  * Checks if the greeter is authorized to do a system restart.
1593  *
1594  * Return value: TRUE if the greeter can restart the system
1595  **/
1596 gboolean
1597 ldm_greeter_get_can_restart (LdmGreeter *greeter)
1598 {
1599     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1600     return ck_call_function (greeter, "CanRestart", TRUE);
1601 }
1602
1603 /**
1604  * ldm_greeter_restart:
1605  * @greeter: A #LdmGreeter
1606  *
1607  * Triggers a system restart.
1608  **/
1609 void
1610 ldm_greeter_restart (LdmGreeter *greeter)
1611 {
1612     g_return_if_fail (LDM_IS_GREETER (greeter));
1613     ck_call_function (greeter, "Restart", FALSE);
1614 }
1615
1616 /**
1617  * ldm_greeter_get_can_shutdown:
1618  * @greeter: A #LdmGreeter
1619  *
1620  * Checks if the greeter is authorized to do a system shutdown.
1621  *
1622  * Return value: TRUE if the greeter can shutdown the system
1623  **/
1624 gboolean
1625 ldm_greeter_get_can_shutdown (LdmGreeter *greeter)
1626 {
1627     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1628     return ck_call_function (greeter, "CanStop", TRUE);
1629 }
1630
1631 /**
1632  * ldm_greeter_shutdown:
1633  * @greeter: A #LdmGreeter
1634  *
1635  * Triggers a system shutdown.
1636  **/
1637 void
1638 ldm_greeter_shutdown (LdmGreeter *greeter)
1639 {
1640     g_return_if_fail (LDM_IS_GREETER (greeter));
1641     ck_call_function (greeter, "Stop", FALSE);
1642 }
1643
1644 /**
1645  * ldm_greeter_get_user_defaults:
1646  * @greeter: A #LdmGreeter
1647  * @username: The user to check
1648  * @language: (out): Default language for this user.
1649  * @layout: (out): Default keyboard layout for this user.
1650  * @session: (out): Default session for this user.
1651  *
1652  * Get the default settings for a given user.  If the user does not exist FALSE
1653  * is returned and language, layout and session are not set.
1654  *
1655  * Return value: TRUE if this user exists.
1656  **/
1657 gboolean
1658 ldm_greeter_get_user_defaults (LdmGreeter *greeter, const gchar *username, gchar **language, gchar **layout, gchar **session)
1659 {
1660     gsize offset = 0;
1661     guint32 id;
1662     guint8 message[MAX_MESSAGE_LENGTH];
1663
1664     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1665     g_return_val_if_fail (username != NULL, FALSE);
1666
1667     offset = 0;
1668     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_GET_USER_DEFAULTS, string_length (username), &offset);
1669     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
1670     write_message (greeter, message, offset);
1671
1672     if (!read_packet (greeter, TRUE))
1673     {
1674         g_warning ("Error reading user defaults from server");
1675         return FALSE;
1676     }
1677
1678     offset = 0;
1679     id = read_int (greeter, &offset);
1680     g_assert (id == GREETER_MESSAGE_USER_DEFAULTS);
1681     read_int (greeter, &offset);
1682     *language = read_string (greeter, &offset);
1683     *layout = read_string (greeter, &offset);
1684     *session = read_string (greeter, &offset);
1685
1686     g_debug ("User defaults for %s: language=%s, layout=%s, session=%s", username, *language, *layout, *session);
1687
1688     greeter->priv->n_read = 0;
1689
1690     return TRUE;
1691 }
1692
1693 static void
1694 ldm_greeter_init (LdmGreeter *greeter)
1695 {
1696     greeter->priv = G_TYPE_INSTANCE_GET_PRIVATE (greeter, LDM_TYPE_GREETER, LdmGreeterPrivate);
1697     greeter->priv->read_buffer = g_malloc (HEADER_SIZE);
1698
1699     g_debug ("default-language=%s", ldm_greeter_get_default_language (greeter));
1700 }
1701
1702 static void
1703 ldm_greeter_set_property (GObject      *object,
1704                           guint         prop_id,
1705                           const GValue *value,
1706                           GParamSpec   *pspec)
1707 {
1708     LdmGreeter *self;
1709
1710     self = LDM_GREETER (object);
1711
1712     switch (prop_id) {
1713     case PROP_LAYOUT:
1714         ldm_greeter_set_layout(self, g_value_get_string (value));
1715         break;
1716     default:
1717         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1718         break;
1719     }
1720 }
1721
1722 static void
1723 ldm_greeter_get_property (GObject    *object,
1724                           guint       prop_id,
1725                           GValue     *value,
1726                           GParamSpec *pspec)
1727 {
1728     LdmGreeter *self;
1729
1730     self = LDM_GREETER (object);
1731
1732     switch (prop_id) {
1733     case PROP_HOSTNAME:
1734         g_value_set_string (value, ldm_greeter_get_hostname (self));
1735         break;
1736     case PROP_NUM_USERS:
1737         g_value_set_int (value, ldm_greeter_get_num_users (self));
1738         break;
1739     case PROP_USERS:
1740         break;
1741     case PROP_DEFAULT_LANGUAGE:
1742         g_value_set_string (value, ldm_greeter_get_default_language (self));
1743         break;
1744     case PROP_LAYOUTS:
1745         break;
1746     case PROP_LAYOUT:
1747         g_value_set_string (value, ldm_greeter_get_layout (self));
1748         break;
1749     case PROP_SESSIONS:
1750         break;
1751     case PROP_DEFAULT_SESSION:
1752         g_value_set_string (value, ldm_greeter_get_default_session (self));
1753         break;
1754     case PROP_TIMED_LOGIN_USER:
1755         g_value_set_string (value, ldm_greeter_get_timed_login_user (self));
1756         break;
1757     case PROP_TIMED_LOGIN_DELAY:
1758         g_value_set_int (value, ldm_greeter_get_timed_login_delay (self));
1759         break;
1760     case PROP_AUTHENTICATION_USER:
1761         g_value_set_string (value, ldm_greeter_get_authentication_user (self));
1762         break;
1763     case PROP_IN_AUTHENTICATION:
1764         g_value_set_boolean (value, ldm_greeter_get_in_authentication (self));
1765         break;
1766     case PROP_IS_AUTHENTICATED:
1767         g_value_set_boolean (value, ldm_greeter_get_is_authenticated (self));
1768         break;
1769     case PROP_CAN_SUSPEND:
1770         g_value_set_boolean (value, ldm_greeter_get_can_suspend (self));
1771         break;
1772     case PROP_CAN_HIBERNATE:
1773         g_value_set_boolean (value, ldm_greeter_get_can_hibernate (self));
1774         break;
1775     case PROP_CAN_RESTART:
1776         g_value_set_boolean (value, ldm_greeter_get_can_restart (self));
1777         break;
1778     case PROP_CAN_SHUTDOWN:
1779         g_value_set_boolean (value, ldm_greeter_get_can_shutdown (self));
1780         break;
1781     default:
1782         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1783         break;
1784     }
1785 }
1786
1787 static void
1788 ldm_greeter_class_init (LdmGreeterClass *klass)
1789 {
1790     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1791
1792     g_type_class_add_private (klass, sizeof (LdmGreeterPrivate));
1793
1794     object_class->set_property = ldm_greeter_set_property;
1795     object_class->get_property = ldm_greeter_get_property;
1796
1797     g_object_class_install_property (object_class,
1798                                      PROP_NUM_USERS,
1799                                      g_param_spec_string ("hostname",
1800                                                           "hostname",
1801                                                           "Hostname displaying greeter for",
1802                                                           NULL,
1803                                                           G_PARAM_READABLE));
1804     g_object_class_install_property (object_class,
1805                                      PROP_NUM_USERS,
1806                                      g_param_spec_int ("num-users",
1807                                                        "num-users",
1808                                                        "Number of login users",
1809                                                        0, G_MAXINT, 0,
1810                                                        G_PARAM_READABLE));
1811     /*g_object_class_install_property (object_class,
1812                                      PROP_USERS,
1813                                      g_param_spec_list ("users",
1814                                                         "users",
1815                                                         "Users that can login"));
1816     g_object_class_install_property (object_class,
1817                                      PROP_DEFAULT_LANGUAGE,
1818                                      g_param_spec_string ("default-language",
1819                                                           "default-language",
1820                                                           "Default language",
1821                                                           NULL,
1822                                                           G_PARAM_READWRITE));
1823     g_object_class_install_property (object_class,
1824                                      PROP_LAYOUTS,
1825                                      g_param_spec_list ("layouts",
1826                                                         "layouts",
1827                                                         "Available keyboard layouts"));*/
1828     g_object_class_install_property (object_class,
1829                                      PROP_LAYOUT,
1830                                      g_param_spec_string ("layout",
1831                                                           "layout",
1832                                                           "Current keyboard layout",
1833                                                           NULL,
1834                                                           G_PARAM_READWRITE));
1835     /*g_object_class_install_property (object_class,
1836                                      PROP_SESSIONS,
1837                                      g_param_spec_list ("sessions",
1838                                                         "sessions",
1839                                                         "Available sessions"));*/
1840     g_object_class_install_property (object_class,
1841                                      PROP_DEFAULT_SESSION,
1842                                      g_param_spec_string ("default-session",
1843                                                           "default-session",
1844                                                           "Default session",
1845                                                           NULL,
1846                                                           G_PARAM_READWRITE));
1847     g_object_class_install_property (object_class,
1848                                      PROP_TIMED_LOGIN_USER,
1849                                      g_param_spec_string ("timed-login-user",
1850                                                           "timed-login-user",
1851                                                           "User to login as when timed expires",
1852                                                           NULL,
1853                                                           G_PARAM_READABLE));
1854     g_object_class_install_property (object_class,
1855                                      PROP_TIMED_LOGIN_DELAY,
1856                                      g_param_spec_int ("login-delay",
1857                                                        "login-delay",
1858                                                        "Number of seconds until logging in as default user",
1859                                                        G_MININT, G_MAXINT, 0,
1860                                                        G_PARAM_READABLE));
1861     g_object_class_install_property (object_class,
1862                                      PROP_AUTHENTICATION_USER,
1863                                      g_param_spec_string ("authentication-user",
1864                                                           "authentication-user",
1865                                                           "The user being authenticated",
1866                                                           NULL,
1867                                                           G_PARAM_READABLE));
1868     g_object_class_install_property (object_class,
1869                                      PROP_IN_AUTHENTICATION,
1870                                      g_param_spec_boolean ("in-authentication",
1871                                                            "in-authentication",
1872                                                            "TRUE if a user is being authenticated",
1873                                                            FALSE,
1874                                                            G_PARAM_READABLE));
1875     g_object_class_install_property (object_class,
1876                                      PROP_IS_AUTHENTICATED,
1877                                      g_param_spec_boolean ("is-authenticated",
1878                                                            "is-authenticated",
1879                                                            "TRUE if the selected user is authenticated",
1880                                                            FALSE,
1881                                                            G_PARAM_READABLE));
1882     g_object_class_install_property (object_class,
1883                                      PROP_CAN_SUSPEND,
1884                                      g_param_spec_boolean ("can-suspend",
1885                                                            "can-suspend",
1886                                                            "TRUE if allowed to suspend the system",
1887                                                            FALSE,
1888                                                            G_PARAM_READABLE));
1889     g_object_class_install_property (object_class,
1890                                      PROP_CAN_HIBERNATE,
1891                                      g_param_spec_boolean ("can-hibernate",
1892                                                            "can-hibernate",
1893                                                            "TRUE if allowed to hibernate the system",
1894                                                            FALSE,
1895                                                            G_PARAM_READABLE));
1896     g_object_class_install_property (object_class,
1897                                      PROP_CAN_RESTART,
1898                                      g_param_spec_boolean ("can-restart",
1899                                                            "can-restart",
1900                                                            "TRUE if allowed to restart the system",
1901                                                            FALSE,
1902                                                            G_PARAM_READABLE));
1903     g_object_class_install_property (object_class,
1904                                      PROP_CAN_SHUTDOWN,
1905                                      g_param_spec_boolean ("can-shutdown",
1906                                                            "can-shutdown",
1907                                                            "TRUE if allowed to shutdown the system",
1908                                                            FALSE,
1909                                                            G_PARAM_READABLE));
1910
1911     /**
1912      * LdmGreeter::connected:
1913      * @greeter: A #LdmGreeter
1914      *
1915      * The ::connected signal gets emitted when the greeter connects to the
1916      * LightDM server.
1917      **/
1918     signals[CONNECTED] =
1919         g_signal_new ("connected",
1920                       G_TYPE_FROM_CLASS (klass),
1921                       G_SIGNAL_RUN_LAST,
1922                       G_STRUCT_OFFSET (LdmGreeterClass, connected),
1923                       NULL, NULL,
1924                       g_cclosure_marshal_VOID__VOID,
1925                       G_TYPE_NONE, 0);
1926
1927     /**
1928      * LdmGreeter::show-prompt:
1929      * @greeter: A #LdmGreeter
1930      * @text: Prompt text
1931      *
1932      * The ::show-prompt signal gets emitted when the greeter should show a
1933      * prompt to the user.  The given text should be displayed and an input
1934      * field for the user to provide a response.
1935      *
1936      * Call ldm_greeter_respond() with the resultant input or
1937      * ldm_greeter_cancel_authentication() to abort the authentication.
1938      **/
1939     signals[SHOW_PROMPT] =
1940         g_signal_new ("show-prompt",
1941                       G_TYPE_FROM_CLASS (klass),
1942                       G_SIGNAL_RUN_LAST,
1943                       G_STRUCT_OFFSET (LdmGreeterClass, show_prompt),
1944                       NULL, NULL,
1945                       g_cclosure_marshal_VOID__STRING,
1946                       G_TYPE_NONE, 1, G_TYPE_STRING);
1947
1948     /**
1949      * LdmGreeter::show-message:
1950      * @greeter: A #LdmGreeter
1951      * @text: Message text
1952      *
1953      * The ::show-message signal gets emitted when the greeter
1954      * should show an informational message to the user.
1955      **/
1956     signals[SHOW_MESSAGE] =
1957         g_signal_new ("show-message",
1958                       G_TYPE_FROM_CLASS (klass),
1959                       G_SIGNAL_RUN_LAST,
1960                       G_STRUCT_OFFSET (LdmGreeterClass, show_message),
1961                       NULL, NULL,
1962                       g_cclosure_marshal_VOID__STRING,
1963                       G_TYPE_NONE, 1, G_TYPE_STRING);
1964
1965     /**
1966      * LdmGreeter::show-error:
1967      * @greeter: A #LdmGreeter
1968      * @text: Message text
1969      *
1970      * The ::show-error signal gets emitted when the greeter
1971      * should show an error message to the user.
1972      **/
1973     signals[SHOW_ERROR] =
1974         g_signal_new ("show-error",
1975                       G_TYPE_FROM_CLASS (klass),
1976                       G_SIGNAL_RUN_LAST,
1977                       G_STRUCT_OFFSET (LdmGreeterClass, show_error),
1978                       NULL, NULL,
1979                       g_cclosure_marshal_VOID__STRING,
1980                       G_TYPE_NONE, 1, G_TYPE_STRING);
1981
1982     /**
1983      * LdmGreeter::authentication-complete:
1984      * @greeter: A #LdmGreeter
1985      *
1986      * The ::authentication-complete signal gets emitted when the greeter
1987      * has completed authentication.
1988      *
1989      * Call ldm_greeter_get_is_authenticated() to check if the authentication
1990      * was successful.
1991      **/
1992     signals[AUTHENTICATION_COMPLETE] =
1993         g_signal_new ("authentication-complete",
1994                       G_TYPE_FROM_CLASS (klass),
1995                       G_SIGNAL_RUN_LAST,
1996                       G_STRUCT_OFFSET (LdmGreeterClass, authentication_complete),
1997                       NULL, NULL,
1998                       g_cclosure_marshal_VOID__VOID,
1999                       G_TYPE_NONE, 0);
2000
2001     /**
2002      * LdmGreeter::timed-login:
2003      * @greeter: A #LdmGreeter
2004      * @username: A username
2005      *
2006      * The ::timed-login signal gets emitted when the default user timer
2007      * has expired.
2008      **/
2009     signals[TIMED_LOGIN] =
2010         g_signal_new ("timed-login",
2011                       G_TYPE_FROM_CLASS (klass),
2012                       G_SIGNAL_RUN_LAST,
2013                       G_STRUCT_OFFSET (LdmGreeterClass, timed_login),
2014                       NULL, NULL,
2015                       g_cclosure_marshal_VOID__STRING,
2016                       G_TYPE_NONE, 1, G_TYPE_STRING);
2017
2018     /**
2019      * LdmGreeter::user-added:
2020      * @greeter: A #LdmGreeter
2021      *
2022      * The ::user-added signal gets emitted when a user account is created.
2023      **/
2024     signals[USER_ADDED] =
2025         g_signal_new ("user-added",
2026                       G_TYPE_FROM_CLASS (klass),
2027                       G_SIGNAL_RUN_LAST,
2028                       G_STRUCT_OFFSET (LdmGreeterClass, user_added),
2029                       NULL, NULL,
2030                       g_cclosure_marshal_VOID__OBJECT,
2031                       G_TYPE_NONE, 1, LDM_TYPE_USER);
2032
2033     /**
2034      * LdmGreeter::user-changed:
2035      * @greeter: A #LdmGreeter
2036      *
2037      * The ::user-changed signal gets emitted when a user account is modified.
2038      **/
2039     signals[USER_CHANGED] =
2040         g_signal_new ("user-changed",
2041                       G_TYPE_FROM_CLASS (klass),
2042                       G_SIGNAL_RUN_LAST,
2043                       G_STRUCT_OFFSET (LdmGreeterClass, user_changed),
2044                       NULL, NULL,
2045                       g_cclosure_marshal_VOID__OBJECT,
2046                       G_TYPE_NONE, 1, LDM_TYPE_USER);
2047
2048     /**
2049      * LdmGreeter::user-removed:
2050      * @greeter: A #LdmGreeter
2051      *
2052      * The ::user-removed signal gets emitted when a user account is removed.
2053      **/
2054     signals[USER_REMOVED] =
2055         g_signal_new ("user-removed",
2056                       G_TYPE_FROM_CLASS (klass),
2057                       G_SIGNAL_RUN_LAST,
2058                       G_STRUCT_OFFSET (LdmGreeterClass, user_removed),
2059                       NULL, NULL,
2060                       g_cclosure_marshal_VOID__OBJECT,
2061                       G_TYPE_NONE, 1, LDM_TYPE_USER);
2062
2063     /**
2064      * LdmGreeter::quit:
2065      * @greeter: A #LdmGreeter
2066      *
2067      * The ::quit signal gets emitted when the greeter should exit.
2068      **/
2069     signals[QUIT] =
2070         g_signal_new ("quit",
2071                       G_TYPE_FROM_CLASS (klass),
2072                       G_SIGNAL_RUN_LAST,
2073                       G_STRUCT_OFFSET (LdmGreeterClass, quit),
2074                       NULL, NULL,
2075                       g_cclosure_marshal_VOID__VOID,
2076                       G_TYPE_NONE, 0);
2077 }