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