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