]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - liblightdm-gobject/greeter.c
Add liblightdm function to ensure a shared data directory
[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 2 or version 3 of the License.
8  * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
9  */
10
11 #include <config.h>
12
13 #include <stdlib.h>
14 #include <string.h>
15 #include <security/pam_appl.h>
16
17 #include "lightdm/greeter.h"
18
19 enum {
20     PROP_0,
21     PROP_DEFAULT_SESSION_HINT,
22     PROP_HIDE_USERS_HINT,
23     PROP_SHOW_MANUAL_LOGIN_HINT,
24     PROP_SHOW_REMOTE_LOGIN_HINT,
25     PROP_LOCK_HINT,
26     PROP_HAS_GUEST_ACCOUNT_HINT,
27     PROP_SELECT_USER_HINT,
28     PROP_SELECT_GUEST_HINT,
29     PROP_AUTOLOGIN_USER_HINT,
30     PROP_AUTOLOGIN_GUEST_HINT,
31     PROP_AUTOLOGIN_TIMEOUT_HINT,
32     PROP_AUTHENTICATION_USER,
33     PROP_IN_AUTHENTICATION,
34     PROP_IS_AUTHENTICATED,
35 };
36
37 enum {
38     SHOW_PROMPT,
39     SHOW_MESSAGE,
40     AUTHENTICATION_COMPLETE,
41     AUTOLOGIN_TIMER_EXPIRED,
42     LAST_SIGNAL
43 };
44 static guint signals[LAST_SIGNAL] = { 0 };
45
46 typedef struct
47 {
48     gboolean connected;
49
50     GIOChannel *to_server_channel, *from_server_channel;
51     guint8 *read_buffer;
52     gsize n_read;
53
54     gsize n_responses_waiting;
55     GList *responses_received;
56
57     GHashTable *hints;
58     guint autologin_timeout;
59
60     gchar *authentication_user;
61     gboolean in_authentication;
62     gboolean is_authenticated;
63     guint32 authenticate_sequence_number;
64     gboolean cancelling_authentication;
65 } LightDMGreeterPrivate;
66
67 G_DEFINE_TYPE (LightDMGreeter, lightdm_greeter, G_TYPE_OBJECT);
68
69 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_GREETER, LightDMGreeterPrivate)
70
71 #define HEADER_SIZE 8
72 #define MAX_MESSAGE_LENGTH 1024
73
74 /* Messages from the greeter to the server */
75 typedef enum
76 {
77     GREETER_MESSAGE_CONNECT = 0,
78     GREETER_MESSAGE_AUTHENTICATE,
79     GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
80     GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
81     GREETER_MESSAGE_START_SESSION,
82     GREETER_MESSAGE_CANCEL_AUTHENTICATION,
83     GREETER_MESSAGE_SET_LANGUAGE,
84     GREETER_MESSAGE_AUTHENTICATE_REMOTE,
85     GREETER_MESSAGE_ENSURE_SHARED_DIR,
86 } GreeterMessage;
87
88 /* Messages from the server to the greeter */
89 typedef enum
90 {
91     SERVER_MESSAGE_CONNECTED = 0,
92     SERVER_MESSAGE_PROMPT_AUTHENTICATION,
93     SERVER_MESSAGE_END_AUTHENTICATION,
94     SERVER_MESSAGE_SESSION_RESULT
95 } ServerMessage;
96
97 /**
98  * lightdm_greeter_new:
99  *
100  * Create a new greeter.
101  *
102  * Return value: the new #LightDMGreeter
103  **/
104 LightDMGreeter *
105 lightdm_greeter_new ()
106 {
107     return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
108 }
109
110 static gboolean
111 timed_login_cb (gpointer data)
112 {
113     LightDMGreeter *greeter = data;
114     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
115
116     priv->autologin_timeout = 0;
117     g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
118
119     return FALSE;
120 }
121
122 static guint32
123 int_length (void)
124 {
125     return 4;
126 }
127
128 static void
129 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
130 {
131     if (*offset + 4 >= buffer_length)
132         return;
133     buffer[*offset] = value >> 24;
134     buffer[*offset+1] = (value >> 16) & 0xFF;
135     buffer[*offset+2] = (value >> 8) & 0xFF;
136     buffer[*offset+3] = value & 0xFF;
137     *offset += 4;
138 }
139
140 static void
141 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
142 {
143     gint length = 0;
144
145     if (value)
146         length = strlen (value);
147     write_int (buffer, buffer_length, length, offset);
148     if (*offset + length >= buffer_length)
149         return;
150     memcpy (buffer + *offset, value, length);
151     *offset += length;
152 }
153
154 static guint32
155 read_int (guint8 *message, gsize message_length, gsize *offset)
156 {
157     guint32 value;
158     guint8 *buffer;
159
160     if (message_length - *offset < int_length ())
161     {
162         g_warning ("Not enough space for int, need %i, got %zi", int_length (), message_length - *offset);
163         return 0;
164     }
165
166     buffer = message + *offset;
167     value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
168     *offset += int_length ();
169
170     return value;
171 }
172
173 static gchar *
174 read_string (guint8 *message, gsize message_length, gsize *offset)
175 {
176     guint32 length;
177     gchar *value;
178
179     length = read_int (message, message_length, offset);
180     if (message_length - *offset < length)
181     {
182         g_warning ("Not enough space for string, need %u, got %zu", length, message_length - *offset);
183         return g_strdup ("");
184     }
185
186     value = g_malloc (sizeof (gchar) * (length + 1));
187     memcpy (value, message + *offset, length);
188     value[length] = '\0';
189     *offset += length;
190
191     return value;
192 }
193
194 static guint32
195 string_length (const gchar *value)
196 {
197     if (value)
198         return int_length () + strlen (value);
199     else
200         return int_length ();
201 }
202
203 static void
204 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
205 {
206     write_int (buffer, buffer_length, id, offset);
207     write_int (buffer, buffer_length, length, offset);
208 }
209
210 static guint32
211 get_message_length (guint8 *message, gsize message_length)
212 {
213     gsize offset = 4;
214     return read_int (message, message_length, &offset);
215 }
216
217 static void
218 write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
219 {
220     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
221     GIOStatus status;
222     GError *error = NULL;
223     guint32 stated_length;
224
225     /* Double check that we're sending well-formed messages.  If we say we're
226        sending more than we do, we end up DOS'ing lightdm as it waits for the
227        rest.  If we say we're sending less than we do, we confuse the heck out
228        of lightdm, as it starts reading headers from the middle of our
229        messages. */
230     stated_length = HEADER_SIZE + get_message_length (message, message_length);
231     if (stated_length != message_length)
232     {
233         g_warning ("Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu", stated_length, message_length);
234         return;
235     }
236
237     status = g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, &error);
238     if (error)
239         g_warning ("Error writing to daemon: %s", error->message);
240     g_clear_error (&error);
241     if (status == G_IO_STATUS_NORMAL)
242         g_debug ("Wrote %zi bytes to daemon", message_length);
243     g_io_channel_flush (priv->to_server_channel, NULL);
244 }
245
246 static void
247 handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
248 {
249     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
250     gchar *version;
251     GString *hint_string;
252     int timeout;
253
254     version = read_string (message, message_length, offset);
255     hint_string = g_string_new ("");
256     while (*offset < message_length)
257     {
258         gchar *name, *value;
259       
260         name = read_string (message, message_length, offset);
261         value = read_string (message, message_length, offset);
262         g_hash_table_insert (priv->hints, name, value);
263         g_string_append_printf (hint_string, " %s=%s", name, value);
264     }
265
266     g_debug ("Connected version=%s%s", version, hint_string->str);
267     g_free (version);
268     g_string_free (hint_string, TRUE);
269
270     /* Set timeout for default login */
271     timeout = lightdm_greeter_get_autologin_timeout_hint (greeter);
272     if (timeout)
273     {
274         g_debug ("Setting autologin timer for %d seconds", timeout);
275         priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
276     }
277 }
278
279 static void
280 handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
281 {
282     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
283     guint32 sequence_number, n_messages, i;
284     gchar *username;
285
286     sequence_number = read_int (message, message_length, offset);
287     if (sequence_number != priv->authenticate_sequence_number)
288     {
289         g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
290         return;
291     }
292
293     if (priv->cancelling_authentication)
294     {
295         g_debug ("Ignoring prompt authentication as waiting for it to cancel");
296         return;
297     }
298
299     /* Update username */
300     username = read_string (message, message_length, offset);
301     if (strcmp (username, "") == 0)
302     {
303         g_free (username);
304         username = NULL;
305     }
306     g_free (priv->authentication_user);
307     priv->authentication_user = username;
308
309     g_list_free_full (priv->responses_received, g_free);
310     priv->responses_received = NULL;
311     priv->n_responses_waiting = 0;
312
313     n_messages = read_int (message, message_length, offset);
314     g_debug ("Prompt user with %d message(s)", n_messages);
315
316     for (i = 0; i < n_messages; i++)
317     {
318         int style;
319         gchar *text;
320
321         style = read_int (message, message_length, offset);
322         text = read_string (message, message_length, offset);
323
324         // FIXME: Should stop on prompts?
325         switch (style)
326         {
327         case PAM_PROMPT_ECHO_OFF:
328             priv->n_responses_waiting++;
329             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_SECRET);
330             break;
331         case PAM_PROMPT_ECHO_ON:
332             priv->n_responses_waiting++;
333             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_QUESTION);
334             break;
335         case PAM_ERROR_MSG:
336             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_ERROR);
337             break;
338         case PAM_TEXT_INFO:
339             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_INFO);
340             break;
341         }
342
343         g_free (text);
344     }
345 }
346
347 static void
348 handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
349 {
350     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
351     guint32 sequence_number, return_code;
352     gchar *username;
353
354     sequence_number = read_int (message, message_length, offset);
355
356     if (sequence_number != priv->authenticate_sequence_number)
357     {
358         g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
359         return;
360     }
361
362     username = read_string (message, message_length, offset);
363     return_code = read_int (message, message_length, offset);
364
365     g_debug ("Authentication complete for user %s with return code %d", username, return_code);
366
367     /* Update username */
368     if (strcmp (username, "") == 0)
369     {
370         g_free (username);
371         username = NULL;
372     }
373     g_free (priv->authentication_user);
374     priv->authentication_user = username;
375
376     priv->cancelling_authentication = FALSE;
377     priv->is_authenticated = (return_code == 0);
378
379     priv->in_authentication = FALSE;
380     g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
381 }
382
383 static guint8 *
384 read_message (LightDMGreeter *greeter, gsize *length, gboolean block)
385 {
386     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
387     gsize n_to_read, n_read;
388     guint8 *buffer;
389     GError *error = NULL;
390
391     /* Read the header, or the whole message if we already have that */
392     n_to_read = HEADER_SIZE;
393     if (priv->n_read >= HEADER_SIZE)
394         n_to_read += get_message_length (priv->read_buffer, priv->n_read);
395
396     do
397     {
398         GIOStatus status;
399         status = g_io_channel_read_chars (priv->from_server_channel,
400                                           (gchar *) priv->read_buffer + priv->n_read,
401                                           n_to_read - priv->n_read,
402                                           &n_read,
403                                           &error);
404         if (error)
405             g_warning ("Error reading from server: %s", error->message);
406         g_clear_error (&error);
407         if (status != G_IO_STATUS_NORMAL)
408             break;
409
410         g_debug ("Read %zi bytes from daemon", n_read);
411
412         priv->n_read += n_read;
413     } while (priv->n_read < n_to_read && block);
414
415     /* Stop if haven't got all the data we want */
416     if (priv->n_read != n_to_read)
417         return FALSE;
418
419     /* If have header, rerun for content */
420     if (priv->n_read == HEADER_SIZE)
421     {
422         n_to_read = get_message_length (priv->read_buffer, priv->n_read);
423         if (n_to_read > 0)
424         {
425             priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
426             return read_message (greeter, length, block);
427         }
428     }
429
430     buffer = priv->read_buffer;
431     *length = priv->n_read;
432
433     priv->read_buffer = g_malloc (priv->n_read);
434     priv->n_read = 0;
435
436     return buffer;
437 }
438
439 static gboolean
440 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
441 {
442     LightDMGreeter *greeter = data;
443     guint8 *message;
444     gsize message_length, offset;
445     guint32 id;
446
447     message = read_message (greeter, &message_length, FALSE);
448     if (!message)
449         return TRUE;
450
451     offset = 0;
452     id = read_int (message, message_length, &offset);
453     read_int (message, message_length, &offset);
454     switch (id)
455     {
456     case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
457         handle_prompt_authentication (greeter, message, message_length, &offset);
458         break;
459     case SERVER_MESSAGE_END_AUTHENTICATION:
460         handle_end_authentication (greeter, message, message_length, &offset);
461         break;
462     default:
463         g_warning ("Unknown message from server: %d", id);
464         break;
465     }
466     g_free (message);
467
468     return TRUE;
469 }
470
471 /**
472  * lightdm_greeter_connect_sync:
473  * @greeter: The greeter to connect
474  * @error: return location for a #GError, or %NULL
475  *
476  * Connects the greeter to the display manager.  Will block until connected.
477  *
478  * Return value: #TRUE if successfully connected
479  **/
480 gboolean
481 lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
482 {
483     LightDMGreeterPrivate *priv;
484     const gchar *fd;
485     guint8 message[MAX_MESSAGE_LENGTH];
486     guint8 *response;
487     gsize response_length, offset = 0;
488     guint32 id;
489
490     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
491
492     priv = GET_PRIVATE (greeter);
493
494     fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
495     if (!fd)
496     {
497         g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
498         return FALSE;
499     }
500     priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
501     g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
502
503     fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
504     if (!fd)
505     {
506         g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
507         return FALSE;
508     }
509     priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
510     g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
511     g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
512
513     g_debug ("Connecting to display manager...");
514     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
515     write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
516     write_message (greeter, message, offset);
517
518     response = read_message (greeter, &response_length, TRUE);
519     if (!response)
520         return FALSE;
521
522     offset = 0;
523     id = read_int (response, response_length, &offset);
524     read_int (response, response_length, &offset);
525     if (id == SERVER_MESSAGE_CONNECTED)
526         handle_connected (greeter, response, response_length, &offset);
527     g_free (response);
528     if (id != SERVER_MESSAGE_CONNECTED)
529     {
530         g_warning ("Expected CONNECTED message, got %d", id);
531         return FALSE;
532     }
533
534     priv->connected = TRUE;
535
536     return TRUE;
537 }
538
539 /**
540  * lightdm_greeter_get_hint:
541  * @greeter: A #LightDMGreeter
542  * @name: The hint name to query.
543  *
544  * Get a hint.
545  *
546  * Return value: The value for this hint or #NULL if not set.
547  **/
548 const gchar *
549 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
550 {
551     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
552     return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
553 }
554
555 /**
556  * lightdm_greeter_get_default_session_hint:
557  * @greeter: A #LightDMGreeter
558  *
559  * Get the default session to use.
560  *
561  * Return value: The session name
562  **/
563 const gchar *
564 lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
565 {
566     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
567     return lightdm_greeter_get_hint (greeter, "default-session");
568 }
569
570 /**
571  * lightdm_greeter_get_hide_users_hint:
572  * @greeter: A #LightDMGreeter
573  *
574  * Check if user accounts should be shown.  If this is TRUE then the list of
575  * accounts should be taken from #LightDMUserList and displayed in the greeter
576  * for the user to choose from.  Note that this list can be empty and it is
577  * recommended you show a method for the user to enter a username manually.
578  * 
579  * If this option is shown the greeter should only allow these users to be
580  * chosen for login unless the manual login hint is set.
581  *
582  * Return value: #TRUE if the available users should not be shown.
583  */
584 gboolean
585 lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
586 {
587     const gchar *value;
588
589     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
590     value = lightdm_greeter_get_hint (greeter, "hide-users");
591
592     return g_strcmp0 (value, "true") == 0;
593 }
594
595 /**
596  * lightdm_greeter_get_show_manual_login_hint:
597  * @greeter: A #LightDMGreeter
598  *
599  * Check if a manual login option should be shown.  If set the GUI
600  * should provide a way for a username to be entered manually.
601  * Without this hint a greeter which is showing a user list can
602  * limit logins to only those users.
603  *
604  * Return value: #TRUE if a manual login option should be shown.
605  */
606 gboolean
607 lightdm_greeter_get_show_manual_login_hint (LightDMGreeter *greeter)
608 {
609     const gchar *value;
610
611     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
612     value = lightdm_greeter_get_hint (greeter, "show-manual-login");
613
614     return g_strcmp0 (value, "true") == 0;
615 }
616
617 /**
618  * lightdm_greeter_get_show_remote_login_hint:
619  * @greeter: A #LightDMGreeter
620  *
621  * Check if a remote login option should be shown.  If set the GUI
622  * should provide a way for a user to log into a remote desktop server.
623  *
624  * Return value: #TRUE if a remote login option should be shown.
625  */
626 gboolean
627 lightdm_greeter_get_show_remote_login_hint (LightDMGreeter *greeter)
628 {
629     const gchar *value;
630
631     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
632     value = lightdm_greeter_get_hint (greeter, "show-remote-login");
633
634     return g_strcmp0 (value, "true") == 0;
635 }
636
637 /**
638  * lightdm_greeter_get_lock_hint:
639  * @greeter: A #LightDMGreeter
640  *
641  * Check if the greeter is acting as a lock screen.
642  *
643  * Return value: #TRUE if the greeter was triggered by locking the seat.
644  */
645 gboolean
646 lightdm_greeter_get_lock_hint (LightDMGreeter *greeter)
647 {
648     const gchar *value;
649
650     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
651     value = lightdm_greeter_get_hint (greeter, "lock-screen");
652
653     return g_strcmp0 (value, "true") == 0;
654 }
655
656 /**
657  * lightdm_greeter_get_has_guest_account_hint:
658  * @greeter: A #LightDMGreeter
659  *
660  * Check if guest sessions are supported.
661  *
662  * Return value: #TRUE if guest sessions are supported.
663  */
664 gboolean
665 lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
666 {
667     const gchar *value;
668
669     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
670     value = lightdm_greeter_get_hint (greeter, "has-guest-account");
671   
672     return g_strcmp0 (value, "true") == 0;
673 }
674
675 /**
676  * lightdm_greeter_get_select_user_hint:
677  * @greeter: A #LightDMGreeter
678  *
679  * Get the user to select by default.
680  *
681  * Return value: A username
682  */
683 const gchar *
684 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
685 {
686     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
687     return lightdm_greeter_get_hint (greeter, "select-user");
688 }
689
690 /**
691  * lightdm_greeter_get_select_guest_hint:
692  * @greeter: A #LightDMGreeter
693  *
694  * Check if the guest account should be selected by default.
695  *
696  * Return value: #TRUE if the guest account should be selected by default.
697  */
698 gboolean
699 lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
700 {
701     const gchar *value;
702
703     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
704     value = lightdm_greeter_get_hint (greeter, "select-guest");
705   
706     return g_strcmp0 (value, "true") == 0;
707 }
708
709 /**
710  * lightdm_greeter_get_autologin_user_hint:
711  * @greeter: A #LightDMGreeter
712  *
713  * Get the user account to automatically logg into when the timer expires.
714  *
715  * Return value: The user account to automatically log into.
716  */
717 const gchar *
718 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
719 {
720     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
721     return lightdm_greeter_get_hint (greeter, "autologin-user");
722 }
723
724 /**
725  * lightdm_greeter_get_autologin_guest_hint:
726  * @greeter: A #LightDMGreeter
727  *
728  * Check if the guest account should be automatically logged into when the timer expires.
729  *
730  * Return value: #TRUE if the guest account should be automatically logged into.
731  */
732 gboolean
733 lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
734 {
735     const gchar *value;
736
737     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
738     value = lightdm_greeter_get_hint (greeter, "autologin-guest");
739   
740     return g_strcmp0 (value, "true") == 0;
741 }
742
743 /**
744  * lightdm_greeter_get_autologin_timeout_hint:
745  * @greeter: A #LightDMGreeter
746  *
747  * Get the number of seconds to wait before automaitcally logging in.
748  *
749  * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
750  */
751 gint
752 lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
753 {
754     const gchar *value;
755     gint timeout = 0;
756
757     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
758     value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
759     if (value)
760         timeout = atoi (value);
761     if (timeout < 0)
762         timeout = 0;
763
764     return timeout;
765 }
766
767 /**
768  * lightdm_greeter_cancel_autologin:
769  * @greeter: A #LightDMGreeter
770  *
771  * Cancel the automatic login.
772  */
773 void
774 lightdm_greeter_cancel_autologin (LightDMGreeter *greeter)
775 {
776     LightDMGreeterPrivate *priv;
777
778     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
779
780     priv = GET_PRIVATE (greeter);
781
782     if (priv->autologin_timeout)
783        g_source_remove (priv->autologin_timeout);
784     priv->autologin_timeout = 0;
785 }
786
787 /**
788  * lightdm_greeter_authenticate:
789  * @greeter: A #LightDMGreeter
790  * @username: (allow-none): A username or #NULL to prompt for a username.
791  *
792  * Starts the authentication procedure for a user.
793  **/
794 void
795 lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username)
796 {
797     LightDMGreeterPrivate *priv;
798     guint8 message[MAX_MESSAGE_LENGTH];
799     gsize offset = 0;
800
801     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
802
803     priv = GET_PRIVATE (greeter);
804
805     g_return_if_fail (priv->connected);
806
807     priv->cancelling_authentication = FALSE;
808     priv->authenticate_sequence_number++;
809     priv->in_authentication = TRUE;  
810     priv->is_authenticated = FALSE;
811     if (username != priv->authentication_user)
812     {
813         g_free (priv->authentication_user);
814         priv->authentication_user = g_strdup (username);
815     }
816
817     g_debug ("Starting authentication for user %s...", username);
818     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset);
819     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
820     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
821     write_message (greeter, message, offset);
822 }
823
824 /**
825  * lightdm_greeter_authenticate_as_guest:
826  * @greeter: A #LightDMGreeter
827  *
828  * Starts the authentication procedure for the guest user.
829  **/
830 void
831 lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter)
832 {
833     LightDMGreeterPrivate *priv;
834     guint8 message[MAX_MESSAGE_LENGTH];
835     gsize offset = 0;
836
837     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
838
839     priv = GET_PRIVATE (greeter);
840
841     g_return_if_fail (priv->connected);
842
843     priv->cancelling_authentication = FALSE;
844     priv->authenticate_sequence_number++;
845     priv->in_authentication = TRUE;
846     priv->is_authenticated = FALSE;
847     g_free (priv->authentication_user);
848     priv->authentication_user = NULL;
849
850     g_debug ("Starting authentication for guest account...");
851     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset);
852     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
853     write_message (greeter, message, offset);
854 }
855
856 /**
857  * lightdm_greeter_authenticate_autologin:
858  * @greeter: A #LightDMGreeter
859  *
860  * Starts the authentication procedure for the automatic login user.
861  **/
862 void
863 lightdm_greeter_authenticate_autologin (LightDMGreeter *greeter)
864 {
865     const gchar *user;
866
867     user = lightdm_greeter_get_autologin_user_hint (greeter);
868     if (lightdm_greeter_get_autologin_guest_hint (greeter))
869         lightdm_greeter_authenticate_as_guest (greeter);
870     else if (user)
871         lightdm_greeter_authenticate (greeter, user);
872 }
873
874 /**
875  * lightdm_greeter_authenticate_remote:
876  * @greeter: A #LightDMGreeter
877  * @session: The name of a remote session
878  * @username: (allow-none): A username of #NULL to prompt for a username.
879  *
880  * Start authentication for a remote session type.
881  **/
882 void
883 lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *session, const gchar *username)
884 {
885     LightDMGreeterPrivate *priv;
886     guint8 message[MAX_MESSAGE_LENGTH];
887     gsize offset = 0;
888
889     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
890
891     priv = GET_PRIVATE (greeter);
892
893     g_return_if_fail (priv->connected);
894
895     priv->cancelling_authentication = FALSE;
896     priv->authenticate_sequence_number++;
897     priv->in_authentication = TRUE;
898     priv->is_authenticated = FALSE;
899     g_free (priv->authentication_user);
900     priv->authentication_user = NULL;
901
902     if (username)
903         g_debug ("Starting authentication for remote session %s as user %s...", session, username);
904     else
905         g_debug ("Starting authentication for remote session %s...", session);
906     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_REMOTE, int_length () + string_length (session) + string_length (username), &offset);
907     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
908     write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
909     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
910     write_message (greeter, message, offset);
911 }
912
913 /**
914  * lightdm_greeter_respond:
915  * @greeter: A #LightDMGreeter
916  * @response: Response to a prompt
917  *
918  * Provide response to a prompt.  May be one in a series.
919  **/
920 void
921 lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response)
922 {
923     LightDMGreeterPrivate *priv;
924     guint8 message[MAX_MESSAGE_LENGTH];
925     gsize offset = 0;
926
927     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
928     g_return_if_fail (response != NULL);
929
930     priv = GET_PRIVATE (greeter);
931
932     g_return_if_fail (priv->connected);
933     g_return_if_fail (priv->n_responses_waiting > 0);
934
935     priv->n_responses_waiting--;
936     priv->responses_received = g_list_append (priv->responses_received, g_strdup (response));
937
938     if (priv->n_responses_waiting == 0)
939     {
940       guint32 msg_length;
941       GList *iter;
942
943       g_debug ("Providing response to display manager");
944
945       msg_length = int_length ();
946       for (iter = priv->responses_received; iter; iter = iter->next)
947       {
948           msg_length += string_length ((gchar *)iter->data);
949       }
950
951       write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, msg_length, &offset);
952       write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset);
953       for (iter = priv->responses_received; iter; iter = iter->next)
954       {
955           write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset);
956       }
957       write_message (greeter, message, offset);
958
959       g_list_free_full (priv->responses_received, g_free);
960       priv->responses_received = NULL;
961     }
962 }
963
964 /**
965  * lightdm_greeter_cancel_authentication:
966  * @greeter: A #LightDMGreeter
967  *
968  * Cancel the current user authentication.
969  **/
970 void
971 lightdm_greeter_cancel_authentication (LightDMGreeter *greeter)
972 {
973     LightDMGreeterPrivate *priv;
974     guint8 message[MAX_MESSAGE_LENGTH];
975     gsize offset = 0;
976
977     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
978
979     priv = GET_PRIVATE (greeter);
980
981     g_return_if_fail (priv->connected);
982
983     priv->cancelling_authentication = TRUE;
984     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
985     write_message (greeter, message, offset);
986 }
987
988 /**
989  * lightdm_greeter_get_in_authentication:
990  * @greeter: A #LightDMGreeter
991  *
992  * Checks if the greeter is in the process of authenticating.
993  *
994  * Return value: #TRUE if the greeter is authenticating a user.
995  **/
996 gboolean
997 lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
998 {
999     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1000     return GET_PRIVATE (greeter)->in_authentication;
1001 }
1002
1003 /**
1004  * lightdm_greeter_get_is_authenticated:
1005  * @greeter: A #LightDMGreeter
1006  *
1007  * Checks if the greeter has successfully authenticated.
1008  *
1009  * Return value: #TRUE if the greeter is authenticated for login.
1010  **/
1011 gboolean
1012 lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
1013 {
1014     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1015     return GET_PRIVATE (greeter)->is_authenticated;
1016 }
1017
1018 /**
1019  * lightdm_greeter_get_authentication_user:
1020  * @greeter: A #LightDMGreeter
1021  *
1022  * Get the user that is being authenticated.
1023  *
1024  * Return value: The username of the authentication user being authenticated or #NULL if no authentication in progress.
1025  */
1026 const gchar *
1027 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
1028 {
1029     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1030     return GET_PRIVATE (greeter)->authentication_user;
1031 }
1032
1033 /**
1034  * lightdm_greeter_set_language:
1035  * @greeter: A #LightDMGreeter
1036  * @language: The language to use for this user in the form of a locale specification (e.g. "de_DE.UTF-8").
1037  *
1038  * Set the language for the currently authenticated user.
1039  **/
1040 void
1041 lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language)
1042 {
1043     LightDMGreeterPrivate *priv;
1044     guint8 message[MAX_MESSAGE_LENGTH];
1045     gsize offset = 0;
1046
1047     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1048
1049     priv = GET_PRIVATE (greeter);
1050
1051     g_return_if_fail (priv->connected);
1052
1053     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset);
1054     write_string (message, MAX_MESSAGE_LENGTH, language, &offset);
1055     write_message (greeter, message, offset);
1056 }
1057
1058 /**
1059  * lightdm_greeter_start_session_sync:
1060  * @greeter: A #LightDMGreeter
1061  * @session: (allow-none): The session to log into or #NULL to use the default.
1062  * @error: return location for a #GError, or %NULL
1063  *
1064  * Start a session for the authenticated user.
1065  *
1066  * Return value: TRUE if the session was started.
1067  **/
1068 gboolean
1069 lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
1070 {
1071     LightDMGreeterPrivate *priv;
1072     guint8 message[MAX_MESSAGE_LENGTH];
1073     guint8 *response;
1074     gsize response_length, offset = 0;
1075     guint32 id, return_code = 1;
1076
1077     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1078
1079     priv = GET_PRIVATE (greeter);
1080
1081     g_return_val_if_fail (priv->connected, FALSE);
1082     g_return_val_if_fail (priv->is_authenticated, FALSE);
1083
1084     if (session)
1085         g_debug ("Starting session %s", session);
1086     else
1087         g_debug ("Starting default session");
1088
1089     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
1090     write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
1091     write_message (greeter, message, offset);
1092
1093     response = read_message (greeter, &response_length, TRUE);
1094     if (!response)
1095         return FALSE;
1096
1097     offset = 0;
1098     id = read_int (response, response_length, &offset);
1099     read_int (response, response_length, &offset);
1100     if (id == SERVER_MESSAGE_SESSION_RESULT)
1101         return_code = read_int (response, response_length, &offset);
1102     else
1103         g_warning ("Expected SESSION_RESULT message, got %d", id);
1104
1105     g_free (response);
1106
1107     return return_code == 0;
1108 }
1109
1110 /**
1111  * lightdm_greeter_ensure_shared_data_dir:
1112  * @greeter: A #LightDMGreeter
1113  * @username: A username
1114  *
1115  * Ensure that a shared data dir for the given user is available.  This will
1116  * be created at /var/lib/lightdm-data/@username.  Both the greeter user and
1117  * @username will have write access to that folder.  The intention is that
1118  * larger pieces of shared data would be stored there (files that the greeter
1119  * creates but wants to give to a user -- like camera photos -- or files that
1120  * the user creates but wants the greeter to see -- like contact avatars).
1121  *
1122  * LightDM will automatically create these if the user actually logs in, so
1123  * greeters only need to call this method if they want to store something in
1124  * the directory themselves.
1125  **/
1126 void
1127 lightdm_greeter_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username)
1128 {
1129     LightDMGreeterPrivate *priv;
1130     guint8 message[MAX_MESSAGE_LENGTH];
1131     gsize offset = 0;
1132
1133     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1134
1135     priv = GET_PRIVATE (greeter);
1136
1137     g_return_if_fail (priv->connected);
1138
1139     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_ENSURE_SHARED_DIR, string_length (username), &offset);
1140     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
1141     write_message (greeter, message, offset);
1142 }
1143
1144 static void
1145 lightdm_greeter_init (LightDMGreeter *greeter)
1146 {
1147     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1148
1149     priv->read_buffer = g_malloc (HEADER_SIZE);
1150     priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1151 }
1152
1153 static void
1154 lightdm_greeter_set_property (GObject      *object,
1155                           guint         prop_id,
1156                           const GValue *value,
1157                           GParamSpec   *pspec)
1158 {
1159     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1160 }
1161
1162 static void
1163 lightdm_greeter_get_property (GObject    *object,
1164                           guint       prop_id,
1165                           GValue     *value,
1166                           GParamSpec *pspec)
1167 {
1168     LightDMGreeter *self;
1169
1170     self = LIGHTDM_GREETER (object);
1171
1172     switch (prop_id) {
1173     case PROP_DEFAULT_SESSION_HINT:
1174         g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
1175         break;
1176     case PROP_HIDE_USERS_HINT:
1177         g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
1178         break;
1179     case PROP_SHOW_MANUAL_LOGIN_HINT:
1180         g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
1181         break;
1182     case PROP_SHOW_REMOTE_LOGIN_HINT:
1183         g_value_set_boolean (value, lightdm_greeter_get_show_remote_login_hint (self));
1184         break;
1185     case PROP_LOCK_HINT:
1186         g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
1187         break;
1188     case PROP_HAS_GUEST_ACCOUNT_HINT:
1189         g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
1190         break;
1191     case PROP_SELECT_USER_HINT:
1192         g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
1193         break;
1194     case PROP_SELECT_GUEST_HINT:
1195         g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
1196         break;
1197     case PROP_AUTOLOGIN_USER_HINT:
1198         g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
1199         break;
1200     case PROP_AUTOLOGIN_GUEST_HINT:
1201         g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
1202         break;
1203     case PROP_AUTOLOGIN_TIMEOUT_HINT:
1204         g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
1205         break;
1206     case PROP_AUTHENTICATION_USER:
1207         g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
1208         break;
1209     case PROP_IN_AUTHENTICATION:
1210         g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
1211         break;
1212     case PROP_IS_AUTHENTICATED:
1213         g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
1214         break;
1215     default:
1216         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1217         break;
1218     }
1219 }
1220
1221 static void
1222 lightdm_greeter_finalize (GObject *object)
1223 {
1224     LightDMGreeter *self = LIGHTDM_GREETER (object);
1225     LightDMGreeterPrivate *priv = GET_PRIVATE (self);
1226
1227     if (priv->to_server_channel)
1228         g_io_channel_unref (priv->to_server_channel);
1229     if (priv->from_server_channel)
1230         g_io_channel_unref (priv->from_server_channel);
1231     g_free (priv->authentication_user);
1232     g_hash_table_unref (priv->hints);
1233
1234     G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
1235 }
1236
1237 static void
1238 lightdm_greeter_class_init (LightDMGreeterClass *klass)
1239 {
1240     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1241
1242     g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
1243
1244     object_class->set_property = lightdm_greeter_set_property;
1245     object_class->get_property = lightdm_greeter_get_property;
1246     object_class->finalize = lightdm_greeter_finalize;
1247
1248     g_object_class_install_property (object_class,
1249                                      PROP_DEFAULT_SESSION_HINT,
1250                                      g_param_spec_string ("default-session-hint",
1251                                                           "default-session-hint",
1252                                                           "Default session hint",
1253                                                           NULL,
1254                                                           G_PARAM_READWRITE));
1255
1256     g_object_class_install_property (object_class,
1257                                      PROP_HIDE_USERS_HINT,
1258                                      g_param_spec_boolean ("hide-users-hint",
1259                                                            "hide-users-hint",
1260                                                            "Hide users hint",
1261                                                            FALSE,
1262                                                            G_PARAM_READABLE));
1263
1264     g_object_class_install_property (object_class,
1265                                      PROP_SHOW_MANUAL_LOGIN_HINT,
1266                                      g_param_spec_boolean ("show-manual-login-hint",
1267                                                            "show-manual-login-hint",
1268                                                            "Show manual login hint",
1269                                                            FALSE,
1270                                                            G_PARAM_READABLE));
1271
1272     g_object_class_install_property (object_class,
1273                                      PROP_SHOW_REMOTE_LOGIN_HINT,
1274                                      g_param_spec_boolean ("show-remote-login-hint",
1275                                                            "show-remote-login-hint",
1276                                                            "Show remote login hint",
1277                                                            FALSE,
1278                                                            G_PARAM_READABLE));
1279
1280     g_object_class_install_property (object_class,
1281                                      PROP_LOCK_HINT,
1282                                      g_param_spec_boolean ("lock-hint",
1283                                                            "lock-hint",
1284                                                            "Lock hint",
1285                                                            FALSE,
1286                                                            G_PARAM_READABLE));
1287
1288     g_object_class_install_property (object_class,
1289                                      PROP_HAS_GUEST_ACCOUNT_HINT,
1290                                      g_param_spec_boolean ("has-guest-account-hint",
1291                                                            "has-guest-account-hint",
1292                                                            "Has guest account hint",
1293                                                            FALSE,
1294                                                            G_PARAM_READABLE));
1295
1296     g_object_class_install_property (object_class,
1297                                      PROP_SELECT_USER_HINT,
1298                                      g_param_spec_string ("select-user-hint",
1299                                                           "select-user-hint",
1300                                                           "Select user hint",
1301                                                           NULL,
1302                                                           G_PARAM_READABLE));
1303
1304     g_object_class_install_property (object_class,
1305                                      PROP_SELECT_GUEST_HINT,
1306                                      g_param_spec_boolean ("select-guest-hint",
1307                                                            "select-guest-hint",
1308                                                            "Select guest account hint",
1309                                                            FALSE,
1310                                                            G_PARAM_READABLE));
1311
1312     g_object_class_install_property (object_class,
1313                                      PROP_AUTOLOGIN_USER_HINT,
1314                                      g_param_spec_string ("autologin-user-hint",
1315                                                           "autologin-user-hint",
1316                                                           "Autologin user hint",
1317                                                           NULL,
1318                                                           G_PARAM_READABLE));
1319
1320     g_object_class_install_property (object_class,
1321                                      PROP_AUTOLOGIN_GUEST_HINT,
1322                                      g_param_spec_boolean ("autologin-guest-hint",
1323                                                            "autologin-guest-hint",
1324                                                            "Autologin guest account hint",
1325                                                            FALSE,
1326                                                            G_PARAM_READABLE));
1327
1328     g_object_class_install_property (object_class,
1329                                      PROP_AUTOLOGIN_TIMEOUT_HINT,
1330                                      g_param_spec_int ("autologin-timeout-hint",
1331                                                        "autologin-timeout-hint",
1332                                                        "Autologin timeout hint",
1333                                                        0, G_MAXINT, 0,
1334                                                        G_PARAM_READABLE));
1335
1336     g_object_class_install_property (object_class,
1337                                      PROP_AUTHENTICATION_USER,
1338                                      g_param_spec_string ("authentication-user",
1339                                                           "authentication-user",
1340                                                           "The user being authenticated",
1341                                                           NULL,
1342                                                           G_PARAM_READABLE));
1343     g_object_class_install_property (object_class,
1344                                      PROP_IN_AUTHENTICATION,
1345                                      g_param_spec_boolean ("in-authentication",
1346                                                            "in-authentication",
1347                                                            "TRUE if a user is being authenticated",
1348                                                            FALSE,
1349                                                            G_PARAM_READABLE));
1350     g_object_class_install_property (object_class,
1351                                      PROP_IS_AUTHENTICATED,
1352                                      g_param_spec_boolean ("is-authenticated",
1353                                                            "is-authenticated",
1354                                                            "TRUE if the selected user is authenticated",
1355                                                            FALSE,
1356                                                            G_PARAM_READABLE));
1357
1358     /**
1359      * LightDMGreeter::show-prompt:
1360      * @greeter: A #LightDMGreeter
1361      * @text: Prompt text
1362      * @type: Prompt type
1363      *
1364      * The ::show-prompt signal gets emitted when the greeter should show a
1365      * prompt to the user.  The given text should be displayed and an input
1366      * field for the user to provide a response.
1367      *
1368      * Call lightdm_greeter_respond() with the resultant input or
1369      * lightdm_greeter_cancel_authentication() to abort the authentication.
1370      **/
1371     signals[SHOW_PROMPT] =
1372         g_signal_new ("show-prompt",
1373                       G_TYPE_FROM_CLASS (klass),
1374                       G_SIGNAL_RUN_LAST,
1375                       G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
1376                       NULL, NULL,
1377                       NULL,
1378                       G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1379
1380     /**
1381      * LightDMGreeter::show-message:
1382      * @greeter: A #LightDMGreeter
1383      * @text: Message text
1384      * @type: Message type
1385      *
1386      * The ::show-message signal gets emitted when the greeter
1387      * should show a message to the user.
1388      **/
1389     signals[SHOW_MESSAGE] =
1390         g_signal_new ("show-message",
1391                       G_TYPE_FROM_CLASS (klass),
1392                       G_SIGNAL_RUN_LAST,
1393                       G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
1394                       NULL, NULL,
1395                       NULL,
1396                       G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1397
1398     /**
1399      * LightDMGreeter::authentication-complete:
1400      * @greeter: A #LightDMGreeter
1401      *
1402      * The ::authentication-complete signal gets emitted when the greeter
1403      * has completed authentication.
1404      *
1405      * Call lightdm_greeter_get_is_authenticated() to check if the authentication
1406      * was successful.
1407      **/
1408     signals[AUTHENTICATION_COMPLETE] =
1409         g_signal_new ("authentication-complete",
1410                       G_TYPE_FROM_CLASS (klass),
1411                       G_SIGNAL_RUN_LAST,
1412                       G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
1413                       NULL, NULL,
1414                       NULL,
1415                       G_TYPE_NONE, 0);
1416
1417     /**
1418      * LightDMGreeter::autologin-timer-expired:
1419      * @greeter: A #LightDMGreeter
1420      *
1421      * The ::timed-login signal gets emitted when the automatic login timer has expired.
1422      * The application should then call lightdm_greeter_login().
1423      **/
1424     signals[AUTOLOGIN_TIMER_EXPIRED] =
1425         g_signal_new ("autologin-timer-expired",
1426                       G_TYPE_FROM_CLASS (klass),
1427                       G_SIGNAL_RUN_LAST,
1428                       G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),
1429                       NULL, NULL,
1430                       NULL,
1431                       G_TYPE_NONE, 0);
1432 }