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