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