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