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