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