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