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