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