]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - liblightdm-gobject/greeter.c
Fix docstring
[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
835     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
836
837     priv = GET_PRIVATE (greeter);
838
839     /* Read until we are connected */
840     send_connect (greeter, priv->resettable);
841     request = request_new (NULL, NULL, NULL);
842     priv->connect_requests = g_list_append (priv->connect_requests, g_object_ref (request));
843     do
844     {
845         guint8 *message;
846         gsize message_length;
847
848         message = recv_message (greeter, &message_length, TRUE);
849         if (!message)
850             break;
851         handle_message (greeter, message, message_length);
852         g_free (message);
853     } while (!request->complete);
854
855     g_object_unref (request);
856
857     return request->complete;
858 }
859
860 /**
861  * lightdm_greeter_connect_sync:
862  * @greeter: The greeter to connect
863  * @error: return location for a #GError, or %NULL
864  *
865  * Connects the greeter to the display manager.  Will block until connected.
866  *
867  * Return value: #TRUE if successfully connected
868  *
869  * Deprecated: 1.11.1: Use lightdm_greeter_connect_to_daemon_sync() instead
870  **/
871 gboolean
872 lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
873 {
874     return lightdm_greeter_connect_to_daemon_sync (greeter, error);
875 }
876
877 /**
878  * lightdm_greeter_get_hint:
879  * @greeter: A #LightDMGreeter
880  * @name: The hint name to query.
881  *
882  * Get a hint.
883  *
884  * Return value: (nullable): The value for this hint or #NULL if not set.
885  **/
886 const gchar *
887 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
888 {
889     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
890     return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
891 }
892
893 /**
894  * lightdm_greeter_get_default_session_hint:
895  * @greeter: A #LightDMGreeter
896  *
897  * Get the default session to use.
898  *
899  * Return value: The session name
900  **/
901 const gchar *
902 lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
903 {
904     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
905     return lightdm_greeter_get_hint (greeter, "default-session");
906 }
907
908 /**
909  * lightdm_greeter_get_hide_users_hint:
910  * @greeter: A #LightDMGreeter
911  *
912  * Check if user accounts should be shown.  If this is TRUE then the list of
913  * accounts should be taken from #LightDMUserList and displayed in the greeter
914  * for the user to choose from.  Note that this list can be empty and it is
915  * recommended you show a method for the user to enter a username manually.
916  *
917  * If this option is shown the greeter should only allow these users to be
918  * chosen for login unless the manual login hint is set.
919  *
920  * Return value: #TRUE if the available users should not be shown.
921  */
922 gboolean
923 lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
924 {
925     const gchar *value;
926
927     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
928     value = lightdm_greeter_get_hint (greeter, "hide-users");
929
930     return g_strcmp0 (value, "true") == 0;
931 }
932
933 /**
934  * lightdm_greeter_get_show_manual_login_hint:
935  * @greeter: A #LightDMGreeter
936  *
937  * Check if a manual login option should be shown.  If set the GUI
938  * should provide a way for a username to be entered manually.
939  * Without this hint a greeter which is showing a user list can
940  * limit logins to only those users.
941  *
942  * Return value: #TRUE if a manual login option should be shown.
943  */
944 gboolean
945 lightdm_greeter_get_show_manual_login_hint (LightDMGreeter *greeter)
946 {
947     const gchar *value;
948
949     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
950     value = lightdm_greeter_get_hint (greeter, "show-manual-login");
951
952     return g_strcmp0 (value, "true") == 0;
953 }
954
955 /**
956  * lightdm_greeter_get_show_remote_login_hint:
957  * @greeter: A #LightDMGreeter
958  *
959  * Check if a remote login option should be shown.  If set the GUI
960  * should provide a way for a user to log into a remote desktop server.
961  *
962  * Return value: #TRUE if a remote login option should be shown.
963  */
964 gboolean
965 lightdm_greeter_get_show_remote_login_hint (LightDMGreeter *greeter)
966 {
967     const gchar *value;
968
969     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
970     value = lightdm_greeter_get_hint (greeter, "show-remote-login");
971
972     return g_strcmp0 (value, "true") == 0;
973 }
974
975 /**
976  * lightdm_greeter_get_lock_hint:
977  * @greeter: A #LightDMGreeter
978  *
979  * Check if the greeter is acting as a lock screen.
980  *
981  * Return value: #TRUE if the greeter was triggered by locking the seat.
982  */
983 gboolean
984 lightdm_greeter_get_lock_hint (LightDMGreeter *greeter)
985 {
986     const gchar *value;
987
988     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
989     value = lightdm_greeter_get_hint (greeter, "lock-screen");
990
991     return g_strcmp0 (value, "true") == 0;
992 }
993
994 /**
995  * lightdm_greeter_get_has_guest_account_hint:
996  * @greeter: A #LightDMGreeter
997  *
998  * Check if guest sessions are supported.
999  *
1000  * Return value: #TRUE if guest sessions are supported.
1001  */
1002 gboolean
1003 lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
1004 {
1005     const gchar *value;
1006
1007     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1008     value = lightdm_greeter_get_hint (greeter, "has-guest-account");
1009
1010     return g_strcmp0 (value, "true") == 0;
1011 }
1012
1013 /**
1014  * lightdm_greeter_get_select_user_hint:
1015  * @greeter: A #LightDMGreeter
1016  *
1017  * Get the user to select by default.
1018  *
1019  * Return value: (nullable): A username or %NULL if no particular user should be selected.
1020  */
1021 const gchar *
1022 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
1023 {
1024     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1025     return lightdm_greeter_get_hint (greeter, "select-user");
1026 }
1027
1028 /**
1029  * lightdm_greeter_get_select_guest_hint:
1030  * @greeter: A #LightDMGreeter
1031  *
1032  * Check if the guest account should be selected by default.
1033  *
1034  * Return value: #TRUE if the guest account should be selected by default.
1035  */
1036 gboolean
1037 lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
1038 {
1039     const gchar *value;
1040
1041     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1042     value = lightdm_greeter_get_hint (greeter, "select-guest");
1043
1044     return g_strcmp0 (value, "true") == 0;
1045 }
1046
1047 /**
1048  * lightdm_greeter_get_autologin_user_hint:
1049  * @greeter: A #LightDMGreeter
1050  *
1051  * Get the user account to automatically log into when the timer expires.
1052  *
1053  * Return value: (nullable): The user account to automatically log into or %NULL if none configured.
1054  */
1055 const gchar *
1056 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
1057 {
1058     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1059     return lightdm_greeter_get_hint (greeter, "autologin-user");
1060 }
1061
1062 /**
1063  * lightdm_greeter_get_autologin_guest_hint:
1064  * @greeter: A #LightDMGreeter
1065  *
1066  * Check if the guest account should be automatically logged into when the timer expires.
1067  *
1068  * Return value: #TRUE if the guest account should be automatically logged into.
1069  */
1070 gboolean
1071 lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
1072 {
1073     const gchar *value;
1074
1075     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1076     value = lightdm_greeter_get_hint (greeter, "autologin-guest");
1077
1078     return g_strcmp0 (value, "true") == 0;
1079 }
1080
1081 /**
1082  * lightdm_greeter_get_autologin_timeout_hint:
1083  * @greeter: A #LightDMGreeter
1084  *
1085  * Get the number of seconds to wait before automaitcally logging in.
1086  *
1087  * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
1088  */
1089 gint
1090 lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
1091 {
1092     const gchar *value;
1093     gint timeout = 0;
1094
1095     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1096     value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
1097     if (value)
1098         timeout = atoi (value);
1099     if (timeout < 0)
1100         timeout = 0;
1101
1102     return timeout;
1103 }
1104
1105 /**
1106  * lightdm_greeter_cancel_autologin:
1107  * @greeter: A #LightDMGreeter
1108  *
1109  * Cancel the automatic login.
1110  */
1111 void
1112 lightdm_greeter_cancel_autologin (LightDMGreeter *greeter)
1113 {
1114     LightDMGreeterPrivate *priv;
1115
1116     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1117
1118     priv = GET_PRIVATE (greeter);
1119
1120     if (priv->autologin_timeout)
1121        g_source_remove (priv->autologin_timeout);
1122     priv->autologin_timeout = 0;
1123 }
1124
1125 /**
1126  * lightdm_greeter_authenticate:
1127  * @greeter: A #LightDMGreeter
1128  * @username: (allow-none): A username or #NULL to prompt for a username.
1129  *
1130  * Starts the authentication procedure for a user.
1131  **/
1132 void
1133 lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username)
1134 {
1135     LightDMGreeterPrivate *priv;
1136     guint8 message[MAX_MESSAGE_LENGTH];
1137     gsize offset = 0;
1138
1139     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1140
1141     priv = GET_PRIVATE (greeter);
1142
1143     g_return_if_fail (priv->connected);
1144
1145     priv->cancelling_authentication = FALSE;
1146     priv->authenticate_sequence_number++;
1147     priv->in_authentication = TRUE;
1148     priv->is_authenticated = FALSE;
1149     if (username != priv->authentication_user)
1150     {
1151         g_free (priv->authentication_user);
1152         priv->authentication_user = g_strdup (username);
1153     }
1154
1155     g_debug ("Starting authentication for user %s...", username);
1156     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset);
1157     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
1158     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
1159     send_message (greeter, message, offset);
1160 }
1161
1162 /**
1163  * lightdm_greeter_authenticate_as_guest:
1164  * @greeter: A #LightDMGreeter
1165  *
1166  * Starts the authentication procedure for the guest user.
1167  **/
1168 void
1169 lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter)
1170 {
1171     LightDMGreeterPrivate *priv;
1172     guint8 message[MAX_MESSAGE_LENGTH];
1173     gsize offset = 0;
1174
1175     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1176
1177     priv = GET_PRIVATE (greeter);
1178
1179     g_return_if_fail (priv->connected);
1180
1181     priv->cancelling_authentication = FALSE;
1182     priv->authenticate_sequence_number++;
1183     priv->in_authentication = TRUE;
1184     priv->is_authenticated = FALSE;
1185     g_free (priv->authentication_user);
1186     priv->authentication_user = NULL;
1187
1188     g_debug ("Starting authentication for guest account...");
1189     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset);
1190     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
1191     send_message (greeter, message, offset);
1192 }
1193
1194 /**
1195  * lightdm_greeter_authenticate_autologin:
1196  * @greeter: A #LightDMGreeter
1197  *
1198  * Starts the authentication procedure for the automatic login user.
1199  **/
1200 void
1201 lightdm_greeter_authenticate_autologin (LightDMGreeter *greeter)
1202 {
1203     const gchar *user;
1204
1205     user = lightdm_greeter_get_autologin_user_hint (greeter);
1206     if (lightdm_greeter_get_autologin_guest_hint (greeter))
1207         lightdm_greeter_authenticate_as_guest (greeter);
1208     else if (user)
1209         lightdm_greeter_authenticate (greeter, user);
1210 }
1211
1212 /**
1213  * lightdm_greeter_authenticate_remote:
1214  * @greeter: A #LightDMGreeter
1215  * @session: The name of a remote session
1216  * @username: (allow-none): A username of #NULL to prompt for a username.
1217  *
1218  * Start authentication for a remote session type.
1219  **/
1220 void
1221 lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *session, const gchar *username)
1222 {
1223     LightDMGreeterPrivate *priv;
1224     guint8 message[MAX_MESSAGE_LENGTH];
1225     gsize offset = 0;
1226
1227     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1228
1229     priv = GET_PRIVATE (greeter);
1230
1231     g_return_if_fail (priv->connected);
1232
1233     priv->cancelling_authentication = FALSE;
1234     priv->authenticate_sequence_number++;
1235     priv->in_authentication = TRUE;
1236     priv->is_authenticated = FALSE;
1237     g_free (priv->authentication_user);
1238     priv->authentication_user = NULL;
1239
1240     if (username)
1241         g_debug ("Starting authentication for remote session %s as user %s...", session, username);
1242     else
1243         g_debug ("Starting authentication for remote session %s...", session);
1244     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_REMOTE, int_length () + string_length (session) + string_length (username), &offset);
1245     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
1246     write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
1247     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
1248     send_message (greeter, message, offset);
1249 }
1250
1251 /**
1252  * lightdm_greeter_respond:
1253  * @greeter: A #LightDMGreeter
1254  * @response: Response to a prompt
1255  *
1256  * Provide response to a prompt.  May be one in a series.
1257  **/
1258 void
1259 lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response)
1260 {
1261     LightDMGreeterPrivate *priv;
1262     guint8 message[MAX_MESSAGE_LENGTH];
1263     gsize offset = 0;
1264
1265     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1266     g_return_if_fail (response != NULL);
1267
1268     priv = GET_PRIVATE (greeter);
1269
1270     g_return_if_fail (priv->connected);
1271     g_return_if_fail (priv->n_responses_waiting > 0);
1272
1273     priv->n_responses_waiting--;
1274     priv->responses_received = g_list_append (priv->responses_received, g_strdup (response));
1275
1276     if (priv->n_responses_waiting == 0)
1277     {
1278         guint32 msg_length;
1279         GList *iter;
1280
1281         g_debug ("Providing response to display manager");
1282
1283         msg_length = int_length ();
1284         for (iter = priv->responses_received; iter; iter = iter->next)
1285             msg_length += string_length ((gchar *)iter->data);
1286
1287         write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, msg_length, &offset);
1288         write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset);
1289         for (iter = priv->responses_received; iter; iter = iter->next)
1290             write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset);
1291         send_message (greeter, message, offset);
1292
1293         g_list_free_full (priv->responses_received, g_free);
1294         priv->responses_received = NULL;
1295     }
1296 }
1297
1298 /**
1299  * lightdm_greeter_cancel_authentication:
1300  * @greeter: A #LightDMGreeter
1301  *
1302  * Cancel the current user authentication.
1303  **/
1304 void
1305 lightdm_greeter_cancel_authentication (LightDMGreeter *greeter)
1306 {
1307     LightDMGreeterPrivate *priv;
1308     guint8 message[MAX_MESSAGE_LENGTH];
1309     gsize offset = 0;
1310
1311     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1312
1313     priv = GET_PRIVATE (greeter);
1314
1315     g_return_if_fail (priv->connected);
1316
1317     priv->cancelling_authentication = TRUE;
1318     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
1319     send_message (greeter, message, offset);
1320 }
1321
1322 /**
1323  * lightdm_greeter_get_in_authentication:
1324  * @greeter: A #LightDMGreeter
1325  *
1326  * Checks if the greeter is in the process of authenticating.
1327  *
1328  * Return value: #TRUE if the greeter is authenticating a user.
1329  **/
1330 gboolean
1331 lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
1332 {
1333     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1334     return GET_PRIVATE (greeter)->in_authentication;
1335 }
1336
1337 /**
1338  * lightdm_greeter_get_is_authenticated:
1339  * @greeter: A #LightDMGreeter
1340  *
1341  * Checks if the greeter has successfully authenticated.
1342  *
1343  * Return value: #TRUE if the greeter is authenticated for login.
1344  **/
1345 gboolean
1346 lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
1347 {
1348     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1349     return GET_PRIVATE (greeter)->is_authenticated;
1350 }
1351
1352 /**
1353  * lightdm_greeter_get_authentication_user:
1354  * @greeter: A #LightDMGreeter
1355  *
1356  * Get the user that is being authenticated.
1357  *
1358  * Return value: (nullable): The username of the authentication user being authenticated or #NULL if no authentication in progress.
1359  */
1360 const gchar *
1361 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
1362 {
1363     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1364     return GET_PRIVATE (greeter)->authentication_user;
1365 }
1366
1367 /**
1368  * lightdm_greeter_set_language:
1369  * @greeter: A #LightDMGreeter
1370  * @language: The language to use for this user in the form of a locale specification (e.g. "de_DE.UTF-8").
1371  *
1372  * Set the language for the currently authenticated user.
1373  **/
1374 void
1375 lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language)
1376 {
1377     LightDMGreeterPrivate *priv;
1378     guint8 message[MAX_MESSAGE_LENGTH];
1379     gsize offset = 0;
1380
1381     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1382
1383     priv = GET_PRIVATE (greeter);
1384
1385     g_return_if_fail (priv->connected);
1386
1387     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset);
1388     write_string (message, MAX_MESSAGE_LENGTH, language, &offset);
1389     send_message (greeter, message, offset);
1390 }
1391
1392 /**
1393  * lightdm_greeter_start_session:
1394  * @greeter: A #LightDMGreeter
1395  * @session: (allow-none): The session to log into or #NULL to use the default.
1396  * @cancellable: (allow-none): A #GCancellable or %NULL.
1397  * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
1398  * @user_data: (allow-none): data to pass to the @callback or %NULL.
1399  *
1400  * Asynchronously start a session for the authenticated user.
1401  *
1402  * 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.
1403  *
1404  * See lightdm_greeter_start_session_sync() for the synchronous version.
1405  **/
1406 void
1407 lightdm_greeter_start_session (LightDMGreeter *greeter, const gchar *session, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
1408 {
1409     LightDMGreeterPrivate *priv;
1410     Request *request;
1411
1412     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1413
1414     priv = GET_PRIVATE (greeter);
1415
1416     send_start_session (greeter, session);
1417     request = request_new (cancellable, callback, user_data);
1418     priv->start_session_requests = g_list_append (priv->start_session_requests, request);
1419 }
1420
1421 /**
1422  * lightdm_greeter_start_session_finish:
1423  * @greeter: A #LightDMGreeter
1424  * @result: A #GAsyncResult.
1425  * @error: return location for a #GError, or %NULL
1426  *
1427  * Start a session for the authenticated user.
1428  *
1429  * Return value: TRUE if the session was started.
1430  **/
1431 gboolean
1432 lightdm_greeter_start_session_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error)
1433 {
1434     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1435     return REQUEST (result)->return_code == 0;
1436 }
1437
1438 /**
1439  * lightdm_greeter_start_session_sync:
1440  * @greeter: A #LightDMGreeter
1441  * @session: (allow-none): The session to log into or #NULL to use the default.
1442  * @error: return location for a #GError, or %NULL
1443  *
1444  * Start a session for the authenticated user.
1445  *
1446  * Return value: TRUE if the session was started.
1447  **/
1448 gboolean
1449 lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
1450 {
1451     LightDMGreeterPrivate *priv;
1452     Request *request;
1453     guint32 return_code;
1454
1455     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1456
1457     priv = GET_PRIVATE (greeter);
1458
1459     g_return_val_if_fail (priv->connected, FALSE);
1460     g_return_val_if_fail (priv->is_authenticated, FALSE);
1461
1462     /* Read until the session is started */
1463     send_start_session (greeter, session);
1464     request = request_new (NULL, NULL, NULL);
1465     priv->start_session_requests = g_list_append (priv->start_session_requests, g_object_ref (request));
1466     do
1467     {
1468         guint8 *message;
1469         gsize message_length;
1470
1471         message = recv_message (greeter, &message_length, TRUE);
1472         if (!message)
1473             break;
1474         handle_message (greeter, message, message_length);
1475         g_free (message);
1476     } while (!request->complete);
1477
1478     return_code = request->return_code;
1479     g_object_unref (request);
1480
1481     return return_code == 0;
1482 }
1483
1484 /**
1485  * lightdm_greeter_ensure_shared_data_dir:
1486  * @greeter: A #LightDMGreeter
1487  * @username: A username
1488  * @cancellable: (allow-none): A #GCancellable or %NULL.
1489  * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
1490  * @user_data: (allow-none): data to pass to the @callback or %NULL.
1491  *
1492  * Ensure that a shared data dir for the given user is available.  Both the
1493  * greeter user and @username will have write access to that folder.  The
1494  * intention is that larger pieces of shared data would be stored there (files
1495  * that the greeter creates but wants to give to a user -- like camera
1496  * photos -- or files that the user creates but wants the greeter to
1497  * see -- like contact avatars).
1498  *
1499  * LightDM will automatically create these if the user actually logs in, so
1500  * greeters only need to call this method if they want to store something in
1501  * the directory themselves.
1502  **/
1503 void
1504 lightdm_greeter_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
1505 {
1506     LightDMGreeterPrivate *priv;
1507     Request *request;
1508
1509     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1510
1511     priv = GET_PRIVATE (greeter);
1512
1513     send_ensure_shared_data_dir (greeter, username);
1514     request = request_new (cancellable, callback, user_data);
1515     priv->ensure_shared_data_dir_requests = g_list_append (priv->ensure_shared_data_dir_requests, request);
1516 }
1517
1518 /**
1519  * lightdm_greeter_ensure_shared_data_dir_finish:
1520  * @result: A #GAsyncResult.
1521  * @greeter: A #LightDMGreeter
1522  *
1523  * Function to call from lightdm_greeter_ensure_shared_data_dir callback.
1524  *
1525  * Return value: The path to the shared directory, free with g_free.
1526  **/
1527 gchar *
1528 lightdm_greeter_ensure_shared_data_dir_finish (LightDMGreeter *greeter, GAsyncResult *result)
1529 {
1530     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1531     return g_strdup (REQUEST (result)->dir);
1532 }
1533
1534 /**
1535  * lightdm_greeter_ensure_shared_data_dir_sync:
1536  * @greeter: A #LightDMGreeter
1537  * @username: A username
1538  *
1539  * Ensure that a shared data dir for the given user is available.  Both the
1540  * greeter user and @username will have write access to that folder.  The
1541  * intention is that larger pieces of shared data would be stored there (files
1542  * that the greeter creates but wants to give to a user -- like camera
1543  * photos -- or files that the user creates but wants the greeter to
1544  * see -- like contact avatars).
1545  *
1546  * LightDM will automatically create these if the user actually logs in, so
1547  * greeters only need to call this method if they want to store something in
1548  * the directory themselves.
1549  *
1550  * Return value: The path to the shared directory, free with g_free.
1551  **/
1552 gchar *
1553 lightdm_greeter_ensure_shared_data_dir_sync (LightDMGreeter *greeter, const gchar *username)
1554 {
1555     LightDMGreeterPrivate *priv;
1556     Request *request;
1557     gchar *data_dir;
1558
1559     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1560
1561     priv = GET_PRIVATE (greeter);
1562
1563     g_return_val_if_fail (priv->connected, NULL);
1564
1565     /* Read until a response */
1566     send_ensure_shared_data_dir (greeter, username);
1567     request = request_new (NULL, NULL, NULL);
1568     priv->ensure_shared_data_dir_requests = g_list_append (priv->ensure_shared_data_dir_requests, g_object_ref (request));
1569     do
1570     {
1571         guint8 *message;
1572         gsize message_length;
1573
1574         message = recv_message (greeter, &message_length, TRUE);
1575         if (!message)
1576             break;
1577         handle_message (greeter, message, message_length);
1578         g_free (message);
1579     } while (!request->complete);
1580
1581     data_dir = g_strdup (request->dir);
1582     g_object_unref (request);
1583
1584     return data_dir;
1585 }
1586
1587 static void
1588 lightdm_greeter_init (LightDMGreeter *greeter)
1589 {
1590     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1591     const gchar *fd;
1592
1593     priv->read_buffer = g_malloc (HEADER_SIZE);
1594     priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1595
1596     fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
1597     if (fd)
1598     {
1599         GError *error = NULL;
1600
1601         priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
1602         g_io_channel_set_encoding (priv->to_server_channel, NULL, &error);
1603         if (error)
1604             g_warning ("Failed to set encoding on to server channel to binary: %s\n", error->message);
1605         g_clear_error (&error);
1606     }
1607     else
1608         g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
1609
1610     fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
1611     if (fd)
1612     {
1613         GError *error = NULL;
1614
1615         priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
1616         g_io_channel_set_encoding (priv->from_server_channel, NULL, &error);
1617         if (error)
1618             g_warning ("Failed to set encoding on from server channel to binary: %s\n", error->message);
1619         g_clear_error (&error);
1620         g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
1621     }
1622     else
1623         g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
1624 }
1625
1626 static void
1627 lightdm_greeter_set_property (GObject      *object,
1628                           guint         prop_id,
1629                           const GValue *value,
1630                           GParamSpec   *pspec)
1631 {
1632     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1633 }
1634
1635 static void
1636 lightdm_greeter_get_property (GObject    *object,
1637                           guint       prop_id,
1638                           GValue     *value,
1639                           GParamSpec *pspec)
1640 {
1641     LightDMGreeter *self;
1642
1643     self = LIGHTDM_GREETER (object);
1644
1645     switch (prop_id) {
1646     case PROP_DEFAULT_SESSION_HINT:
1647         g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
1648         break;
1649     case PROP_HIDE_USERS_HINT:
1650         g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
1651         break;
1652     case PROP_SHOW_MANUAL_LOGIN_HINT:
1653         g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
1654         break;
1655     case PROP_SHOW_REMOTE_LOGIN_HINT:
1656         g_value_set_boolean (value, lightdm_greeter_get_show_remote_login_hint (self));
1657         break;
1658     case PROP_LOCK_HINT:
1659         g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
1660         break;
1661     case PROP_HAS_GUEST_ACCOUNT_HINT:
1662         g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
1663         break;
1664     case PROP_SELECT_USER_HINT:
1665         g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
1666         break;
1667     case PROP_SELECT_GUEST_HINT:
1668         g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
1669         break;
1670     case PROP_AUTOLOGIN_USER_HINT:
1671         g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
1672         break;
1673     case PROP_AUTOLOGIN_GUEST_HINT:
1674         g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
1675         break;
1676     case PROP_AUTOLOGIN_TIMEOUT_HINT:
1677         g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
1678         break;
1679     case PROP_AUTHENTICATION_USER:
1680         g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
1681         break;
1682     case PROP_IN_AUTHENTICATION:
1683         g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
1684         break;
1685     case PROP_IS_AUTHENTICATED:
1686         g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
1687         break;
1688     default:
1689         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1690         break;
1691     }
1692 }
1693
1694 static void
1695 lightdm_greeter_finalize (GObject *object)
1696 {
1697     LightDMGreeter *self = LIGHTDM_GREETER (object);
1698     LightDMGreeterPrivate *priv = GET_PRIVATE (self);
1699
1700     if (priv->to_server_channel)
1701         g_io_channel_unref (priv->to_server_channel);
1702     if (priv->from_server_channel)
1703         g_io_channel_unref (priv->from_server_channel);
1704     g_free (priv->authentication_user);
1705     g_hash_table_unref (priv->hints);
1706
1707     G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
1708 }
1709
1710 static void
1711 lightdm_greeter_class_init (LightDMGreeterClass *klass)
1712 {
1713     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1714
1715     g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
1716
1717     object_class->set_property = lightdm_greeter_set_property;
1718     object_class->get_property = lightdm_greeter_get_property;
1719     object_class->finalize = lightdm_greeter_finalize;
1720
1721     g_object_class_install_property (object_class,
1722                                      PROP_DEFAULT_SESSION_HINT,
1723                                      g_param_spec_string ("default-session-hint",
1724                                                           "default-session-hint",
1725                                                           "Default session hint",
1726                                                           NULL,
1727                                                           G_PARAM_READABLE));
1728
1729     g_object_class_install_property (object_class,
1730                                      PROP_HIDE_USERS_HINT,
1731                                      g_param_spec_boolean ("hide-users-hint",
1732                                                            "hide-users-hint",
1733                                                            "Hide users hint",
1734                                                            FALSE,
1735                                                            G_PARAM_READABLE));
1736
1737     g_object_class_install_property (object_class,
1738                                      PROP_SHOW_MANUAL_LOGIN_HINT,
1739                                      g_param_spec_boolean ("show-manual-login-hint",
1740                                                            "show-manual-login-hint",
1741                                                            "Show manual login hint",
1742                                                            FALSE,
1743                                                            G_PARAM_READABLE));
1744
1745     g_object_class_install_property (object_class,
1746                                      PROP_SHOW_REMOTE_LOGIN_HINT,
1747                                      g_param_spec_boolean ("show-remote-login-hint",
1748                                                            "show-remote-login-hint",
1749                                                            "Show remote login hint",
1750                                                            FALSE,
1751                                                            G_PARAM_READABLE));
1752
1753     g_object_class_install_property (object_class,
1754                                      PROP_LOCK_HINT,
1755                                      g_param_spec_boolean ("lock-hint",
1756                                                            "lock-hint",
1757                                                            "Lock hint",
1758                                                            FALSE,
1759                                                            G_PARAM_READABLE));
1760
1761     g_object_class_install_property (object_class,
1762                                      PROP_HAS_GUEST_ACCOUNT_HINT,
1763                                      g_param_spec_boolean ("has-guest-account-hint",
1764                                                            "has-guest-account-hint",
1765                                                            "Has guest account hint",
1766                                                            FALSE,
1767                                                            G_PARAM_READABLE));
1768
1769     g_object_class_install_property (object_class,
1770                                      PROP_SELECT_USER_HINT,
1771                                      g_param_spec_string ("select-user-hint",
1772                                                           "select-user-hint",
1773                                                           "Select user hint",
1774                                                           NULL,
1775                                                           G_PARAM_READABLE));
1776
1777     g_object_class_install_property (object_class,
1778                                      PROP_SELECT_GUEST_HINT,
1779                                      g_param_spec_boolean ("select-guest-hint",
1780                                                            "select-guest-hint",
1781                                                            "Select guest account hint",
1782                                                            FALSE,
1783                                                            G_PARAM_READABLE));
1784
1785     g_object_class_install_property (object_class,
1786                                      PROP_AUTOLOGIN_USER_HINT,
1787                                      g_param_spec_string ("autologin-user-hint",
1788                                                           "autologin-user-hint",
1789                                                           "Autologin user hint",
1790                                                           NULL,
1791                                                           G_PARAM_READABLE));
1792
1793     g_object_class_install_property (object_class,
1794                                      PROP_AUTOLOGIN_GUEST_HINT,
1795                                      g_param_spec_boolean ("autologin-guest-hint",
1796                                                            "autologin-guest-hint",
1797                                                            "Autologin guest account hint",
1798                                                            FALSE,
1799                                                            G_PARAM_READABLE));
1800
1801     g_object_class_install_property (object_class,
1802                                      PROP_AUTOLOGIN_TIMEOUT_HINT,
1803                                      g_param_spec_int ("autologin-timeout-hint",
1804                                                        "autologin-timeout-hint",
1805                                                        "Autologin timeout hint",
1806                                                        0, G_MAXINT, 0,
1807                                                        G_PARAM_READABLE));
1808
1809     g_object_class_install_property (object_class,
1810                                      PROP_AUTHENTICATION_USER,
1811                                      g_param_spec_string ("authentication-user",
1812                                                           "authentication-user",
1813                                                           "The user being authenticated",
1814                                                           NULL,
1815                                                           G_PARAM_READABLE));
1816     g_object_class_install_property (object_class,
1817                                      PROP_IN_AUTHENTICATION,
1818                                      g_param_spec_boolean ("in-authentication",
1819                                                            "in-authentication",
1820                                                            "TRUE if a user is being authenticated",
1821                                                            FALSE,
1822                                                            G_PARAM_READABLE));
1823     g_object_class_install_property (object_class,
1824                                      PROP_IS_AUTHENTICATED,
1825                                      g_param_spec_boolean ("is-authenticated",
1826                                                            "is-authenticated",
1827                                                            "TRUE if the selected user is authenticated",
1828                                                            FALSE,
1829                                                            G_PARAM_READABLE));
1830
1831     /**
1832      * LightDMGreeter::show-prompt:
1833      * @greeter: A #LightDMGreeter
1834      * @text: Prompt text
1835      * @type: Prompt type
1836      *
1837      * The ::show-prompt signal gets emitted when the greeter should show a
1838      * prompt to the user.  The given text should be displayed and an input
1839      * field for the user to provide a response.
1840      *
1841      * Call lightdm_greeter_respond() with the resultant input or
1842      * lightdm_greeter_cancel_authentication() to abort the authentication.
1843      **/
1844     signals[SHOW_PROMPT] =
1845         g_signal_new (LIGHTDM_GREETER_SIGNAL_SHOW_PROMPT,
1846                       G_TYPE_FROM_CLASS (klass),
1847                       G_SIGNAL_RUN_LAST,
1848                       G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
1849                       NULL, NULL,
1850                       NULL,
1851                       G_TYPE_NONE, 2, G_TYPE_STRING, lightdm_prompt_type_get_type ());
1852
1853     /**
1854      * LightDMGreeter::show-message:
1855      * @greeter: A #LightDMGreeter
1856      * @text: Message text
1857      * @type: Message type
1858      *
1859      * The ::show-message signal gets emitted when the greeter
1860      * should show a message to the user.
1861      **/
1862     signals[SHOW_MESSAGE] =
1863         g_signal_new (LIGHTDM_GREETER_SIGNAL_SHOW_MESSAGE,
1864                       G_TYPE_FROM_CLASS (klass),
1865                       G_SIGNAL_RUN_LAST,
1866                       G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
1867                       NULL, NULL,
1868                       NULL,
1869                       G_TYPE_NONE, 2, G_TYPE_STRING, lightdm_message_type_get_type ());
1870
1871     /**
1872      * LightDMGreeter::authentication-complete:
1873      * @greeter: A #LightDMGreeter
1874      *
1875      * The ::authentication-complete signal gets emitted when the greeter
1876      * has completed authentication.
1877      *
1878      * Call lightdm_greeter_get_is_authenticated() to check if the authentication
1879      * was successful.
1880      **/
1881     signals[AUTHENTICATION_COMPLETE] =
1882         g_signal_new (LIGHTDM_GREETER_SIGNAL_AUTHENTICATION_COMPLETE,
1883                       G_TYPE_FROM_CLASS (klass),
1884                       G_SIGNAL_RUN_LAST,
1885                       G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
1886                       NULL, NULL,
1887                       NULL,
1888                       G_TYPE_NONE, 0);
1889
1890     /**
1891      * LightDMGreeter::autologin-timer-expired:
1892      * @greeter: A #LightDMGreeter
1893      *
1894      * The ::timed-login signal gets emitted when the automatic login timer has expired.
1895      * The application should then call lightdm_greeter_login().
1896      **/
1897     signals[AUTOLOGIN_TIMER_EXPIRED] =
1898         g_signal_new (LIGHTDM_GREETER_SIGNAL_AUTOLOGIN_TIMER_EXPIRED,
1899                       G_TYPE_FROM_CLASS (klass),
1900                       G_SIGNAL_RUN_LAST,
1901                       G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),
1902                       NULL, NULL,
1903                       NULL,
1904                       G_TYPE_NONE, 0);
1905
1906     /**
1907      * LightDMGreeter::idle:
1908      * @greeter: A #LightDMGreeter
1909      *
1910      * The ::idle signal gets emitted when the user has logged in and the
1911      * greeter is no longer needed.
1912      *
1913      * This signal only matters if the greeter has marked itself as
1914      * resettable using lightdm_greeter_set_resettable().
1915      **/
1916     signals[IDLE] =
1917         g_signal_new (LIGHTDM_GREETER_SIGNAL_IDLE,
1918                       G_TYPE_FROM_CLASS (klass),
1919                       G_SIGNAL_RUN_LAST,
1920                       G_STRUCT_OFFSET (LightDMGreeterClass, idle),
1921                       NULL, NULL,
1922                       NULL,
1923                       G_TYPE_NONE, 0);
1924
1925     /**
1926      * LightDMGreeter::reset:
1927      * @greeter: A #LightDMGreeter
1928      *
1929      * The ::reset signal gets emitted when the user is returning to a greeter
1930      * that was previously marked idle.
1931      *
1932      * This signal only matters if the greeter has marked itself as
1933      * resettable using lightdm_greeter_set_resettable().
1934      **/
1935     signals[RESET] =
1936         g_signal_new (LIGHTDM_GREETER_SIGNAL_RESET,
1937                       G_TYPE_FROM_CLASS (klass),
1938                       G_SIGNAL_RUN_LAST,
1939                       G_STRUCT_OFFSET (LightDMGreeterClass, reset),
1940                       NULL, NULL,
1941                       NULL,
1942                       G_TYPE_NONE, 0);
1943 }
1944
1945 static void
1946 request_init (Request *request)
1947 {
1948 }
1949
1950 static void
1951 request_finalize (GObject *object)
1952 {
1953     Request *request = REQUEST (object);
1954
1955     g_free (request->dir);
1956     g_clear_object (&request->cancellable);
1957
1958     G_OBJECT_CLASS (request_parent_class)->finalize (object);
1959 }
1960
1961 static void
1962 request_class_init (RequestClass *klass)
1963 {
1964     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1965     object_class->finalize = request_finalize;
1966 }
1967
1968 static gpointer
1969 request_get_user_data (GAsyncResult *result)
1970 {
1971     return REQUEST (result)->user_data;
1972 }
1973
1974 static GObject *
1975 request_get_source_object (GAsyncResult *res)
1976 {
1977     return NULL;
1978 }
1979
1980 static void
1981 request_iface_init (GAsyncResultIface *iface)
1982 {
1983     iface->get_user_data = request_get_user_data;
1984     iface->get_source_object = request_get_source_object;
1985 }