]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - liblightdm-gobject/greeter.c
62cb30d623fb67e651967912e730a37d245df902
[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 <gio/gio.h>
16 #include <gio/gunixsocketaddress.h>
17 #include <security/pam_appl.h>
18
19 #include "lightdm/greeter.h"
20
21 G_DEFINE_QUARK (lightdm_greeter_error, lightdm_greeter_error)
22
23 enum {
24     PROP_0,
25     PROP_DEFAULT_SESSION_HINT,
26     PROP_HIDE_USERS_HINT,
27     PROP_SHOW_MANUAL_LOGIN_HINT,
28     PROP_SHOW_REMOTE_LOGIN_HINT,
29     PROP_LOCK_HINT,
30     PROP_HAS_GUEST_ACCOUNT_HINT,
31     PROP_SELECT_USER_HINT,
32     PROP_SELECT_GUEST_HINT,
33     PROP_AUTOLOGIN_USER_HINT,
34     PROP_AUTOLOGIN_GUEST_HINT,
35     PROP_AUTOLOGIN_TIMEOUT_HINT,
36     PROP_AUTHENTICATION_USER,
37     PROP_IN_AUTHENTICATION,
38     PROP_IS_AUTHENTICATED,
39 };
40
41 enum {
42     SHOW_PROMPT,
43     SHOW_MESSAGE,
44     AUTHENTICATION_COMPLETE,
45     AUTOLOGIN_TIMER_EXPIRED,
46     IDLE,
47     RESET,
48     LAST_SIGNAL
49 };
50 static guint signals[LAST_SIGNAL] = { 0 };
51
52 typedef struct
53 {
54     /* TRUE if the daemon can reuse this greeter */
55     gboolean resettable;
56
57     /* Socket connection to daemon */
58     GSocket *socket;
59
60     /* Channel to write to daemon */
61     GIOChannel *to_server_channel;
62
63     /* Channel to read from daemon */
64     GIOChannel *from_server_channel;
65
66     /* Data read from the daemon */
67     guint8 *read_buffer;
68     gsize n_read;
69
70     gsize n_responses_waiting;
71     GList *responses_received;
72
73     /* TRUE if have got a connect response */
74     gboolean connected;
75
76     /* Pending connect requests */
77     GList *connect_requests;
78
79     /* Pending start session requests */
80     GList *start_session_requests;
81
82     /* Pending ensure shared data dir requests */
83     GList *ensure_shared_data_dir_requests;
84
85     /* Hints provided by the daemon */
86     GHashTable *hints;
87
88     /* Timeout source to notify greeter to autologin */
89     guint autologin_timeout;
90
91     gchar *authentication_user;
92     gboolean in_authentication;
93     gboolean is_authenticated;
94     guint32 authenticate_sequence_number;
95     gboolean cancelling_authentication;
96 } LightDMGreeterPrivate;
97
98 G_DEFINE_TYPE (LightDMGreeter, lightdm_greeter, G_TYPE_OBJECT);
99
100 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_GREETER, LightDMGreeterPrivate)
101
102 #define HEADER_SIZE 8
103 #define MAX_MESSAGE_LENGTH 1024
104
105 /* Messages from the greeter to the server */
106 typedef enum
107 {
108     GREETER_MESSAGE_CONNECT = 0,
109     GREETER_MESSAGE_AUTHENTICATE,
110     GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
111     GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
112     GREETER_MESSAGE_START_SESSION,
113     GREETER_MESSAGE_CANCEL_AUTHENTICATION,
114     GREETER_MESSAGE_SET_LANGUAGE,
115     GREETER_MESSAGE_AUTHENTICATE_REMOTE,
116     GREETER_MESSAGE_ENSURE_SHARED_DIR,
117 } GreeterMessage;
118
119 /* Messages from the server to the greeter */
120 typedef enum
121 {
122     SERVER_MESSAGE_CONNECTED = 0,
123     SERVER_MESSAGE_PROMPT_AUTHENTICATION,
124     SERVER_MESSAGE_END_AUTHENTICATION,
125     SERVER_MESSAGE_SESSION_RESULT,
126     SERVER_MESSAGE_SHARED_DIR_RESULT,
127     SERVER_MESSAGE_IDLE,
128     SERVER_MESSAGE_RESET,
129 } ServerMessage;
130
131 /* Request sent to server */
132 typedef struct
133 {
134     GObject parent_instance;
135     LightDMGreeter *greeter;
136     GCancellable *cancellable;
137     GAsyncReadyCallback callback;
138     gpointer user_data;
139     gboolean complete;
140     gboolean result;
141     GError *error;
142     gchar *dir;
143 } Request;
144 typedef struct
145 {
146     GObjectClass parent_class;
147 } RequestClass;
148 GType request_get_type (void);
149 static void request_iface_init (GAsyncResultIface *iface);
150 #define REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), request_get_type (), Request))
151 G_DEFINE_TYPE_WITH_CODE (Request, request, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, request_iface_init));
152
153 static gboolean from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data);
154
155 GType
156 lightdm_greeter_error_get_type (void)
157 {
158     static GType enum_type = 0;
159
160     if (G_UNLIKELY(enum_type == 0)) {
161         static const GEnumValue values[] = {
162             { LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR, "LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR", "communication-error" },
163             { LIGHTDM_GREETER_ERROR_CONNECTION_FAILED, "LIGHTDM_GREETER_ERROR_CONNECTION_FAILED", "connection-failed" },
164             { LIGHTDM_GREETER_ERROR_SESSION_FAILED, "LIGHTDM_GREETER_ERROR_SESSION_FAILED", "session-failed" },
165             { LIGHTDM_GREETER_ERROR_NO_AUTOLOGIN, "LIGHTDM_GREETER_ERROR_NO_AUTOLOGIN", "no-autologin" },
166             { LIGHTDM_GREETER_ERROR_INVALID_USER, "LIGHTDM_GREETER_ERROR_INVALID_USER", "invalid-user" },          
167             { 0, NULL, NULL }
168         };
169         enum_type = g_enum_register_static (g_intern_static_string ("LightDMGreeterError"), values);
170     }
171
172     return enum_type;
173 }
174
175 GType
176 lightdm_prompt_type_get_type (void)
177 {
178     static GType enum_type = 0;
179   
180     if (G_UNLIKELY(enum_type == 0)) {
181         static const GEnumValue values[] = {
182             { LIGHTDM_PROMPT_TYPE_QUESTION, "LIGHTDM_PROMPT_TYPE_QUESTION", "question" },
183             { LIGHTDM_PROMPT_TYPE_SECRET, "LIGHTDM_PROMPT_TYPE_SECRET", "secret" },
184             { 0, NULL, NULL }
185         };
186         enum_type = g_enum_register_static (g_intern_static_string ("LightDMPromptType"), values);
187     }
188
189     return enum_type;
190 }
191
192 GType
193 lightdm_message_type_get_type (void)
194 {
195     static GType enum_type = 0;
196   
197     if (G_UNLIKELY(enum_type == 0)) {
198         static const GEnumValue values[] = {
199             { LIGHTDM_MESSAGE_TYPE_INFO, "LIGHTDM_MESSAGE_TYPE_INFO", "info" },
200             { LIGHTDM_MESSAGE_TYPE_ERROR, "LIGHTDM_MESSAGE_TYPE_ERROR", "error" },
201             { 0, NULL, NULL }
202         };
203         enum_type = g_enum_register_static (g_intern_static_string ("LightDMMessageType"), values);
204     }
205
206     return enum_type;
207 }
208
209
210 /**
211  * lightdm_greeter_new:
212  *
213  * Create a new greeter.
214  *
215  * Return value: the new #LightDMGreeter
216  **/
217 LightDMGreeter *
218 lightdm_greeter_new (void)
219 {
220     return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
221 }
222
223 /**
224  * lightdm_greeter_set_resettable:
225  * @greeter: A #LightDMGreeter
226  * @resettable: Whether the greeter wants to be reset instead of killed after the user logs in
227  *
228  * Set whether the greeter will be reset instead of killed after the user logs in.
229  * This must be called before lightdm_greeter_connect is called.
230  **/
231 void
232 lightdm_greeter_set_resettable (LightDMGreeter *greeter, gboolean resettable)
233 {
234     LightDMGreeterPrivate *priv;
235
236     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
237
238     priv = GET_PRIVATE (greeter);
239
240     g_return_if_fail (!priv->connected);
241     priv->resettable = resettable;
242 }
243
244 static Request *
245 request_new (LightDMGreeter *greeter, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
246 {
247     Request *request;
248
249     request = g_object_new (request_get_type (), NULL);
250     request->greeter = g_object_ref (greeter);
251     if (cancellable)
252         request->cancellable = g_object_ref (cancellable);
253     request->callback = callback;
254     request->user_data = user_data;
255
256     return request;
257 }
258
259 static gboolean
260 request_callback_cb (gpointer data)
261 {
262     Request *request = data;
263     if (request->callback)
264         request->callback (G_OBJECT (request->greeter), G_ASYNC_RESULT (request), request->user_data);
265     g_object_unref (request);
266     return G_SOURCE_REMOVE;
267 }
268
269 static void
270 request_complete (Request *request)
271 {
272     request->complete = TRUE;
273
274     if (!request->callback)
275         return;
276
277     if (request->cancellable && g_cancellable_is_cancelled (request->cancellable))
278         return;
279
280     g_idle_add (request_callback_cb, g_object_ref (request));
281 }
282
283 static gboolean
284 timed_login_cb (gpointer data)
285 {
286     LightDMGreeter *greeter = data;
287     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
288
289     priv->autologin_timeout = 0;
290     g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
291
292     return FALSE;
293 }
294
295 static guint32
296 int_length (void)
297 {
298     return 4;
299 }
300
301 static gboolean
302 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset, GError **error)
303 {
304     if (*offset + 4 >= buffer_length)
305     {
306         g_set_error_literal (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
307                              "Not enough buffer space to write integer");
308         return FALSE;
309     }
310     buffer[*offset] = value >> 24;
311     buffer[*offset+1] = (value >> 16) & 0xFF;
312     buffer[*offset+2] = (value >> 8) & 0xFF;
313     buffer[*offset+3] = value & 0xFF;
314     *offset += 4;
315
316     return TRUE;
317 }
318
319 static gboolean
320 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset, GError **error)
321 {
322     gint length = 0;
323
324     if (value)
325         length = strlen (value);
326     if (!write_int (buffer, buffer_length, length, offset, error))
327         return FALSE;
328     if (*offset + length >= buffer_length)
329     {
330         g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
331                      "Not enough buffer space to write string of length %d octets", length);
332         return FALSE;
333     }
334     if (value)
335         memcpy (buffer + *offset, value, length);
336     *offset += length;
337
338     return TRUE;
339 }
340
341 static guint32
342 read_int (guint8 *message, gsize message_length, gsize *offset)
343 {
344     guint32 value;
345     guint8 *buffer;
346
347     if (message_length - *offset < int_length ())
348     {
349         g_warning ("Not enough space for int, need %i, got %zi", int_length (), message_length - *offset);
350         return 0;
351     }
352
353     buffer = message + *offset;
354     value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
355     *offset += int_length ();
356
357     return value;
358 }
359
360 static gchar *
361 read_string (guint8 *message, gsize message_length, gsize *offset)
362 {
363     guint32 length;
364     gchar *value;
365
366     length = read_int (message, message_length, offset);
367     if (message_length - *offset < length)
368     {
369         g_warning ("Not enough space for string, need %u, got %zu", length, message_length - *offset);
370         return g_strdup ("");
371     }
372
373     value = g_malloc (sizeof (gchar) * (length + 1));
374     memcpy (value, message + *offset, length);
375     value[length] = '\0';
376     *offset += length;
377
378     return value;
379 }
380
381 static guint32
382 string_length (const gchar *value)
383 {
384     if (value)
385         return int_length () + strlen (value);
386     else
387         return int_length ();
388 }
389
390 static gboolean
391 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset, GError **error)
392 {
393     return write_int (buffer, buffer_length, id, offset, error) &&
394            write_int (buffer, buffer_length, length, offset, error);
395 }
396
397 static guint32
398 get_message_length (guint8 *message, gsize message_length)
399 {
400     gsize offset = 4;
401     return read_int (message, message_length, &offset);
402 }
403
404 static gboolean
405 connect_to_daemon (LightDMGreeter *greeter, GError **error)
406 {
407     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
408     const gchar *to_server_fd, *from_server_fd, *pipe_path;
409
410     if (priv->to_server_channel || priv->from_server_channel)
411         return TRUE;
412
413     /* Use private connection if one exists */  
414     to_server_fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
415     from_server_fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
416     pipe_path = g_getenv ("LIGHTDM_GREETER_PIPE");
417     if (to_server_fd && from_server_fd)
418     {
419         priv->to_server_channel = g_io_channel_unix_new (atoi (to_server_fd));
420         priv->from_server_channel = g_io_channel_unix_new (atoi (from_server_fd));
421     }
422     else if (pipe_path)
423     {
424         GSocketAddress *address;
425         gboolean result;
426
427         priv->socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, error);
428         if (!priv->socket)
429             return FALSE;
430
431         address = g_unix_socket_address_new (pipe_path);
432         result = g_socket_connect (priv->socket, address, NULL, error);
433         g_object_unref (address);
434         if (!result)
435             return FALSE;
436
437         priv->from_server_channel = g_io_channel_unix_new (g_socket_get_fd (priv->socket));
438         priv->to_server_channel = g_io_channel_ref (priv->from_server_channel);
439     }
440     else
441     {
442         g_set_error_literal (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_CONNECTION_FAILED,
443                              "Unable to determine socket to daemon");
444         return FALSE;
445     }
446
447     g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
448
449     if (!g_io_channel_set_encoding (priv->to_server_channel, NULL, error) ||
450         !g_io_channel_set_encoding (priv->from_server_channel, NULL, error))
451         return FALSE;
452
453     return TRUE;
454 }
455
456 static gboolean
457 send_message (LightDMGreeter *greeter, guint8 *message, gsize message_length, GError **error)
458 {
459     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
460     gchar *data;
461     gsize data_length;
462     guint32 stated_length;
463     GError *flush_error = NULL;
464
465     if (!connect_to_daemon (greeter, error))
466         return FALSE;
467
468     /* Double check that we're sending well-formed messages.  If we say we're
469        sending more than we do, we end up DOS'ing lightdm as it waits for the
470        rest.  If we say we're sending less than we do, we confuse the heck out
471        of lightdm, as it starts reading headers from the middle of our
472        messages. */
473     stated_length = HEADER_SIZE + get_message_length (message, message_length);
474     if (stated_length != message_length)
475     {
476         g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
477                      "Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu",
478                      stated_length, message_length);
479         return FALSE;
480     }
481
482     data = (gchar *) message;
483     data_length = message_length;
484     while (data_length > 0)
485     {
486         GIOStatus status;
487         gsize n_written;
488         GError *write_error = NULL;
489
490         status = g_io_channel_write_chars (priv->to_server_channel, data, data_length, &n_written, &write_error);
491         if (write_error)
492             g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
493                          "Failed to write to daemon: %s",
494                          write_error->message);
495         g_clear_error (&write_error);
496         if (status == G_IO_STATUS_AGAIN) 
497             continue;
498         if (status != G_IO_STATUS_NORMAL) 
499             return FALSE;
500         data_length -= n_written;
501         data += n_written;
502     }
503
504     g_debug ("Wrote %zi bytes to daemon", message_length);
505     if (!g_io_channel_flush (priv->to_server_channel, &flush_error))
506     {
507         g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
508                      "Failed to write to daemon: %s",
509                      flush_error->message);
510         g_clear_error (&flush_error);
511         return FALSE;
512     }
513
514     return TRUE;
515 }
516
517 static void
518 handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
519 {
520     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
521     gchar *version;
522     GString *hint_string;
523     int timeout;
524     Request *request;
525
526     version = read_string (message, message_length, offset);
527     hint_string = g_string_new ("");
528     while (*offset < message_length)
529     {
530         gchar *name, *value;
531
532         name = read_string (message, message_length, offset);
533         value = read_string (message, message_length, offset);
534         g_hash_table_insert (priv->hints, name, value);
535         g_string_append_printf (hint_string, " %s=%s", name, value);
536     }
537
538     priv->connected = TRUE;
539     g_debug ("Connected version=%s%s", version, hint_string->str);
540     g_free (version);
541     g_string_free (hint_string, TRUE);
542
543     /* Set timeout for default login */
544     timeout = lightdm_greeter_get_autologin_timeout_hint (greeter);
545     if (timeout)
546     {
547         g_debug ("Setting autologin timer for %d seconds", timeout);
548         priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
549     }
550
551     /* Notify asynchronous caller */
552     request = g_list_nth_data (priv->connect_requests, 0);
553     if (request)
554     {
555         request->result = TRUE;
556         request_complete (request);
557         priv->connect_requests = g_list_remove (priv->connect_requests, request);
558         g_object_unref (request);
559     }
560 }
561
562 static void
563 handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
564 {
565     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
566     guint32 sequence_number, n_messages, i;
567     gchar *username;
568
569     sequence_number = read_int (message, message_length, offset);
570     if (sequence_number != priv->authenticate_sequence_number)
571     {
572         g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
573         return;
574     }
575
576     if (priv->cancelling_authentication)
577     {
578         g_debug ("Ignoring prompt authentication as waiting for it to cancel");
579         return;
580     }
581
582     /* Update username */
583     username = read_string (message, message_length, offset);
584     if (strcmp (username, "") == 0)
585     {
586         g_free (username);
587         username = NULL;
588     }
589     g_free (priv->authentication_user);
590     priv->authentication_user = username;
591
592     g_list_free_full (priv->responses_received, g_free);
593     priv->responses_received = NULL;
594     priv->n_responses_waiting = 0;
595
596     n_messages = read_int (message, message_length, offset);
597     g_debug ("Prompt user with %d message(s)", n_messages);
598
599     for (i = 0; i < n_messages; i++)
600     {
601         int style;
602         gchar *text;
603
604         style = read_int (message, message_length, offset);
605         text = read_string (message, message_length, offset);
606
607         // FIXME: Should stop on prompts?
608         switch (style)
609         {
610         case PAM_PROMPT_ECHO_OFF:
611             priv->n_responses_waiting++;
612             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_SECRET);
613             break;
614         case PAM_PROMPT_ECHO_ON:
615             priv->n_responses_waiting++;
616             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_QUESTION);
617             break;
618         case PAM_ERROR_MSG:
619             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_ERROR);
620             break;
621         case PAM_TEXT_INFO:
622             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_INFO);
623             break;
624         }
625
626         g_free (text);
627     }
628 }
629
630 static void
631 handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
632 {
633     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
634     guint32 sequence_number, return_code;
635     gchar *username;
636
637     sequence_number = read_int (message, message_length, offset);
638
639     if (sequence_number != priv->authenticate_sequence_number)
640     {
641         g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
642         return;
643     }
644
645     username = read_string (message, message_length, offset);
646     return_code = read_int (message, message_length, offset);
647
648     g_debug ("Authentication complete for user %s with return code %d", username, return_code);
649
650     /* Update username */
651     if (strcmp (username, "") == 0)
652     {
653         g_free (username);
654         username = NULL;
655     }
656     g_free (priv->authentication_user);
657     priv->authentication_user = username;
658
659     priv->cancelling_authentication = FALSE;
660     priv->is_authenticated = (return_code == 0);
661
662     priv->in_authentication = FALSE;
663     g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
664 }
665
666 static void
667 handle_idle (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
668 {
669     g_signal_emit (G_OBJECT (greeter), signals[IDLE], 0);
670 }
671
672 static void
673 handle_reset (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
674 {
675     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
676     GString *hint_string;
677
678     g_hash_table_remove_all (priv->hints);
679
680     hint_string = g_string_new ("");
681     while (*offset < message_length)
682     {
683         gchar *name, *value;
684
685         name = read_string (message, message_length, offset);
686         value = read_string (message, message_length, offset);
687         g_hash_table_insert (priv->hints, name, value);
688         g_string_append_printf (hint_string, " %s=%s", name, value);
689     }
690
691     g_debug ("Reset%s", hint_string->str);
692     g_string_free (hint_string, TRUE);
693
694     g_signal_emit (G_OBJECT (greeter), signals[RESET], 0);
695 }
696
697 static void
698 handle_session_result (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
699 {
700     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
701     Request *request;
702
703     /* Notify asynchronous caller */
704     request = g_list_nth_data (priv->start_session_requests, 0);
705     if (request)
706     {
707         guint32 return_code;
708
709         return_code = read_int (message, message_length, offset);
710         if (return_code == 0)
711             request->result = TRUE;
712         else
713             request->error = g_error_new (LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_SESSION_FAILED,
714                                           "Session returned error code %d", return_code);
715         request_complete (request);
716         priv->start_session_requests = g_list_remove (priv->start_session_requests, request);
717         g_object_unref (request);
718     }
719 }
720
721 static void
722 handle_shared_dir_result (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
723 {
724     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
725     Request *request;
726
727     /* Notify asynchronous caller */
728     request = g_list_nth_data (priv->ensure_shared_data_dir_requests, 0);
729     if (request)
730     {
731         request->dir = read_string (message, message_length, offset);
732         /* Blank data dir means invalid user */
733         if (g_strcmp0 (request->dir, "") == 0)
734         {
735             g_free (request->dir);
736             request->dir = NULL;
737             request->error = g_error_new (LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_INVALID_USER,
738                                           "No such user");
739         }
740         request_complete (request);
741         priv->ensure_shared_data_dir_requests = g_list_remove (priv->ensure_shared_data_dir_requests, request);
742         g_object_unref (request);
743     }
744 }
745
746 static void
747 handle_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
748 {
749     gsize offset = 0;
750     guint32 id;
751
752     id = read_int (message, message_length, &offset);
753     read_int (message, message_length, &offset);
754     switch (id)
755     {
756     case SERVER_MESSAGE_CONNECTED:
757         handle_connected (greeter, message, message_length, &offset);
758         break;
759     case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
760         handle_prompt_authentication (greeter, message, message_length, &offset);
761         break;
762     case SERVER_MESSAGE_END_AUTHENTICATION:
763         handle_end_authentication (greeter, message, message_length, &offset);
764         break;
765     case SERVER_MESSAGE_SESSION_RESULT:
766         handle_session_result (greeter, message, message_length, &offset);
767         break;
768     case SERVER_MESSAGE_SHARED_DIR_RESULT:
769         handle_shared_dir_result (greeter, message, message_length, &offset);
770         break;
771     case SERVER_MESSAGE_IDLE:
772         handle_idle (greeter, message, message_length, &offset);
773         break;
774     case SERVER_MESSAGE_RESET:
775         handle_reset (greeter, message, message_length, &offset);
776         break;
777     default:
778         g_warning ("Unknown message from server: %d", id);
779         break;
780     }
781 }
782
783 static gboolean
784 recv_message (LightDMGreeter *greeter, gboolean block, guint8 **message, gsize *length, GError **error)
785 {
786     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
787     gsize n_to_read, n_read;
788
789     if (!connect_to_daemon (greeter, error))
790         return FALSE;
791
792     /* Read the header, or the whole message if we already have that */
793     n_to_read = HEADER_SIZE;
794     if (priv->n_read >= HEADER_SIZE)
795         n_to_read += get_message_length (priv->read_buffer, priv->n_read);
796
797     do
798     {
799         GIOStatus status;
800         GError *read_error = NULL;
801
802         status = g_io_channel_read_chars (priv->from_server_channel,
803                                           (gchar *) priv->read_buffer + priv->n_read,
804                                           n_to_read - priv->n_read,
805                                           &n_read,
806                                           &read_error);
807         if (status == G_IO_STATUS_AGAIN)
808         {
809             if (block)
810                 continue;
811         }
812         else if (status != G_IO_STATUS_NORMAL)
813         {
814             g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
815                          "Failed to read from daemon: %s",
816                          read_error->message);
817             g_clear_error (&read_error);
818             return FALSE;
819         }
820
821         g_debug ("Read %zi bytes from daemon", n_read);
822
823         priv->n_read += n_read;
824     } while (priv->n_read < n_to_read && block);
825
826     /* Stop if haven't got all the data we want */
827     if (priv->n_read != n_to_read)
828     {
829         if (message)
830             *message = NULL;
831         if (length)
832             *length = 0;
833         return TRUE;
834     }
835
836     /* If have header, rerun for content */
837     if (priv->n_read == HEADER_SIZE)
838     {
839         n_to_read = get_message_length (priv->read_buffer, priv->n_read);
840         if (n_to_read > 0)
841         {
842             priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
843             return recv_message (greeter, block, message, length, error);
844         }
845     }
846
847     if (message)
848         *message = priv->read_buffer;
849     else
850         g_free (priv->read_buffer);
851     if (length)
852         *length = priv->n_read;
853
854     priv->read_buffer = g_malloc (priv->n_read);
855     priv->n_read = 0;
856
857     return TRUE;
858 }
859
860 static gboolean
861 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
862 {
863     LightDMGreeter *greeter = data;
864     guint8 *message;
865     gsize message_length;
866     GError *error = NULL;
867
868     /* Read one message and process it */
869     if (!recv_message (greeter, FALSE, &message, &message_length, &error))
870     {
871         // FIXME: Should push this up to the client somehow
872         g_warning ("Failed to read from daemon: %s\n", error->message);
873         g_clear_error (&error);
874         return G_SOURCE_REMOVE;
875     }
876
877     if (message)
878     {
879         handle_message (greeter, message, message_length);
880         g_free (message);
881     }
882
883     return G_SOURCE_CONTINUE;
884 }
885
886 static gboolean
887 send_connect (LightDMGreeter *greeter, gboolean resettable, GError **error)
888 {
889     guint8 message[MAX_MESSAGE_LENGTH];
890     gsize offset = 0;
891
892     g_debug ("Connecting to display manager...");
893     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION) + int_length (), &offset, error) &&
894            write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset, error) &&
895            write_int (message, MAX_MESSAGE_LENGTH, resettable ? 1 : 0, &offset, error) &&
896            send_message (greeter, message, offset, error);
897 }
898
899 static gboolean
900 send_start_session (LightDMGreeter *greeter, const gchar *session, GError **error)
901 {
902     guint8 message[MAX_MESSAGE_LENGTH];
903     gsize offset = 0;
904
905     if (session)
906         g_debug ("Starting session %s", session);
907     else
908         g_debug ("Starting default session");
909
910     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset, error) &&
911            write_string (message, MAX_MESSAGE_LENGTH, session, &offset, error) &&
912            send_message (greeter, message, offset, error);
913 }
914
915 static gboolean
916 send_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username, GError **error)
917 {
918     guint8 message[MAX_MESSAGE_LENGTH];
919     gsize offset = 0;
920
921     g_debug ("Ensuring data directory for user %s", username);
922
923     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_ENSURE_SHARED_DIR, string_length (username), &offset, error) &&
924            write_string (message, MAX_MESSAGE_LENGTH, username, &offset, error) &&
925            send_message (greeter, message, offset, error);
926 }
927
928 /**
929  * lightdm_greeter_connect_to_daemon:
930  * @greeter: The greeter to connect
931  * @cancellable: (allow-none): A #GCancellable or %NULL.
932  * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
933  * @user_data: (allow-none): data to pass to the @callback or %NULL.
934  *
935  * Asynchronously connects the greeter to the display manager.
936  *
937  * When the operation is finished, @callback will be invoked. You can then call lightdm_greeter_connect_to_daemon_finish() to get the result of the operation.
938  *
939  * See lightdm_greeter_connect_to_daemon_sync() for the synchronous version.
940  **/
941 void
942 lightdm_greeter_connect_to_daemon (LightDMGreeter *greeter, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
943 {
944     LightDMGreeterPrivate *priv;
945     Request *request;
946     GError *error = NULL;
947
948     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
949
950     priv = GET_PRIVATE (greeter);
951
952     request = request_new (greeter, cancellable, callback, user_data);
953     if (send_connect (greeter, priv->resettable, &error))
954         priv->connect_requests = g_list_append (priv->connect_requests, request);
955     else
956     {
957         request->error = error;
958         request_complete (request);
959         g_object_unref (request);
960     }
961 }
962
963 /**
964  * lightdm_greeter_connect_to_daemon_finish:
965  * @greeter: The greeter the the request was done with
966  * @result: A #GAsyncResult.
967  * @error: return location for a #GError, or %NULL
968  *
969  * Finishes an operation started with lightdm_greeter_connect_to_daemon().
970  *
971  * Return value: #TRUE if successfully connected
972  **/
973 gboolean
974 lightdm_greeter_connect_to_daemon_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error)
975 {
976     Request *request = REQUEST (result);
977
978     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
979
980     if (request->error)
981         g_propagate_error (error, request->error);
982     return request->result;
983 }
984
985 /**
986  * lightdm_greeter_connect_to_daemon_sync:
987  * @greeter: The greeter to connect
988  * @error: return location for a #GError, or %NULL
989  *
990  * Connects the greeter to the display manager.  Will block until connected.
991  *
992  * Return value: #TRUE if successfully connected
993  **/
994 gboolean
995 lightdm_greeter_connect_to_daemon_sync (LightDMGreeter *greeter, GError **error)
996 {
997     LightDMGreeterPrivate *priv;
998     Request *request;
999
1000     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1001
1002     priv = GET_PRIVATE (greeter);
1003
1004     /* Read until we are connected */
1005     if (!send_connect (greeter, priv->resettable, error))
1006         return FALSE;
1007     request = request_new (greeter, NULL, NULL, NULL);
1008     priv->connect_requests = g_list_append (priv->connect_requests, g_object_ref (request));
1009     do
1010     {
1011         guint8 *message;
1012         gsize message_length;
1013
1014         if (!recv_message (greeter, TRUE, &message, &message_length, error))
1015             return FALSE;
1016         handle_message (greeter, message, message_length);
1017         g_free (message);
1018     } while (!request->complete);
1019
1020     return lightdm_greeter_connect_to_daemon_finish (greeter, G_ASYNC_RESULT (request), error);
1021 }
1022
1023 /**
1024  * lightdm_greeter_connect_sync:
1025  * @greeter: The greeter to connect
1026  * @error: return location for a #GError, or %NULL
1027  *
1028  * Connects the greeter to the display manager.  Will block until connected.
1029  *
1030  * Return value: #TRUE if successfully connected
1031  *
1032  * Deprecated: 1.11.1: Use lightdm_greeter_connect_to_daemon_sync() instead
1033  **/
1034 gboolean
1035 lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
1036 {
1037     return lightdm_greeter_connect_to_daemon_sync (greeter, error);
1038 }
1039
1040 /**
1041  * lightdm_greeter_get_hint:
1042  * @greeter: A #LightDMGreeter
1043  * @name: The hint name to query.
1044  *
1045  * Get a hint.
1046  *
1047  * Return value: (nullable): The value for this hint or #NULL if not set.
1048  **/
1049 const gchar *
1050 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
1051 {
1052     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1053     return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
1054 }
1055
1056 /**
1057  * lightdm_greeter_get_default_session_hint:
1058  * @greeter: A #LightDMGreeter
1059  *
1060  * Get the default session to use.
1061  *
1062  * Return value: The session name
1063  **/
1064 const gchar *
1065 lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
1066 {
1067     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1068     return lightdm_greeter_get_hint (greeter, "default-session");
1069 }
1070
1071 /**
1072  * lightdm_greeter_get_hide_users_hint:
1073  * @greeter: A #LightDMGreeter
1074  *
1075  * Check if user accounts should be shown.  If this is TRUE then the list of
1076  * accounts should be taken from #LightDMUserList and displayed in the greeter
1077  * for the user to choose from.  Note that this list can be empty and it is
1078  * recommended you show a method for the user to enter a username manually.
1079  *
1080  * If this option is shown the greeter should only allow these users to be
1081  * chosen for login unless the manual login hint is set.
1082  *
1083  * Return value: #TRUE if the available users should not be shown.
1084  */
1085 gboolean
1086 lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
1087 {
1088     const gchar *value;
1089
1090     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1091     value = lightdm_greeter_get_hint (greeter, "hide-users");
1092
1093     return g_strcmp0 (value, "true") == 0;
1094 }
1095
1096 /**
1097  * lightdm_greeter_get_show_manual_login_hint:
1098  * @greeter: A #LightDMGreeter
1099  *
1100  * Check if a manual login option should be shown.  If set the GUI
1101  * should provide a way for a username to be entered manually.
1102  * Without this hint a greeter which is showing a user list can
1103  * limit logins to only those users.
1104  *
1105  * Return value: #TRUE if a manual login option should be shown.
1106  */
1107 gboolean
1108 lightdm_greeter_get_show_manual_login_hint (LightDMGreeter *greeter)
1109 {
1110     const gchar *value;
1111
1112     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1113     value = lightdm_greeter_get_hint (greeter, "show-manual-login");
1114
1115     return g_strcmp0 (value, "true") == 0;
1116 }
1117
1118 /**
1119  * lightdm_greeter_get_show_remote_login_hint:
1120  * @greeter: A #LightDMGreeter
1121  *
1122  * Check if a remote login option should be shown.  If set the GUI
1123  * should provide a way for a user to log into a remote desktop server.
1124  *
1125  * Return value: #TRUE if a remote login option should be shown.
1126  */
1127 gboolean
1128 lightdm_greeter_get_show_remote_login_hint (LightDMGreeter *greeter)
1129 {
1130     const gchar *value;
1131
1132     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1133     value = lightdm_greeter_get_hint (greeter, "show-remote-login");
1134
1135     return g_strcmp0 (value, "true") == 0;
1136 }
1137
1138 /**
1139  * lightdm_greeter_get_lock_hint:
1140  * @greeter: A #LightDMGreeter
1141  *
1142  * Check if the greeter is acting as a lock screen.
1143  *
1144  * Return value: #TRUE if the greeter was triggered by locking the seat.
1145  */
1146 gboolean
1147 lightdm_greeter_get_lock_hint (LightDMGreeter *greeter)
1148 {
1149     const gchar *value;
1150
1151     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1152     value = lightdm_greeter_get_hint (greeter, "lock-screen");
1153
1154     return g_strcmp0 (value, "true") == 0;
1155 }
1156
1157 /**
1158  * lightdm_greeter_get_has_guest_account_hint:
1159  * @greeter: A #LightDMGreeter
1160  *
1161  * Check if guest sessions are supported.
1162  *
1163  * Return value: #TRUE if guest sessions are supported.
1164  */
1165 gboolean
1166 lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
1167 {
1168     const gchar *value;
1169
1170     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1171     value = lightdm_greeter_get_hint (greeter, "has-guest-account");
1172
1173     return g_strcmp0 (value, "true") == 0;
1174 }
1175
1176 /**
1177  * lightdm_greeter_get_select_user_hint:
1178  * @greeter: A #LightDMGreeter
1179  *
1180  * Get the user to select by default.
1181  *
1182  * Return value: (nullable): A username or %NULL if no particular user should be selected.
1183  */
1184 const gchar *
1185 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
1186 {
1187     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1188     return lightdm_greeter_get_hint (greeter, "select-user");
1189 }
1190
1191 /**
1192  * lightdm_greeter_get_select_guest_hint:
1193  * @greeter: A #LightDMGreeter
1194  *
1195  * Check if the guest account should be selected by default.
1196  *
1197  * Return value: #TRUE if the guest account should be selected by default.
1198  */
1199 gboolean
1200 lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
1201 {
1202     const gchar *value;
1203
1204     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1205     value = lightdm_greeter_get_hint (greeter, "select-guest");
1206
1207     return g_strcmp0 (value, "true") == 0;
1208 }
1209
1210 /**
1211  * lightdm_greeter_get_autologin_user_hint:
1212  * @greeter: A #LightDMGreeter
1213  *
1214  * Get the user account to automatically log into when the timer expires.
1215  *
1216  * Return value: (nullable): The user account to automatically log into or %NULL if none configured.
1217  */
1218 const gchar *
1219 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
1220 {
1221     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1222     return lightdm_greeter_get_hint (greeter, "autologin-user");
1223 }
1224
1225 /**
1226  * lightdm_greeter_get_autologin_guest_hint:
1227  * @greeter: A #LightDMGreeter
1228  *
1229  * Check if the guest account should be automatically logged into when the timer expires.
1230  *
1231  * Return value: #TRUE if the guest account should be automatically logged into.
1232  */
1233 gboolean
1234 lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
1235 {
1236     const gchar *value;
1237
1238     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1239     value = lightdm_greeter_get_hint (greeter, "autologin-guest");
1240
1241     return g_strcmp0 (value, "true") == 0;
1242 }
1243
1244 /**
1245  * lightdm_greeter_get_autologin_timeout_hint:
1246  * @greeter: A #LightDMGreeter
1247  *
1248  * Get the number of seconds to wait before automaitcally logging in.
1249  *
1250  * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
1251  */
1252 gint
1253 lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
1254 {
1255     const gchar *value;
1256     gint timeout = 0;
1257
1258     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1259     value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
1260     if (value)
1261         timeout = atoi (value);
1262     if (timeout < 0)
1263         timeout = 0;
1264
1265     return timeout;
1266 }
1267
1268 /**
1269  * lightdm_greeter_cancel_autologin:
1270  * @greeter: A #LightDMGreeter
1271  *
1272  * Cancel the automatic login.
1273  */
1274 void
1275 lightdm_greeter_cancel_autologin (LightDMGreeter *greeter)
1276 {
1277     LightDMGreeterPrivate *priv;
1278
1279     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1280
1281     priv = GET_PRIVATE (greeter);
1282
1283     if (priv->autologin_timeout)
1284        g_source_remove (priv->autologin_timeout);
1285     priv->autologin_timeout = 0;
1286 }
1287
1288 /**
1289  * lightdm_greeter_authenticate:
1290  * @greeter: A #LightDMGreeter
1291  * @username: (allow-none): A username or #NULL to prompt for a username.
1292  * @error: return location for a #GError, or %NULL
1293  *
1294  * Starts the authentication procedure for a user.
1295  *
1296  * Return value: #TRUE if authentication request sent.
1297  **/
1298 gboolean
1299 lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username, GError **error)
1300 {
1301     LightDMGreeterPrivate *priv;
1302     guint8 message[MAX_MESSAGE_LENGTH];
1303     gsize offset = 0;
1304
1305     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1306
1307     priv = GET_PRIVATE (greeter);
1308
1309     g_return_val_if_fail (priv->connected, FALSE);
1310
1311     priv->cancelling_authentication = FALSE;
1312     priv->authenticate_sequence_number++;
1313     priv->in_authentication = TRUE;
1314     priv->is_authenticated = FALSE;
1315     if (username != priv->authentication_user)
1316     {
1317         g_free (priv->authentication_user);
1318         priv->authentication_user = g_strdup (username);
1319     }
1320
1321     g_debug ("Starting authentication for user %s...", username);
1322     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset, error) &&
1323            write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset, error) &&
1324            write_string (message, MAX_MESSAGE_LENGTH, username, &offset, error) &&
1325            send_message (greeter, message, offset, error);
1326 }
1327
1328 /**
1329  * lightdm_greeter_authenticate_as_guest:
1330  * @greeter: A #LightDMGreeter
1331  * @error: return location for a #GError, or %NULL
1332  *
1333  * Starts the authentication procedure for the guest user.
1334  *
1335  * Return value: #TRUE if authentication request sent.
1336  **/
1337 gboolean
1338 lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter, GError **error)
1339 {
1340     LightDMGreeterPrivate *priv;
1341     guint8 message[MAX_MESSAGE_LENGTH];
1342     gsize offset = 0;
1343
1344     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1345
1346     priv = GET_PRIVATE (greeter);
1347
1348     g_return_val_if_fail (priv->connected, FALSE);
1349
1350     priv->cancelling_authentication = FALSE;
1351     priv->authenticate_sequence_number++;
1352     priv->in_authentication = TRUE;
1353     priv->is_authenticated = FALSE;
1354     g_free (priv->authentication_user);
1355     priv->authentication_user = NULL;
1356
1357     g_debug ("Starting authentication for guest account...");
1358     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset, error) &&
1359            write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset, error) &&
1360            send_message (greeter, message, offset, error);
1361 }
1362
1363 /**
1364  * lightdm_greeter_authenticate_autologin:
1365  * @greeter: A #LightDMGreeter
1366  * @error: return location for a #GError, or %NULL
1367  *
1368  * Starts the authentication procedure for the automatic login user.
1369  *
1370  * Return value: #TRUE if authentication request sent.
1371  **/
1372 gboolean
1373 lightdm_greeter_authenticate_autologin (LightDMGreeter *greeter, GError **error)
1374 {
1375     const gchar *user;
1376
1377     user = lightdm_greeter_get_autologin_user_hint (greeter);
1378     if (lightdm_greeter_get_autologin_guest_hint (greeter))
1379         return lightdm_greeter_authenticate_as_guest (greeter, error);
1380     else if (user)
1381         return lightdm_greeter_authenticate (greeter, user, error);
1382     else
1383     {
1384         g_set_error_literal (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_NO_AUTOLOGIN,
1385                              "Can't authenticate autologin; autologin not configured");
1386         return FALSE;
1387     }
1388 }
1389
1390 /**
1391  * lightdm_greeter_authenticate_remote:
1392  * @greeter: A #LightDMGreeter
1393  * @session: The name of a remote session
1394  * @username: (allow-none): A username of #NULL to prompt for a username.
1395  * @error: return location for a #GError, or %NULL
1396  *
1397  * Start authentication for a remote session type.
1398  *
1399  * Return value: #TRUE if authentication request sent.
1400  **/
1401 gboolean
1402 lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *session, const gchar *username, GError **error)
1403 {
1404     LightDMGreeterPrivate *priv;
1405     guint8 message[MAX_MESSAGE_LENGTH];
1406     gsize offset = 0;
1407
1408     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1409
1410     priv = GET_PRIVATE (greeter);
1411
1412     g_return_val_if_fail (priv->connected, FALSE);
1413
1414     priv->cancelling_authentication = FALSE;
1415     priv->authenticate_sequence_number++;
1416     priv->in_authentication = TRUE;
1417     priv->is_authenticated = FALSE;
1418     g_free (priv->authentication_user);
1419     priv->authentication_user = NULL;
1420
1421     if (username)
1422         g_debug ("Starting authentication for remote session %s as user %s...", session, username);
1423     else
1424         g_debug ("Starting authentication for remote session %s...", session);
1425
1426     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_REMOTE, int_length () + string_length (session) + string_length (username), &offset, error) &&
1427            write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset, error) &&
1428            write_string (message, MAX_MESSAGE_LENGTH, session, &offset, error) &&
1429            write_string (message, MAX_MESSAGE_LENGTH, username, &offset, error) &&
1430            send_message (greeter, message, offset, error);
1431 }
1432
1433 /**
1434  * lightdm_greeter_respond:
1435  * @greeter: A #LightDMGreeter
1436  * @response: Response to a prompt
1437  * @error: return location for a #GError, or %NULL
1438  *
1439  * Provide response to a prompt.  May be one in a series.
1440  *
1441  * Return value: #TRUE if response sent.
1442  **/
1443 gboolean
1444 lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response, GError **error)
1445 {
1446     LightDMGreeterPrivate *priv;
1447     guint8 message[MAX_MESSAGE_LENGTH];
1448     gsize offset = 0;
1449
1450     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1451     g_return_val_if_fail (response != NULL, FALSE);
1452
1453     priv = GET_PRIVATE (greeter);
1454
1455     g_return_val_if_fail (priv->connected, FALSE);
1456     g_return_val_if_fail (priv->n_responses_waiting > 0, FALSE);
1457
1458     priv->n_responses_waiting--;
1459     priv->responses_received = g_list_append (priv->responses_received, g_strdup (response));
1460
1461     if (priv->n_responses_waiting == 0)
1462     {
1463         guint32 msg_length;
1464         GList *iter;
1465
1466         g_debug ("Providing response to display manager");
1467
1468         msg_length = int_length ();
1469         for (iter = priv->responses_received; iter; iter = iter->next)
1470             msg_length += string_length ((gchar *)iter->data);
1471
1472         if (!write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, msg_length, &offset, error) ||
1473             !write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset, error))
1474             return FALSE;
1475         for (iter = priv->responses_received; iter; iter = iter->next)
1476         {
1477             if (!write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset, error))
1478                 return FALSE;
1479         }
1480         if (!send_message (greeter, message, offset, error))
1481             return FALSE;
1482
1483         g_list_free_full (priv->responses_received, g_free);
1484         priv->responses_received = NULL;
1485     }
1486
1487     return TRUE;
1488 }
1489
1490 /**
1491  * lightdm_greeter_cancel_authentication:
1492  * @greeter: A #LightDMGreeter
1493  * @error: return location for a #GError, or %NULL
1494  *
1495  * Cancel the current user authentication.
1496  *
1497  * Return value: #TRUE if cancel request sent.
1498  **/
1499 gboolean
1500 lightdm_greeter_cancel_authentication (LightDMGreeter *greeter, GError **error)
1501 {
1502     LightDMGreeterPrivate *priv;
1503     guint8 message[MAX_MESSAGE_LENGTH];
1504     gsize offset = 0;
1505
1506     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1507
1508     priv = GET_PRIVATE (greeter);
1509
1510     g_return_val_if_fail (priv->connected, FALSE);
1511
1512     priv->cancelling_authentication = TRUE;
1513     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset, error) &&
1514            send_message (greeter, message, offset, error);
1515 }
1516
1517 /**
1518  * lightdm_greeter_get_in_authentication:
1519  * @greeter: A #LightDMGreeter
1520  *
1521  * Checks if the greeter is in the process of authenticating.
1522  *
1523  * Return value: #TRUE if the greeter is authenticating a user.
1524  **/
1525 gboolean
1526 lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
1527 {
1528     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1529     return GET_PRIVATE (greeter)->in_authentication;
1530 }
1531
1532 /**
1533  * lightdm_greeter_get_is_authenticated:
1534  * @greeter: A #LightDMGreeter
1535  *
1536  * Checks if the greeter has successfully authenticated.
1537  *
1538  * Return value: #TRUE if the greeter is authenticated for login.
1539  **/
1540 gboolean
1541 lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
1542 {
1543     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1544     return GET_PRIVATE (greeter)->is_authenticated;
1545 }
1546
1547 /**
1548  * lightdm_greeter_get_authentication_user:
1549  * @greeter: A #LightDMGreeter
1550  *
1551  * Get the user that is being authenticated.
1552  *
1553  * Return value: (nullable): The username of the authentication user being authenticated or #NULL if no authentication in progress.
1554  */
1555 const gchar *
1556 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
1557 {
1558     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1559     return GET_PRIVATE (greeter)->authentication_user;
1560 }
1561
1562 /**
1563  * lightdm_greeter_set_language:
1564  * @greeter: A #LightDMGreeter
1565  * @language: The language to use for this user in the form of a locale specification (e.g. "de_DE.UTF-8").
1566  * @error: return location for a #GError, or %NULL
1567  *
1568  * Set the language for the currently authenticated user.
1569  *
1570  * Return value: #TRUE if set language request sent.
1571  **/
1572 gboolean
1573 lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language, GError **error)
1574 {
1575     LightDMGreeterPrivate *priv;
1576     guint8 message[MAX_MESSAGE_LENGTH];
1577     gsize offset = 0;
1578
1579     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1580
1581     priv = GET_PRIVATE (greeter);
1582
1583     g_return_val_if_fail (priv->connected, FALSE);
1584
1585     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset, error) &&
1586            write_string (message, MAX_MESSAGE_LENGTH, language, &offset, error) &&
1587            send_message (greeter, message, offset, error);
1588 }
1589
1590 /**
1591  * lightdm_greeter_start_session:
1592  * @greeter: A #LightDMGreeter
1593  * @session: (allow-none): The session to log into or #NULL to use the default.
1594  * @cancellable: (allow-none): A #GCancellable or %NULL.
1595  * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
1596  * @user_data: (allow-none): data to pass to the @callback or %NULL.
1597  *
1598  * Asynchronously start a session for the authenticated user.
1599  *
1600  * When the operation is finished, @callback will be invoked. You can then call lightdm_greeter_start_session_finish() to get the result of the operation.
1601  *
1602  * See lightdm_greeter_start_session_sync() for the synchronous version.
1603  **/
1604 void
1605 lightdm_greeter_start_session (LightDMGreeter *greeter, const gchar *session, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
1606 {
1607     LightDMGreeterPrivate *priv;
1608     Request *request;
1609     GError *error = NULL;
1610
1611     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1612
1613     priv = GET_PRIVATE (greeter);
1614
1615     request = request_new (greeter, cancellable, callback, user_data);
1616     priv->start_session_requests = g_list_append (priv->start_session_requests, request);
1617     if (!send_start_session (greeter, session, &error))
1618     {
1619         request->error = error;
1620         request_complete (request);
1621     }
1622 }
1623
1624 /**
1625  * lightdm_greeter_start_session_finish:
1626  * @greeter: A #LightDMGreeter
1627  * @result: A #GAsyncResult.
1628  * @error: return location for a #GError, or %NULL
1629  *
1630  * Start a session for the authenticated user.
1631  *
1632  * Return value: TRUE if the session was started.
1633  **/
1634 gboolean
1635 lightdm_greeter_start_session_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error)
1636 {
1637     Request *request = REQUEST (result);
1638
1639     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1640
1641     if (request->error)  
1642         g_propagate_error (error, request->error);
1643     return request->result;
1644 }
1645
1646 /**
1647  * lightdm_greeter_start_session_sync:
1648  * @greeter: A #LightDMGreeter
1649  * @session: (allow-none): The session to log into or #NULL to use the default.
1650  * @error: return location for a #GError, or %NULL
1651  *
1652  * Start a session for the authenticated user.
1653  *
1654  * Return value: TRUE if the session was started.
1655  **/
1656 gboolean
1657 lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
1658 {
1659     LightDMGreeterPrivate *priv;
1660     Request *request;
1661
1662     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1663
1664     priv = GET_PRIVATE (greeter);
1665
1666     g_return_val_if_fail (priv->connected, FALSE);
1667     g_return_val_if_fail (priv->is_authenticated, FALSE);
1668
1669     /* Read until the session is started */
1670     if (!send_start_session (greeter, session, error))
1671         return FALSE;
1672     request = request_new (greeter, NULL, NULL, NULL);
1673     priv->start_session_requests = g_list_append (priv->start_session_requests, g_object_ref (request));
1674     do
1675     {
1676         guint8 *message;
1677         gsize message_length;
1678
1679         if (!recv_message (greeter, TRUE, &message, &message_length, error))
1680             return FALSE;
1681         handle_message (greeter, message, message_length);
1682         g_free (message);
1683     } while (!request->complete);
1684
1685     return lightdm_greeter_start_session_finish (greeter, G_ASYNC_RESULT (request), error);
1686 }
1687
1688 /**
1689  * lightdm_greeter_ensure_shared_data_dir:
1690  * @greeter: A #LightDMGreeter
1691  * @username: A username
1692  * @cancellable: (allow-none): A #GCancellable or %NULL.
1693  * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
1694  * @user_data: (allow-none): data to pass to the @callback or %NULL.
1695  *
1696  * Ensure that a shared data dir for the given user is available.  Both the
1697  * greeter user and @username will have write access to that folder.  The
1698  * intention is that larger pieces of shared data would be stored there (files
1699  * that the greeter creates but wants to give to a user -- like camera
1700  * photos -- or files that the user creates but wants the greeter to
1701  * see -- like contact avatars).
1702  *
1703  * LightDM will automatically create these if the user actually logs in, so
1704  * greeters only need to call this method if they want to store something in
1705  * the directory themselves.
1706  **/
1707 void
1708 lightdm_greeter_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
1709 {
1710     LightDMGreeterPrivate *priv;
1711     Request *request;
1712     GError *error = NULL;
1713
1714     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1715
1716     priv = GET_PRIVATE (greeter);
1717
1718     request = request_new (greeter, cancellable, callback, user_data);
1719     priv->ensure_shared_data_dir_requests = g_list_append (priv->ensure_shared_data_dir_requests, request);
1720     if (!send_ensure_shared_data_dir (greeter, username, &error))
1721     {
1722         request->error = error;
1723         request_complete (request);
1724     }
1725 }
1726
1727 /**
1728  * lightdm_greeter_ensure_shared_data_dir_finish:
1729  * @result: A #GAsyncResult.
1730  * @greeter: A #LightDMGreeter
1731  * @error: return location for a #GError, or %NULL
1732  *
1733  * Function to call from lightdm_greeter_ensure_shared_data_dir callback.
1734  *
1735  * Return value: The path to the shared directory, free with g_free.
1736  **/
1737 gchar *
1738 lightdm_greeter_ensure_shared_data_dir_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error)
1739 {
1740     Request *request = REQUEST (result);
1741
1742     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1743
1744     if (request->error)
1745         g_propagate_error (error, request->error);
1746     return g_strdup (request->dir);
1747 }
1748
1749 /**
1750  * lightdm_greeter_ensure_shared_data_dir_sync:
1751  * @greeter: A #LightDMGreeter
1752  * @username: A username
1753  * @error: return location for a #GError, or %NULL
1754  *
1755  * Ensure that a shared data dir for the given user is available.  Both the
1756  * greeter user and @username will have write access to that folder.  The
1757  * intention is that larger pieces of shared data would be stored there (files
1758  * that the greeter creates but wants to give to a user -- like camera
1759  * photos -- or files that the user creates but wants the greeter to
1760  * see -- like contact avatars).
1761  *
1762  * LightDM will automatically create these if the user actually logs in, so
1763  * greeters only need to call this method if they want to store something in
1764  * the directory themselves.
1765  *
1766  * Return value: The path to the shared directory, free with g_free.
1767  **/
1768 gchar *
1769 lightdm_greeter_ensure_shared_data_dir_sync (LightDMGreeter *greeter, const gchar *username, GError **error)
1770 {
1771     LightDMGreeterPrivate *priv;
1772     Request *request;
1773
1774     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1775
1776     priv = GET_PRIVATE (greeter);
1777
1778     g_return_val_if_fail (priv->connected, NULL);
1779
1780     /* Read until a response */
1781     if (!send_ensure_shared_data_dir (greeter, username, error))
1782         return NULL;
1783     request = request_new (greeter, NULL, NULL, NULL);
1784     priv->ensure_shared_data_dir_requests = g_list_append (priv->ensure_shared_data_dir_requests, g_object_ref (request));
1785     do
1786     {
1787         guint8 *message;
1788         gsize message_length;
1789
1790         if (!recv_message (greeter, TRUE, &message, &message_length, error))
1791             return FALSE;
1792         handle_message (greeter, message, message_length);
1793         g_free (message);
1794     } while (!request->complete);
1795
1796     return lightdm_greeter_ensure_shared_data_dir_finish (greeter, G_ASYNC_RESULT (request), error);
1797 }
1798
1799 static void
1800 lightdm_greeter_init (LightDMGreeter *greeter)
1801 {
1802     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1803
1804     priv->read_buffer = g_malloc (HEADER_SIZE);
1805     priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1806 }
1807
1808 static void
1809 lightdm_greeter_set_property (GObject      *object,
1810                               guint         prop_id,
1811                               const GValue *value,
1812                               GParamSpec   *pspec)
1813 {
1814     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1815 }
1816
1817 static void
1818 lightdm_greeter_get_property (GObject    *object,
1819                               guint       prop_id,
1820                               GValue     *value,
1821                               GParamSpec *pspec)
1822 {
1823     LightDMGreeter *self;
1824
1825     self = LIGHTDM_GREETER (object);
1826
1827     switch (prop_id) {
1828     case PROP_DEFAULT_SESSION_HINT:
1829         g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
1830         break;
1831     case PROP_HIDE_USERS_HINT:
1832         g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
1833         break;
1834     case PROP_SHOW_MANUAL_LOGIN_HINT:
1835         g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
1836         break;
1837     case PROP_SHOW_REMOTE_LOGIN_HINT:
1838         g_value_set_boolean (value, lightdm_greeter_get_show_remote_login_hint (self));
1839         break;
1840     case PROP_LOCK_HINT:
1841         g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
1842         break;
1843     case PROP_HAS_GUEST_ACCOUNT_HINT:
1844         g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
1845         break;
1846     case PROP_SELECT_USER_HINT:
1847         g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
1848         break;
1849     case PROP_SELECT_GUEST_HINT:
1850         g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
1851         break;
1852     case PROP_AUTOLOGIN_USER_HINT:
1853         g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
1854         break;
1855     case PROP_AUTOLOGIN_GUEST_HINT:
1856         g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
1857         break;
1858     case PROP_AUTOLOGIN_TIMEOUT_HINT:
1859         g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
1860         break;
1861     case PROP_AUTHENTICATION_USER:
1862         g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
1863         break;
1864     case PROP_IN_AUTHENTICATION:
1865         g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
1866         break;
1867     case PROP_IS_AUTHENTICATED:
1868         g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
1869         break;
1870     default:
1871         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1872         break;
1873     }
1874 }
1875
1876 static void
1877 lightdm_greeter_finalize (GObject *object)
1878 {
1879     LightDMGreeter *self = LIGHTDM_GREETER (object);
1880     LightDMGreeterPrivate *priv = GET_PRIVATE (self);
1881
1882     g_clear_object (&priv->socket);
1883     if (priv->to_server_channel)
1884         g_io_channel_unref (priv->to_server_channel);
1885     if (priv->from_server_channel)
1886         g_io_channel_unref (priv->from_server_channel);
1887     g_free (priv->authentication_user);
1888     g_hash_table_unref (priv->hints);
1889
1890     G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
1891 }
1892
1893 static void
1894 lightdm_greeter_class_init (LightDMGreeterClass *klass)
1895 {
1896     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1897
1898     g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
1899
1900     object_class->set_property = lightdm_greeter_set_property;
1901     object_class->get_property = lightdm_greeter_get_property;
1902     object_class->finalize = lightdm_greeter_finalize;
1903
1904     g_object_class_install_property (object_class,
1905                                      PROP_DEFAULT_SESSION_HINT,
1906                                      g_param_spec_string ("default-session-hint",
1907                                                           "default-session-hint",
1908                                                           "Default session hint",
1909                                                           NULL,
1910                                                           G_PARAM_READABLE));
1911
1912     g_object_class_install_property (object_class,
1913                                      PROP_HIDE_USERS_HINT,
1914                                      g_param_spec_boolean ("hide-users-hint",
1915                                                            "hide-users-hint",
1916                                                            "Hide users hint",
1917                                                            FALSE,
1918                                                            G_PARAM_READABLE));
1919
1920     g_object_class_install_property (object_class,
1921                                      PROP_SHOW_MANUAL_LOGIN_HINT,
1922                                      g_param_spec_boolean ("show-manual-login-hint",
1923                                                            "show-manual-login-hint",
1924                                                            "Show manual login hint",
1925                                                            FALSE,
1926                                                            G_PARAM_READABLE));
1927
1928     g_object_class_install_property (object_class,
1929                                      PROP_SHOW_REMOTE_LOGIN_HINT,
1930                                      g_param_spec_boolean ("show-remote-login-hint",
1931                                                            "show-remote-login-hint",
1932                                                            "Show remote login hint",
1933                                                            FALSE,
1934                                                            G_PARAM_READABLE));
1935
1936     g_object_class_install_property (object_class,
1937                                      PROP_LOCK_HINT,
1938                                      g_param_spec_boolean ("lock-hint",
1939                                                            "lock-hint",
1940                                                            "Lock hint",
1941                                                            FALSE,
1942                                                            G_PARAM_READABLE));
1943
1944     g_object_class_install_property (object_class,
1945                                      PROP_HAS_GUEST_ACCOUNT_HINT,
1946                                      g_param_spec_boolean ("has-guest-account-hint",
1947                                                            "has-guest-account-hint",
1948                                                            "Has guest account hint",
1949                                                            FALSE,
1950                                                            G_PARAM_READABLE));
1951
1952     g_object_class_install_property (object_class,
1953                                      PROP_SELECT_USER_HINT,
1954                                      g_param_spec_string ("select-user-hint",
1955                                                           "select-user-hint",
1956                                                           "Select user hint",
1957                                                           NULL,
1958                                                           G_PARAM_READABLE));
1959
1960     g_object_class_install_property (object_class,
1961                                      PROP_SELECT_GUEST_HINT,
1962                                      g_param_spec_boolean ("select-guest-hint",
1963                                                            "select-guest-hint",
1964                                                            "Select guest account hint",
1965                                                            FALSE,
1966                                                            G_PARAM_READABLE));
1967
1968     g_object_class_install_property (object_class,
1969                                      PROP_AUTOLOGIN_USER_HINT,
1970                                      g_param_spec_string ("autologin-user-hint",
1971                                                           "autologin-user-hint",
1972                                                           "Autologin user hint",
1973                                                           NULL,
1974                                                           G_PARAM_READABLE));
1975
1976     g_object_class_install_property (object_class,
1977                                      PROP_AUTOLOGIN_GUEST_HINT,
1978                                      g_param_spec_boolean ("autologin-guest-hint",
1979                                                            "autologin-guest-hint",
1980                                                            "Autologin guest account hint",
1981                                                            FALSE,
1982                                                            G_PARAM_READABLE));
1983
1984     g_object_class_install_property (object_class,
1985                                      PROP_AUTOLOGIN_TIMEOUT_HINT,
1986                                      g_param_spec_int ("autologin-timeout-hint",
1987                                                        "autologin-timeout-hint",
1988                                                        "Autologin timeout hint",
1989                                                        0, G_MAXINT, 0,
1990                                                        G_PARAM_READABLE));
1991
1992     g_object_class_install_property (object_class,
1993                                      PROP_AUTHENTICATION_USER,
1994                                      g_param_spec_string ("authentication-user",
1995                                                           "authentication-user",
1996                                                           "The user being authenticated",
1997                                                           NULL,
1998                                                           G_PARAM_READABLE));
1999     g_object_class_install_property (object_class,
2000                                      PROP_IN_AUTHENTICATION,
2001                                      g_param_spec_boolean ("in-authentication",
2002                                                            "in-authentication",
2003                                                            "TRUE if a user is being authenticated",
2004                                                            FALSE,
2005                                                            G_PARAM_READABLE));
2006     g_object_class_install_property (object_class,
2007                                      PROP_IS_AUTHENTICATED,
2008                                      g_param_spec_boolean ("is-authenticated",
2009                                                            "is-authenticated",
2010                                                            "TRUE if the selected user is authenticated",
2011                                                            FALSE,
2012                                                            G_PARAM_READABLE));
2013
2014     /**
2015      * LightDMGreeter::show-prompt:
2016      * @greeter: A #LightDMGreeter
2017      * @text: Prompt text
2018      * @type: Prompt type
2019      *
2020      * The ::show-prompt signal gets emitted when the greeter should show a
2021      * prompt to the user.  The given text should be displayed and an input
2022      * field for the user to provide a response.
2023      *
2024      * Call lightdm_greeter_respond() with the resultant input or
2025      * lightdm_greeter_cancel_authentication() to abort the authentication.
2026      **/
2027     signals[SHOW_PROMPT] =
2028         g_signal_new (LIGHTDM_GREETER_SIGNAL_SHOW_PROMPT,
2029                       G_TYPE_FROM_CLASS (klass),
2030                       G_SIGNAL_RUN_LAST,
2031                       G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
2032                       NULL, NULL,
2033                       NULL,
2034                       G_TYPE_NONE, 2, G_TYPE_STRING, lightdm_prompt_type_get_type ());
2035
2036     /**
2037      * LightDMGreeter::show-message:
2038      * @greeter: A #LightDMGreeter
2039      * @text: Message text
2040      * @type: Message type
2041      *
2042      * The ::show-message signal gets emitted when the greeter
2043      * should show a message to the user.
2044      **/
2045     signals[SHOW_MESSAGE] =
2046         g_signal_new (LIGHTDM_GREETER_SIGNAL_SHOW_MESSAGE,
2047                       G_TYPE_FROM_CLASS (klass),
2048                       G_SIGNAL_RUN_LAST,
2049                       G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
2050                       NULL, NULL,
2051                       NULL,
2052                       G_TYPE_NONE, 2, G_TYPE_STRING, lightdm_message_type_get_type ());
2053
2054     /**
2055      * LightDMGreeter::authentication-complete:
2056      * @greeter: A #LightDMGreeter
2057      *
2058      * The ::authentication-complete signal gets emitted when the greeter
2059      * has completed authentication.
2060      *
2061      * Call lightdm_greeter_get_is_authenticated() to check if the authentication
2062      * was successful.
2063      **/
2064     signals[AUTHENTICATION_COMPLETE] =
2065         g_signal_new (LIGHTDM_GREETER_SIGNAL_AUTHENTICATION_COMPLETE,
2066                       G_TYPE_FROM_CLASS (klass),
2067                       G_SIGNAL_RUN_LAST,
2068                       G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
2069                       NULL, NULL,
2070                       NULL,
2071                       G_TYPE_NONE, 0);
2072
2073     /**
2074      * LightDMGreeter::autologin-timer-expired:
2075      * @greeter: A #LightDMGreeter
2076      *
2077      * The ::timed-login signal gets emitted when the automatic login timer has expired.
2078      * The application should then call lightdm_greeter_login().
2079      **/
2080     signals[AUTOLOGIN_TIMER_EXPIRED] =
2081         g_signal_new (LIGHTDM_GREETER_SIGNAL_AUTOLOGIN_TIMER_EXPIRED,
2082                       G_TYPE_FROM_CLASS (klass),
2083                       G_SIGNAL_RUN_LAST,
2084                       G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),
2085                       NULL, NULL,
2086                       NULL,
2087                       G_TYPE_NONE, 0);
2088
2089     /**
2090      * LightDMGreeter::idle:
2091      * @greeter: A #LightDMGreeter
2092      *
2093      * The ::idle signal gets emitted when the user has logged in and the
2094      * greeter is no longer needed.
2095      *
2096      * This signal only matters if the greeter has marked itself as
2097      * resettable using lightdm_greeter_set_resettable().
2098      **/
2099     signals[IDLE] =
2100         g_signal_new (LIGHTDM_GREETER_SIGNAL_IDLE,
2101                       G_TYPE_FROM_CLASS (klass),
2102                       G_SIGNAL_RUN_LAST,
2103                       G_STRUCT_OFFSET (LightDMGreeterClass, idle),
2104                       NULL, NULL,
2105                       NULL,
2106                       G_TYPE_NONE, 0);
2107
2108     /**
2109      * LightDMGreeter::reset:
2110      * @greeter: A #LightDMGreeter
2111      *
2112      * The ::reset signal gets emitted when the user is returning to a greeter
2113      * that was previously marked idle.
2114      *
2115      * This signal only matters if the greeter has marked itself as
2116      * resettable using lightdm_greeter_set_resettable().
2117      **/
2118     signals[RESET] =
2119         g_signal_new (LIGHTDM_GREETER_SIGNAL_RESET,
2120                       G_TYPE_FROM_CLASS (klass),
2121                       G_SIGNAL_RUN_LAST,
2122                       G_STRUCT_OFFSET (LightDMGreeterClass, reset),
2123                       NULL, NULL,
2124                       NULL,
2125                       G_TYPE_NONE, 0);
2126 }
2127
2128 static void
2129 request_init (Request *request)
2130 {
2131 }
2132
2133 static void
2134 request_finalize (GObject *object)
2135 {
2136     Request *request = REQUEST (object);
2137
2138     g_clear_object (&request->greeter);
2139     g_clear_object (&request->cancellable);
2140     g_free (request->dir);
2141
2142     G_OBJECT_CLASS (request_parent_class)->finalize (object);
2143 }
2144
2145 static void
2146 request_class_init (RequestClass *klass)
2147 {
2148     GObjectClass *object_class = G_OBJECT_CLASS (klass);
2149     object_class->finalize = request_finalize;
2150 }
2151
2152 static gpointer
2153 request_get_user_data (GAsyncResult *result)
2154 {
2155     return REQUEST (result)->user_data;
2156 }
2157
2158 static GObject *
2159 request_get_source_object (GAsyncResult *result)
2160 {
2161     return g_object_ref (REQUEST (result)->greeter);
2162 }
2163
2164 static void
2165 request_iface_init (GAsyncResultIface *iface)
2166 {
2167     iface->get_user_data = request_get_user_data;
2168     iface->get_source_object = request_get_source_object;
2169 }