]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - liblightdm-gobject/greeter.c
More guest account work, change liblightdm API
[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_login:
1250  * @greeter: A #LdmGreeter
1251  * @username: A username
1252  *
1253  * Starts the authentication procedure for a user.
1254  **/
1255 void
1256 ldm_greeter_login (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_LOGIN, string_length (username));
1267     write_string (greeter, username);
1268     flush (greeter);
1269 }
1270
1271 /**
1272  * ldm_greeter_login_as_guest:
1273  * @greeter: A #LdmGreeter
1274  *
1275  * Starts the authentication procedure for the guest user.
1276  **/
1277 void
1278 ldm_greeter_login_as_guest (LdmGreeter *greeter)
1279 {
1280     g_return_if_fail (LDM_IS_GREETER (greeter));
1281
1282     greeter->priv->in_authentication = TRUE;
1283     greeter->priv->is_authenticated = FALSE;
1284     g_free (greeter->priv->authentication_user);
1285     greeter->priv->authentication_user = NULL;
1286     g_debug ("Starting authentication for guest account...");
1287     write_header (greeter, GREETER_MESSAGE_LOGIN_AS_GUEST, 0);
1288     flush (greeter);
1289 }
1290
1291 /**
1292  * ldm_greeter_provide_secret:
1293  * @greeter: A #LdmGreeter
1294  * @secret: Response to a prompt
1295  *
1296  * Provide secret information from a prompt.
1297  **/
1298 void
1299 ldm_greeter_provide_secret (LdmGreeter *greeter, const gchar *secret)
1300 {
1301     g_return_if_fail (LDM_IS_GREETER (greeter));
1302     g_return_if_fail (secret != NULL);
1303
1304     g_debug ("Providing secret to display manager");
1305     write_header (greeter, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, int_length () + string_length (secret));
1306     // FIXME: Could be multiple secrets required
1307     write_int (greeter, 1);
1308     write_string (greeter, secret);
1309     flush (greeter);
1310 }
1311
1312 /**
1313  * ldm_greeter_cancel_authentication:
1314  * @greeter: A #LdmGreeter
1315  *
1316  * Cancel the current user authentication.
1317  **/
1318 void
1319 ldm_greeter_cancel_authentication (LdmGreeter *greeter)
1320 {
1321     g_return_if_fail (LDM_IS_GREETER (greeter));
1322     write_header (greeter, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0);
1323     flush (greeter);
1324 }
1325
1326 /**
1327  * ldm_greeter_get_in_authentication:
1328  * @greeter: A #LdmGreeter
1329  *
1330  * Checks if the greeter is in the process of authenticating.
1331  *
1332  * Return value: TRUE if the greeter is authenticating a user.
1333  **/
1334 gboolean
1335 ldm_greeter_get_in_authentication (LdmGreeter *greeter)
1336 {
1337     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1338     return greeter->priv->in_authentication;
1339 }
1340
1341 /**
1342  * ldm_greeter_get_is_authenticated:
1343  * @greeter: A #LdmGreeter
1344  *
1345  * Checks if the greeter has successfully authenticated.
1346  *
1347  * Return value: TRUE if the greeter is authenticated for login.
1348  **/
1349 gboolean
1350 ldm_greeter_get_is_authenticated (LdmGreeter *greeter)
1351 {
1352     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1353     return greeter->priv->is_authenticated;
1354 }
1355
1356 /**
1357  * ldm_greeter_get_authentication_user:
1358  * @greeter: A #LdmGreeter
1359  *
1360  * Get the user that is being authenticated.
1361  *
1362  * Return value: The username of the authentication user being authenticated or NULL if no authentication in progress.
1363  */
1364 const gchar *
1365 ldm_greeter_get_authentication_user (LdmGreeter *greeter)
1366 {
1367     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
1368     return greeter->priv->authentication_user;
1369 }
1370
1371 /**
1372  * ldm_greeter_start_session:
1373  * @greeter: A #LdmGreeter
1374  * @session: (allow-none): The session to log into or NULL to use the default
1375  * @language: (allow-none): The language to use or NULL to use the default
1376  *
1377  * Start a session for the logged in user.
1378  **/
1379 void
1380 ldm_greeter_start_session (LdmGreeter *greeter, const gchar *session, const gchar *language)
1381 {
1382     g_return_if_fail (LDM_IS_GREETER (greeter));
1383   
1384     if (!session)
1385         session = "";
1386     if (!language)
1387         language = "";
1388
1389     g_debug ("Starting session %s with language %s", session, language);
1390     write_header (greeter, GREETER_MESSAGE_START_SESSION, string_length (session) + string_length (language));
1391     write_string (greeter, session);
1392     write_string (greeter, language);
1393     flush (greeter);
1394 }
1395
1396 /**
1397  * ldm_greeter_start_session_with_defaults:
1398  * @greeter: A #LdmGreeter
1399  *
1400  * Login a user to a session using default settings for that user.
1401  **/
1402 void
1403 ldm_greeter_start_session_with_defaults (LdmGreeter *greeter)
1404 {
1405     ldm_greeter_start_session (greeter, NULL, NULL);
1406 }
1407
1408 static gboolean
1409 upower_call_function (LdmGreeter *greeter, const gchar *function, gboolean has_result)
1410 {
1411     GDBusProxy *proxy;
1412     GVariant *result;
1413     GError *error = NULL;
1414     gboolean function_result = FALSE;
1415
1416     proxy = g_dbus_proxy_new_sync (greeter->priv->system_bus,
1417                                    G_DBUS_PROXY_FLAGS_NONE,
1418                                    NULL,
1419                                    "org.freedesktop.UPower",
1420                                    "/org/freedesktop/UPower",
1421                                    "org.freedesktop.UPower",
1422                                    NULL, NULL);
1423     result = g_dbus_proxy_call_sync (proxy,
1424                                      function,
1425                                      NULL,
1426                                      G_DBUS_CALL_FLAGS_NONE,
1427                                      -1,
1428                                      NULL,
1429                                      &error);
1430     g_object_unref (proxy);
1431
1432     if (!result)
1433         g_warning ("Error calling UPower function %s: %s", function, error->message);
1434     g_clear_error (&error);
1435     if (!result)
1436         return FALSE;
1437
1438     if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(b)")))
1439         g_variant_get (result, "(b)", &function_result);
1440
1441     g_variant_unref (result);
1442     return function_result;
1443 }
1444
1445 /**
1446  * ldm_greeter_get_can_suspend:
1447  * @greeter: A #LdmGreeter
1448  *
1449  * Checks if the greeter is authorized to do a system suspend.
1450  *
1451  * Return value: TRUE if the greeter can suspend the system
1452  **/
1453 gboolean
1454 ldm_greeter_get_can_suspend (LdmGreeter *greeter)
1455 {
1456     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1457     return upower_call_function (greeter, "SuspendAllowed", TRUE);
1458 }
1459
1460 /**
1461  * ldm_greeter_suspend:
1462  * @greeter: A #LdmGreeter
1463  *
1464  * Triggers a system suspend.
1465  **/
1466 void
1467 ldm_greeter_suspend (LdmGreeter *greeter)
1468 {
1469     g_return_if_fail (LDM_IS_GREETER (greeter));
1470     upower_call_function (greeter, "Suspend", FALSE);
1471 }
1472
1473 /**
1474  * ldm_greeter_get_can_hibernate:
1475  * @greeter: A #LdmGreeter
1476  *
1477  * Checks if the greeter is authorized to do a system hibernate.
1478  *
1479  * Return value: TRUE if the greeter can hibernate the system
1480  **/
1481 gboolean
1482 ldm_greeter_get_can_hibernate (LdmGreeter *greeter)
1483 {
1484     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1485     return upower_call_function (greeter, "HibernateAllowed", TRUE);
1486 }
1487
1488 /**
1489  * ldm_greeter_hibernate:
1490  * @greeter: A #LdmGreeter
1491  *
1492  * Triggers a system hibernate.
1493  **/
1494 void
1495 ldm_greeter_hibernate (LdmGreeter *greeter)
1496 {
1497     g_return_if_fail (LDM_IS_GREETER (greeter));
1498     upower_call_function (greeter, "Hibernate", FALSE);
1499 }
1500
1501 static gboolean
1502 ck_call_function (LdmGreeter *greeter, const gchar *function, gboolean has_result)
1503 {
1504     GDBusProxy *proxy;
1505     GVariant *result;
1506     GError *error = NULL;
1507     gboolean function_result = FALSE;
1508
1509     proxy = g_dbus_proxy_new_sync (greeter->priv->system_bus,
1510                                    G_DBUS_PROXY_FLAGS_NONE,
1511                                    NULL,
1512                                    "org.freedesktop.ConsoleKit",
1513                                    "/org/freedesktop/ConsoleKit/Manager",
1514                                    "org.freedesktop.ConsoleKit.Manager",
1515                                    NULL, NULL);
1516     result = g_dbus_proxy_call_sync (proxy,
1517                                      function,
1518                                      NULL,
1519                                      G_DBUS_CALL_FLAGS_NONE,
1520                                      -1,
1521                                      NULL,
1522                                      &error);
1523     g_object_unref (proxy);
1524
1525     if (!result)
1526         g_warning ("Error calling ConsoleKit function %s: %s", function, error->message);
1527     g_clear_error (&error);
1528     if (!result)
1529         return FALSE;
1530
1531     if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(b)")))
1532         g_variant_get (result, "(b)", &function_result);
1533
1534     g_variant_unref (result);
1535     return function_result;
1536 }
1537
1538 /**
1539  * ldm_greeter_get_can_restart:
1540  * @greeter: A #LdmGreeter
1541  *
1542  * Checks if the greeter is authorized to do a system restart.
1543  *
1544  * Return value: TRUE if the greeter can restart the system
1545  **/
1546 gboolean
1547 ldm_greeter_get_can_restart (LdmGreeter *greeter)
1548 {
1549     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1550     return ck_call_function (greeter, "CanRestart", TRUE);
1551 }
1552
1553 /**
1554  * ldm_greeter_restart:
1555  * @greeter: A #LdmGreeter
1556  *
1557  * Triggers a system restart.
1558  **/
1559 void
1560 ldm_greeter_restart (LdmGreeter *greeter)
1561 {
1562     g_return_if_fail (LDM_IS_GREETER (greeter));
1563     ck_call_function (greeter, "Restart", FALSE);
1564 }
1565
1566 /**
1567  * ldm_greeter_get_can_shutdown:
1568  * @greeter: A #LdmGreeter
1569  *
1570  * Checks if the greeter is authorized to do a system shutdown.
1571  *
1572  * Return value: TRUE if the greeter can shutdown the system
1573  **/
1574 gboolean
1575 ldm_greeter_get_can_shutdown (LdmGreeter *greeter)
1576 {
1577     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1578     return ck_call_function (greeter, "CanStop", TRUE);
1579 }
1580
1581 /**
1582  * ldm_greeter_shutdown:
1583  * @greeter: A #LdmGreeter
1584  *
1585  * Triggers a system shutdown.
1586  **/
1587 void
1588 ldm_greeter_shutdown (LdmGreeter *greeter)
1589 {
1590     g_return_if_fail (LDM_IS_GREETER (greeter));
1591     ck_call_function (greeter, "Stop", FALSE);
1592 }
1593
1594 /**
1595  * ldm_greeter_get_user_defaults:
1596  * @greeter: A #LdmGreeter
1597  * @username: The user to check
1598  * @language: (out): Default language for this user.
1599  * @layout: (out): Default keyboard layout for this user.
1600  * @session: (out): Default session for this user.
1601  *
1602  * Get the default settings for a given user.  If the user does not exist FALSE
1603  * is returned and language, layout and session are not set.
1604  *
1605  * Return value: TRUE if this user exists.
1606  **/
1607 gboolean
1608 ldm_greeter_get_user_defaults (LdmGreeter *greeter, const gchar *username, gchar **language, gchar **layout, gchar **session)
1609 {
1610     gsize offset = 0;
1611     guint32 id;
1612
1613     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1614     g_return_val_if_fail (username != NULL, FALSE);
1615
1616     write_header (greeter, GREETER_MESSAGE_GET_USER_DEFAULTS, string_length (username));
1617     write_string (greeter, username);
1618     flush (greeter);
1619
1620     if (!read_packet (greeter, TRUE))
1621     {
1622         g_warning ("Error reading user defaults from server");
1623         return FALSE;
1624     }
1625
1626     id = read_int (greeter, &offset);
1627     g_assert (id == GREETER_MESSAGE_USER_DEFAULTS);
1628     read_int (greeter, &offset);
1629     *language = read_string (greeter, &offset);
1630     *layout = read_string (greeter, &offset);
1631     *session = read_string (greeter, &offset);
1632
1633     g_debug ("User defaults for %s: language=%s, layout=%s, session=%s", username, *language, *layout, *session);
1634
1635     greeter->priv->n_read = 0;
1636
1637     return TRUE;
1638 }
1639
1640 static void
1641 ldm_greeter_init (LdmGreeter *greeter)
1642 {
1643     greeter->priv = G_TYPE_INSTANCE_GET_PRIVATE (greeter, LDM_TYPE_GREETER, LdmGreeterPrivate);
1644     greeter->priv->read_buffer = g_malloc (HEADER_SIZE);
1645
1646     g_debug ("default-language=%s", ldm_greeter_get_default_language (greeter));
1647 }
1648
1649 static void
1650 ldm_greeter_set_property (GObject      *object,
1651                           guint         prop_id,
1652                           const GValue *value,
1653                           GParamSpec   *pspec)
1654 {
1655     LdmGreeter *self;
1656
1657     self = LDM_GREETER (object);
1658
1659     switch (prop_id) {
1660     case PROP_LAYOUT:
1661         ldm_greeter_set_layout(self, g_value_get_string (value));
1662         break;
1663     default:
1664         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1665         break;
1666     }
1667 }
1668
1669 static void
1670 ldm_greeter_get_property (GObject    *object,
1671                           guint       prop_id,
1672                           GValue     *value,
1673                           GParamSpec *pspec)
1674 {
1675     LdmGreeter *self;
1676
1677     self = LDM_GREETER (object);
1678
1679     switch (prop_id) {
1680     case PROP_HOSTNAME:
1681         g_value_set_string (value, ldm_greeter_get_hostname (self));
1682         break;
1683     case PROP_NUM_USERS:
1684         g_value_set_int (value, ldm_greeter_get_num_users (self));
1685         break;
1686     case PROP_USERS:
1687         break;
1688     case PROP_DEFAULT_LANGUAGE:
1689         g_value_set_string (value, ldm_greeter_get_default_language (self));
1690         break;
1691     case PROP_LAYOUTS:
1692         break;
1693     case PROP_LAYOUT:
1694         g_value_set_string (value, ldm_greeter_get_layout (self));
1695         break;
1696     case PROP_SESSIONS:
1697         break;
1698     case PROP_DEFAULT_SESSION:
1699         g_value_set_string (value, ldm_greeter_get_default_session (self));
1700         break;
1701     case PROP_TIMED_LOGIN_USER:
1702         g_value_set_string (value, ldm_greeter_get_timed_login_user (self));
1703         break;
1704     case PROP_TIMED_LOGIN_DELAY:
1705         g_value_set_int (value, ldm_greeter_get_timed_login_delay (self));
1706         break;
1707     case PROP_AUTHENTICATION_USER:
1708         g_value_set_string (value, ldm_greeter_get_authentication_user (self));
1709         break;
1710     case PROP_IN_AUTHENTICATION:
1711         g_value_set_boolean (value, ldm_greeter_get_in_authentication (self));
1712         break;
1713     case PROP_IS_AUTHENTICATED:
1714         g_value_set_boolean (value, ldm_greeter_get_is_authenticated (self));
1715         break;
1716     case PROP_CAN_SUSPEND:
1717         g_value_set_boolean (value, ldm_greeter_get_can_suspend (self));
1718         break;
1719     case PROP_CAN_HIBERNATE:
1720         g_value_set_boolean (value, ldm_greeter_get_can_hibernate (self));
1721         break;
1722     case PROP_CAN_RESTART:
1723         g_value_set_boolean (value, ldm_greeter_get_can_restart (self));
1724         break;
1725     case PROP_CAN_SHUTDOWN:
1726         g_value_set_boolean (value, ldm_greeter_get_can_shutdown (self));
1727         break;
1728     default:
1729         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1730         break;
1731     }
1732 }
1733
1734 static void
1735 ldm_greeter_class_init (LdmGreeterClass *klass)
1736 {
1737     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1738
1739     g_type_class_add_private (klass, sizeof (LdmGreeterPrivate));
1740
1741     object_class->set_property = ldm_greeter_set_property;
1742     object_class->get_property = ldm_greeter_get_property;
1743
1744     g_object_class_install_property (object_class,
1745                                      PROP_NUM_USERS,
1746                                      g_param_spec_string ("hostname",
1747                                                           "hostname",
1748                                                           "Hostname displaying greeter for",
1749                                                           NULL,
1750                                                           G_PARAM_READABLE));
1751     g_object_class_install_property (object_class,
1752                                      PROP_NUM_USERS,
1753                                      g_param_spec_int ("num-users",
1754                                                        "num-users",
1755                                                        "Number of login users",
1756                                                        0, G_MAXINT, 0,
1757                                                        G_PARAM_READABLE));
1758     /*g_object_class_install_property (object_class,
1759                                      PROP_USERS,
1760                                      g_param_spec_list ("users",
1761                                                         "users",
1762                                                         "Users that can login"));
1763     g_object_class_install_property (object_class,
1764                                      PROP_DEFAULT_LANGUAGE,
1765                                      g_param_spec_string ("default-language",
1766                                                           "default-language",
1767                                                           "Default language",
1768                                                           NULL,
1769                                                           G_PARAM_READWRITE));
1770     g_object_class_install_property (object_class,
1771                                      PROP_LAYOUTS,
1772                                      g_param_spec_list ("layouts",
1773                                                         "layouts",
1774                                                         "Available keyboard layouts"));*/
1775     g_object_class_install_property (object_class,
1776                                      PROP_LAYOUT,
1777                                      g_param_spec_string ("layout",
1778                                                           "layout",
1779                                                           "Current keyboard layout",
1780                                                           NULL,
1781                                                           G_PARAM_READWRITE));
1782     /*g_object_class_install_property (object_class,
1783                                      PROP_SESSIONS,
1784                                      g_param_spec_list ("sessions",
1785                                                         "sessions",
1786                                                         "Available sessions"));*/
1787     g_object_class_install_property (object_class,
1788                                      PROP_DEFAULT_SESSION,
1789                                      g_param_spec_string ("default-session",
1790                                                           "default-session",
1791                                                           "Default session",
1792                                                           NULL,
1793                                                           G_PARAM_READWRITE));
1794     g_object_class_install_property (object_class,
1795                                      PROP_TIMED_LOGIN_USER,
1796                                      g_param_spec_string ("timed-login-user",
1797                                                           "timed-login-user",
1798                                                           "User to login as when timed expires",
1799                                                           NULL,
1800                                                           G_PARAM_READABLE));
1801     g_object_class_install_property (object_class,
1802                                      PROP_TIMED_LOGIN_DELAY,
1803                                      g_param_spec_int ("login-delay",
1804                                                        "login-delay",
1805                                                        "Number of seconds until logging in as default user",
1806                                                        G_MININT, G_MAXINT, 0,
1807                                                        G_PARAM_READABLE));
1808     g_object_class_install_property (object_class,
1809                                      PROP_AUTHENTICATION_USER,
1810                                      g_param_spec_string ("authentication-user",
1811                                                           "authentication-user",
1812                                                           "The user being authenticated",
1813                                                           NULL,
1814                                                           G_PARAM_READABLE));
1815     g_object_class_install_property (object_class,
1816                                      PROP_IN_AUTHENTICATION,
1817                                      g_param_spec_boolean ("in-authentication",
1818                                                            "in-authentication",
1819                                                            "TRUE if a user is being authenticated",
1820                                                            FALSE,
1821                                                            G_PARAM_READABLE));
1822     g_object_class_install_property (object_class,
1823                                      PROP_IS_AUTHENTICATED,
1824                                      g_param_spec_boolean ("is-authenticated",
1825                                                            "is-authenticated",
1826                                                            "TRUE if the selected user is authenticated",
1827                                                            FALSE,
1828                                                            G_PARAM_READABLE));
1829     g_object_class_install_property (object_class,
1830                                      PROP_CAN_SUSPEND,
1831                                      g_param_spec_boolean ("can-suspend",
1832                                                            "can-suspend",
1833                                                            "TRUE if allowed to suspend the system",
1834                                                            FALSE,
1835                                                            G_PARAM_READABLE));
1836     g_object_class_install_property (object_class,
1837                                      PROP_CAN_HIBERNATE,
1838                                      g_param_spec_boolean ("can-hibernate",
1839                                                            "can-hibernate",
1840                                                            "TRUE if allowed to hibernate the system",
1841                                                            FALSE,
1842                                                            G_PARAM_READABLE));
1843     g_object_class_install_property (object_class,
1844                                      PROP_CAN_RESTART,
1845                                      g_param_spec_boolean ("can-restart",
1846                                                            "can-restart",
1847                                                            "TRUE if allowed to restart the system",
1848                                                            FALSE,
1849                                                            G_PARAM_READABLE));
1850     g_object_class_install_property (object_class,
1851                                      PROP_CAN_SHUTDOWN,
1852                                      g_param_spec_boolean ("can-shutdown",
1853                                                            "can-shutdown",
1854                                                            "TRUE if allowed to shutdown the system",
1855                                                            FALSE,
1856                                                            G_PARAM_READABLE));
1857
1858     /**
1859      * LdmGreeter::connected:
1860      * @greeter: A #LdmGreeter
1861      *
1862      * The ::connected signal gets emitted when the greeter connects to the
1863      * LightDM server.
1864      **/
1865     signals[CONNECTED] =
1866         g_signal_new ("connected",
1867                       G_TYPE_FROM_CLASS (klass),
1868                       G_SIGNAL_RUN_LAST,
1869                       G_STRUCT_OFFSET (LdmGreeterClass, connected),
1870                       NULL, NULL,
1871                       g_cclosure_marshal_VOID__VOID,
1872                       G_TYPE_NONE, 0);
1873
1874     /**
1875      * LdmGreeter::show-prompt:
1876      * @greeter: A #LdmGreeter
1877      * @text: Prompt text
1878      *
1879      * The ::show-prompt signal gets emitted when the greeter should show a
1880      * prompt to the user.  The given text should be displayed and an input
1881      * field for the user to provide a response.
1882      *
1883      * Call ldm_greeter_provide_secret() with the resultant input or
1884      * ldm_greeter_cancel_authentication() to abort the authentication.
1885      **/
1886     signals[SHOW_PROMPT] =
1887         g_signal_new ("show-prompt",
1888                       G_TYPE_FROM_CLASS (klass),
1889                       G_SIGNAL_RUN_LAST,
1890                       G_STRUCT_OFFSET (LdmGreeterClass, show_prompt),
1891                       NULL, NULL,
1892                       g_cclosure_marshal_VOID__STRING,
1893                       G_TYPE_NONE, 1, G_TYPE_STRING);
1894
1895     /**
1896      * LdmGreeter::show-message:
1897      * @greeter: A #LdmGreeter
1898      * @text: Message text
1899      *
1900      * The ::show-message signal gets emitted when the greeter
1901      * should show an informational message to the user.
1902      **/
1903     signals[SHOW_MESSAGE] =
1904         g_signal_new ("show-message",
1905                       G_TYPE_FROM_CLASS (klass),
1906                       G_SIGNAL_RUN_LAST,
1907                       G_STRUCT_OFFSET (LdmGreeterClass, show_message),
1908                       NULL, NULL,
1909                       g_cclosure_marshal_VOID__STRING,
1910                       G_TYPE_NONE, 1, G_TYPE_STRING);
1911
1912     /**
1913      * LdmGreeter::show-error:
1914      * @greeter: A #LdmGreeter
1915      * @text: Message text
1916      *
1917      * The ::show-error signal gets emitted when the greeter
1918      * should show an error message to the user.
1919      **/
1920     signals[SHOW_ERROR] =
1921         g_signal_new ("show-error",
1922                       G_TYPE_FROM_CLASS (klass),
1923                       G_SIGNAL_RUN_LAST,
1924                       G_STRUCT_OFFSET (LdmGreeterClass, show_error),
1925                       NULL, NULL,
1926                       g_cclosure_marshal_VOID__STRING,
1927                       G_TYPE_NONE, 1, G_TYPE_STRING);
1928
1929     /**
1930      * LdmGreeter::authentication-complete:
1931      * @greeter: A #LdmGreeter
1932      *
1933      * The ::authentication-complete signal gets emitted when the greeter
1934      * has completed authentication.
1935      *
1936      * Call ldm_greeter_get_is_authenticated() to check if the authentication
1937      * was successful.
1938      **/
1939     signals[AUTHENTICATION_COMPLETE] =
1940         g_signal_new ("authentication-complete",
1941                       G_TYPE_FROM_CLASS (klass),
1942                       G_SIGNAL_RUN_LAST,
1943                       G_STRUCT_OFFSET (LdmGreeterClass, authentication_complete),
1944                       NULL, NULL,
1945                       g_cclosure_marshal_VOID__VOID,
1946                       G_TYPE_NONE, 0);
1947
1948     /**
1949      * LdmGreeter::timed-login:
1950      * @greeter: A #LdmGreeter
1951      * @username: A username
1952      *
1953      * The ::timed-login signal gets emitted when the default user timer
1954      * has expired.
1955      **/
1956     signals[TIMED_LOGIN] =
1957         g_signal_new ("timed-login",
1958                       G_TYPE_FROM_CLASS (klass),
1959                       G_SIGNAL_RUN_LAST,
1960                       G_STRUCT_OFFSET (LdmGreeterClass, timed_login),
1961                       NULL, NULL,
1962                       g_cclosure_marshal_VOID__STRING,
1963                       G_TYPE_NONE, 1, G_TYPE_STRING);
1964
1965     /**
1966      * LdmGreeter::user-added:
1967      * @greeter: A #LdmGreeter
1968      *
1969      * The ::user-added signal gets emitted when a user account is created.
1970      **/
1971     signals[USER_ADDED] =
1972         g_signal_new ("user-added",
1973                       G_TYPE_FROM_CLASS (klass),
1974                       G_SIGNAL_RUN_LAST,
1975                       G_STRUCT_OFFSET (LdmGreeterClass, user_added),
1976                       NULL, NULL,
1977                       g_cclosure_marshal_VOID__OBJECT,
1978                       G_TYPE_NONE, 1, LDM_TYPE_USER);
1979
1980     /**
1981      * LdmGreeter::user-changed:
1982      * @greeter: A #LdmGreeter
1983      *
1984      * The ::user-changed signal gets emitted when a user account is modified.
1985      **/
1986     signals[USER_CHANGED] =
1987         g_signal_new ("user-changed",
1988                       G_TYPE_FROM_CLASS (klass),
1989                       G_SIGNAL_RUN_LAST,
1990                       G_STRUCT_OFFSET (LdmGreeterClass, user_changed),
1991                       NULL, NULL,
1992                       g_cclosure_marshal_VOID__OBJECT,
1993                       G_TYPE_NONE, 1, LDM_TYPE_USER);
1994
1995     /**
1996      * LdmGreeter::user-removed:
1997      * @greeter: A #LdmGreeter
1998      *
1999      * The ::user-removed signal gets emitted when a user account is removed.
2000      **/
2001     signals[USER_REMOVED] =
2002         g_signal_new ("user-removed",
2003                       G_TYPE_FROM_CLASS (klass),
2004                       G_SIGNAL_RUN_LAST,
2005                       G_STRUCT_OFFSET (LdmGreeterClass, user_removed),
2006                       NULL, NULL,
2007                       g_cclosure_marshal_VOID__OBJECT,
2008                       G_TYPE_NONE, 1, LDM_TYPE_USER);
2009
2010     /**
2011      * LdmGreeter::quit:
2012      * @greeter: A #LdmGreeter
2013      *
2014      * The ::quit signal gets emitted when the greeter should exit.
2015      **/
2016     signals[QUIT] =
2017         g_signal_new ("quit",
2018                       G_TYPE_FROM_CLASS (klass),
2019                       G_SIGNAL_RUN_LAST,
2020                       G_STRUCT_OFFSET (LdmGreeterClass, quit),
2021                       NULL, NULL,
2022                       g_cclosure_marshal_VOID__VOID,
2023                       G_TYPE_NONE, 0);
2024 }