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