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