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