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