]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/greeter.c
Add test to check in-session greeter doesn't open a new session when unlocking active...
[sojka/lightdm.git] / src / greeter.c
1 /*
2  * Copyright (C) 2010-2016 Canonical Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify it under
5  * the terms of the GNU General Public License as published by the Free Software
6  * Foundation, either version 3 of the License, or (at your option) any later
7  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8  * license.
9  */
10
11 #include <config.h>
12
13 #include <stdlib.h>
14 #include <string.h>
15 #include <gcrypt.h>
16
17 #include "greeter.h"
18 #include "configuration.h"
19 #include "shared-data-manager.h"
20
21 enum {
22     PROP_0,
23     PROP_ACTIVE_USERNAME,
24 };
25
26 enum {
27     CONNECTED,
28     DISCONNECTED,  
29     CREATE_SESSION,
30     START_SESSION,
31     LAST_SIGNAL
32 };
33 static guint signals[LAST_SIGNAL] = { 0 };
34
35 struct GreeterPrivate
36 {
37     /* PAM service to authenticate with */
38     gchar *pam_service;
39     gchar *autologin_pam_service;
40
41     /* Buffer for data read from greeter */
42     guint8 *read_buffer;
43     gsize n_read;
44     gboolean use_secure_memory;
45
46     /* Hints for the greeter */
47     GHashTable *hints;
48
49     /* Default session to use */
50     gchar *default_session;
51
52     /* Sequence number of current PAM session */
53     guint32 authentication_sequence_number;
54
55     /* Remote session name */
56     gchar *remote_session;
57
58     /* Currently selected user */
59     gchar *active_username;
60
61     /* PAM session being constructed by the greeter */
62     Session *authentication_session;
63
64     /* TRUE if a the greeter can handle a reset; else we will just kill it instead */
65     gboolean resettable;
66
67     /* TRUE if a user has been authenticated and the session requested to start */
68     gboolean start_session;
69
70     /* TRUE if can log into guest accounts */
71     gboolean allow_guest;
72
73     /* TRUE if logging into guest session */
74     gboolean guest_account_authenticated;
75
76     /* Communication channels to communicate with */
77     int to_greeter_input;
78     int from_greeter_output;
79     GIOChannel *to_greeter_channel;
80     GIOChannel *from_greeter_channel;
81     guint from_greeter_watch;
82 };
83
84 G_DEFINE_TYPE (Greeter, greeter, G_TYPE_OBJECT);
85
86 /* Messages from the greeter to the server */
87 typedef enum
88 {
89     GREETER_MESSAGE_CONNECT = 0,
90     GREETER_MESSAGE_AUTHENTICATE,
91     GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
92     GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
93     GREETER_MESSAGE_START_SESSION,
94     GREETER_MESSAGE_CANCEL_AUTHENTICATION,
95     GREETER_MESSAGE_SET_LANGUAGE,
96     GREETER_MESSAGE_AUTHENTICATE_REMOTE,
97     GREETER_MESSAGE_ENSURE_SHARED_DIR,
98 } GreeterMessage;
99
100 /* Messages from the server to the greeter */
101 typedef enum
102 {
103     SERVER_MESSAGE_CONNECTED = 0,
104     SERVER_MESSAGE_PROMPT_AUTHENTICATION,
105     SERVER_MESSAGE_END_AUTHENTICATION,
106     SERVER_MESSAGE_SESSION_RESULT,
107     SERVER_MESSAGE_SHARED_DIR_RESULT,
108     SERVER_MESSAGE_IDLE,
109     SERVER_MESSAGE_RESET,
110 } ServerMessage;
111
112 static gboolean read_cb (GIOChannel *source, GIOCondition condition, gpointer data);
113
114 Greeter *
115 greeter_new (void)
116 {
117     return g_object_new (GREETER_TYPE, NULL);
118 }
119
120 void
121 greeter_set_file_descriptors (Greeter *greeter, int to_greeter_fd, int from_greeter_fd)
122 {
123     GError *error = NULL;
124
125     g_return_if_fail (greeter != NULL);
126     g_return_if_fail (greeter->priv->to_greeter_input < 0);
127     g_return_if_fail (greeter->priv->from_greeter_output < 0);
128
129     greeter->priv->to_greeter_input = to_greeter_fd;  
130     greeter->priv->to_greeter_channel = g_io_channel_unix_new (greeter->priv->to_greeter_input);
131     g_io_channel_set_encoding (greeter->priv->to_greeter_channel, NULL, &error);
132     if (error)
133         g_warning ("Failed to set encoding on to greeter channel to binary: %s\n", error->message);
134     g_clear_error (&error);
135     greeter->priv->from_greeter_output = from_greeter_fd;
136     greeter->priv->from_greeter_channel = g_io_channel_unix_new (greeter->priv->from_greeter_output);
137     g_io_channel_set_encoding (greeter->priv->from_greeter_channel, NULL, &error);
138     if (error)
139         g_warning ("Failed to set encoding on from greeter channel to binary: %s\n", error->message);
140     g_clear_error (&error);
141     g_io_channel_set_buffered (greeter->priv->from_greeter_channel, FALSE);
142     greeter->priv->from_greeter_watch = g_io_add_watch (greeter->priv->from_greeter_channel, G_IO_IN | G_IO_HUP, read_cb, greeter);
143 }
144
145 void
146 greeter_stop (Greeter *greeter)
147 {
148     /* Stop any events occurring after we've stopped */
149     if (greeter->priv->authentication_session)
150         g_signal_handlers_disconnect_matched (greeter->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, greeter);
151 }
152
153 void
154 greeter_set_pam_services (Greeter *greeter, const gchar *pam_service, const gchar *autologin_pam_service)
155 {
156     g_return_if_fail (greeter != NULL);
157     g_free (greeter->priv->pam_service);
158     greeter->priv->pam_service = g_strdup (pam_service);
159     g_free (greeter->priv->autologin_pam_service);
160     greeter->priv->autologin_pam_service = g_strdup (autologin_pam_service);
161 }
162
163 void
164 greeter_set_allow_guest (Greeter *greeter, gboolean allow_guest)
165 {
166     g_return_if_fail (greeter != NULL);  
167     greeter->priv->allow_guest = allow_guest;
168 }
169
170 void
171 greeter_clear_hints (Greeter *greeter)
172 {
173     g_return_if_fail (greeter != NULL);
174     g_hash_table_remove_all (greeter->priv->hints);
175 }
176
177 void
178 greeter_set_hint (Greeter *greeter, const gchar *name, const gchar *value)
179 {
180     g_return_if_fail (greeter != NULL);
181     g_hash_table_insert (greeter->priv->hints, g_strdup (name), g_strdup (value));
182 }
183
184 static void *
185 secure_malloc (Greeter *greeter, size_t n)
186 {
187     if (greeter->priv->use_secure_memory)
188         return gcry_malloc_secure (n);
189     else
190         return g_malloc (n);
191 }
192
193 static void *
194 secure_realloc (Greeter *greeter, void *ptr, size_t n)
195 {
196     if (greeter->priv->use_secure_memory)
197         return gcry_realloc (ptr, n);
198     else
199         return g_realloc (ptr, n);
200 }
201
202 static void
203 secure_free (Greeter *greeter, void *ptr)
204 {
205     if (greeter->priv->use_secure_memory)
206         return gcry_free (ptr);
207     else
208         return g_free (ptr);
209 }
210
211 static guint32
212 int_length (void)
213 {
214     return 4;
215 }
216
217 #define HEADER_SIZE (sizeof (guint32) * 2)
218 #define MAX_MESSAGE_LENGTH 1024
219
220 static void
221 write_message (Greeter *greeter, guint8 *message, gsize message_length)
222 {
223     gchar *data;
224     gsize data_length;
225     GError *error = NULL;
226
227     data = (gchar *) message;
228     data_length = message_length;
229     while (data_length > 0)
230     {
231         GIOStatus status;
232         gsize n_written;
233
234         status = g_io_channel_write_chars (greeter->priv->to_greeter_channel, data, data_length, &n_written, &error);
235         if (error)
236             g_warning ("Error writing to greeter: %s", error->message);
237         g_clear_error (&error);
238         if (status != G_IO_STATUS_NORMAL)
239             return;
240         data_length -= n_written;
241         data += n_written;
242     }
243
244     g_io_channel_flush (greeter->priv->to_greeter_channel, &error);
245     if (error)
246         g_warning ("Failed to flush data to greeter: %s", error->message);
247     g_clear_error (&error);
248 }
249
250 static void
251 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
252 {
253     if (*offset + 4 >= buffer_length)
254         return;
255     buffer[*offset] = value >> 24;
256     buffer[*offset+1] = (value >> 16) & 0xFF;
257     buffer[*offset+2] = (value >> 8) & 0xFF;
258     buffer[*offset+3] = value & 0xFF;
259     *offset += 4;
260 }
261
262 static void
263 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
264 {
265     gint length;
266
267     if (value)
268         length = strlen (value);
269     else
270         length = 0;
271     write_int (buffer, buffer_length, length, offset);
272     if (*offset + length >= buffer_length)
273         return;
274     if (length > 0)
275     {
276         memcpy (buffer + *offset, value, length);
277         *offset += length;
278     }
279 }
280
281 static void
282 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
283 {
284     write_int (buffer, buffer_length, id, offset);
285     write_int (buffer, buffer_length, length, offset);
286 }
287
288 static guint32
289 string_length (const gchar *value)
290 {
291     if (value == NULL)
292         return int_length ();
293     else
294         return int_length () + strlen (value);
295 }
296
297 static void
298 handle_connect (Greeter *greeter, const gchar *version, gboolean resettable)
299 {
300     guint8 message[MAX_MESSAGE_LENGTH];
301     gsize offset = 0;
302     guint32 length;
303     GHashTableIter iter;
304     gpointer key, value;
305
306     g_debug ("Greeter connected version=%s resettable=%s", version, resettable ? "true" : "false");
307
308     greeter->priv->resettable = resettable;
309
310     length = string_length (VERSION);
311     g_hash_table_iter_init (&iter, greeter->priv->hints);
312     while (g_hash_table_iter_next (&iter, &key, &value))
313         length += string_length (key) + string_length (value);
314
315     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_CONNECTED, length, &offset);
316     write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
317     g_hash_table_iter_init (&iter, greeter->priv->hints);
318     while (g_hash_table_iter_next (&iter, &key, &value))
319     {
320         write_string (message, MAX_MESSAGE_LENGTH, key, &offset);
321         write_string (message, MAX_MESSAGE_LENGTH, value, &offset);
322     }
323     write_message (greeter, message, offset);
324
325     g_signal_emit (greeter, signals[CONNECTED], 0);
326 }
327
328 static void
329 pam_messages_cb (Session *session, Greeter *greeter)
330 {
331     int i;
332     guint32 size;
333     guint8 message[MAX_MESSAGE_LENGTH];
334     const struct pam_message *messages;
335     int messages_length;
336     gsize offset = 0;
337     int n_prompts = 0;
338
339     messages = session_get_messages (session);
340     messages_length = session_get_messages_length (session);
341
342     /* Respond to d-bus query with messages */
343     g_debug ("Prompt greeter with %d message(s)", messages_length);
344     size = int_length () + string_length (session_get_username (session)) + int_length ();
345     for (i = 0; i < messages_length; i++)
346         size += int_length () + string_length (messages[i].msg);
347
348     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_PROMPT_AUTHENTICATION, size, &offset);
349     write_int (message, MAX_MESSAGE_LENGTH, greeter->priv->authentication_sequence_number, &offset);
350     write_string (message, MAX_MESSAGE_LENGTH, session_get_username (session), &offset);
351     write_int (message, MAX_MESSAGE_LENGTH, messages_length, &offset);
352     for (i = 0; i < messages_length; i++)
353     {
354         write_int (message, MAX_MESSAGE_LENGTH, messages[i].msg_style, &offset);
355         write_string (message, MAX_MESSAGE_LENGTH, messages[i].msg, &offset);
356
357         if (messages[i].msg_style == PAM_PROMPT_ECHO_OFF || messages[i].msg_style == PAM_PROMPT_ECHO_ON)
358             n_prompts++;
359     }
360     write_message (greeter, message, offset);
361
362     /* Continue immediately if nothing to respond with */
363     // FIXME: Should probably give the greeter a chance to ack the message
364     if (n_prompts == 0)
365     {
366         struct pam_response *response;
367         response = calloc (messages_length, sizeof (struct pam_response));
368         session_respond (greeter->priv->authentication_session, response);
369         free (response);
370     }
371 }
372
373 static void
374 send_end_authentication (Greeter *greeter, guint32 sequence_number, const gchar *username, int result)
375 {
376     guint8 message[MAX_MESSAGE_LENGTH];
377     gsize offset = 0;
378
379     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_END_AUTHENTICATION, int_length () + string_length (username) + int_length (), &offset);
380     write_int (message, MAX_MESSAGE_LENGTH, sequence_number, &offset);
381     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
382     write_int (message, MAX_MESSAGE_LENGTH, result, &offset);
383     write_message (greeter, message, offset);
384 }
385
386 void
387 greeter_idle (Greeter *greeter)
388 {
389     guint8 message[MAX_MESSAGE_LENGTH];
390     gsize offset = 0;
391
392     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_IDLE, 0, &offset);
393     write_message (greeter, message, offset);
394 }
395
396 void
397 greeter_reset (Greeter *greeter)
398 {
399     guint8 message[MAX_MESSAGE_LENGTH];
400     gsize offset = 0;
401     guint32 length = 0;
402     GHashTableIter iter;
403     gpointer key, value;
404
405     g_return_if_fail (greeter != NULL);
406
407     g_hash_table_iter_init (&iter, greeter->priv->hints);
408     while (g_hash_table_iter_next (&iter, &key, &value))
409         length += string_length (key) + string_length (value);
410
411     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_RESET, length, &offset);
412     g_hash_table_iter_init (&iter, greeter->priv->hints);
413     while (g_hash_table_iter_next (&iter, &key, &value))
414     {
415         write_string (message, MAX_MESSAGE_LENGTH, key, &offset);
416         write_string (message, MAX_MESSAGE_LENGTH, value, &offset);
417     }
418     write_message (greeter, message, offset);
419 }
420
421 static void
422 authentication_complete_cb (Session *session, Greeter *greeter)
423 {
424     int result;
425
426     g_debug ("Authenticate result for user %s: %s", session_get_username (session), session_get_authentication_result_string (session));
427
428     result = session_get_authentication_result (session);
429     if (session_get_is_authenticated (session))
430     {
431         if (session_get_user (session))
432             g_debug ("User %s authorized", session_get_username (session));
433         else
434         {
435             g_debug ("User %s authorized, but no account of that name exists", session_get_username (session));
436             result = PAM_USER_UNKNOWN;
437         }
438     }
439
440     send_end_authentication (greeter, greeter->priv->authentication_sequence_number, session_get_username (session), result);
441 }
442
443 static void
444 reset_session (Greeter *greeter)
445 {
446     g_free (greeter->priv->remote_session);
447     greeter->priv->remote_session = NULL;
448     if (greeter->priv->authentication_session)
449     {
450         g_signal_handlers_disconnect_matched (greeter->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, greeter);
451         session_stop (greeter->priv->authentication_session);
452         g_clear_object (&greeter->priv->authentication_session);
453     }
454
455     greeter->priv->guest_account_authenticated = FALSE;
456 }
457
458 static void
459 handle_login (Greeter *greeter, guint32 sequence_number, const gchar *username)
460 {
461     const gchar *autologin_username, *service;
462     gboolean is_interactive;
463
464     if (username[0] == '\0')
465     {
466         g_debug ("Greeter start authentication");
467         username = NULL;
468     }
469     else
470         g_debug ("Greeter start authentication for %s", username);
471
472     reset_session (greeter);
473
474     if (greeter->priv->active_username)
475         g_free (greeter->priv->active_username);
476     greeter->priv->active_username = g_strdup (username);
477     g_object_notify (G_OBJECT (greeter), GREETER_PROPERTY_ACTIVE_USERNAME);
478
479     greeter->priv->authentication_sequence_number = sequence_number;
480     g_signal_emit (greeter, signals[CREATE_SESSION], 0, &greeter->priv->authentication_session);
481     if (!greeter->priv->authentication_session)
482     {
483         send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN);
484         return;
485     }
486
487     g_signal_connect (G_OBJECT (greeter->priv->authentication_session), SESSION_SIGNAL_GOT_MESSAGES, G_CALLBACK (pam_messages_cb), greeter);
488     g_signal_connect (G_OBJECT (greeter->priv->authentication_session), SESSION_SIGNAL_AUTHENTICATION_COMPLETE, G_CALLBACK (authentication_complete_cb), greeter);
489
490     /* Use non-interactive service for autologin user */
491     autologin_username = g_hash_table_lookup (greeter->priv->hints, "autologin-user");
492     if (autologin_username != NULL && g_strcmp0 (username, autologin_username) == 0)
493     {
494         service = greeter->priv->autologin_pam_service;
495         is_interactive = FALSE;
496     }
497     else
498     {
499         service = greeter->priv->pam_service;
500         is_interactive = TRUE;
501     }
502
503     /* Run the session process */
504     session_set_pam_service (greeter->priv->authentication_session, service);
505     session_set_username (greeter->priv->authentication_session, username);
506     session_set_do_authenticate (greeter->priv->authentication_session, TRUE);
507     session_set_is_interactive (greeter->priv->authentication_session, is_interactive);
508     session_start (greeter->priv->authentication_session);
509 }
510
511 static void
512 handle_login_as_guest (Greeter *greeter, guint32 sequence_number)
513 {
514     g_debug ("Greeter start authentication for guest account");
515
516     reset_session (greeter);
517
518     if (!greeter->priv->allow_guest)
519     {
520         g_debug ("Guest account is disabled");
521         send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN);
522         return;
523     }
524
525     greeter->priv->guest_account_authenticated = TRUE;
526     send_end_authentication (greeter, sequence_number, "", PAM_SUCCESS);
527 }
528
529 static gchar *
530 get_remote_session_service (const gchar *session_name)
531 {
532     GKeyFile *session_desktop_file;
533     gboolean result;
534     const gchar *c;
535     gchar *remote_sessions_dir, *filename, *path, *service = NULL;
536     GError *error = NULL;
537
538     /* Validate session name doesn't contain directory separators */
539     for (c = session_name; *c; c++)
540     {
541         if (*c == '/')
542             return NULL;
543     }
544
545     /* Load the session file */
546     session_desktop_file = g_key_file_new ();
547     filename = g_strdup_printf ("%s.desktop", session_name);
548     remote_sessions_dir = config_get_string (config_get_instance (), "LightDM", "remote-sessions-directory");
549     path = g_build_filename (remote_sessions_dir, filename, NULL);
550     g_free (remote_sessions_dir);
551     g_free (filename);
552     result = g_key_file_load_from_file (session_desktop_file, path, G_KEY_FILE_NONE, &error);
553     if (error)
554         g_debug ("Failed to load session file %s: %s", path, error->message);
555     g_free (path);
556     g_clear_error (&error);
557     if (result)
558         service = g_key_file_get_string (session_desktop_file, G_KEY_FILE_DESKTOP_GROUP, "X-LightDM-PAM-Service", NULL);
559     g_key_file_free (session_desktop_file);
560
561     return service;
562 }
563
564 static void
565 handle_login_remote (Greeter *greeter, const gchar *session_name, const gchar *username, guint32 sequence_number)
566 {
567     gchar *service;
568
569     if (username[0] == '\0')
570     {
571         g_debug ("Greeter start authentication for remote session %s", session_name);
572         username = NULL;
573     }
574     else
575         g_debug ("Greeter start authentication for remote session %s as user %s", session_name, username);
576
577     reset_session (greeter);
578
579     service = get_remote_session_service (session_name);
580     if (!service)
581     {
582         send_end_authentication (greeter, sequence_number, "", PAM_SYSTEM_ERR);
583         return;
584     }
585
586     greeter->priv->authentication_sequence_number = sequence_number;
587     greeter->priv->remote_session = g_strdup (session_name);
588     g_signal_emit (greeter, signals[CREATE_SESSION], 0, &greeter->priv->authentication_session);
589     if (greeter->priv->authentication_session)
590     {
591         g_signal_connect (G_OBJECT (greeter->priv->authentication_session), SESSION_SIGNAL_GOT_MESSAGES, G_CALLBACK (pam_messages_cb), greeter);
592         g_signal_connect (G_OBJECT (greeter->priv->authentication_session), SESSION_SIGNAL_AUTHENTICATION_COMPLETE, G_CALLBACK (authentication_complete_cb), greeter);
593
594         /* Run the session process */
595         session_set_pam_service (greeter->priv->authentication_session, service);
596         session_set_username (greeter->priv->authentication_session, username);
597         session_set_do_authenticate (greeter->priv->authentication_session, TRUE);
598         session_set_is_interactive (greeter->priv->authentication_session, TRUE);
599         session_set_is_guest (greeter->priv->authentication_session, TRUE);
600         session_start (greeter->priv->authentication_session);
601     }
602
603     g_free (service);
604
605     if (!greeter->priv->authentication_session)
606     {
607         send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN);
608         return;
609     }
610 }
611
612 static void
613 handle_continue_authentication (Greeter *greeter, gchar **secrets)
614 {
615     int messages_length;
616     const struct pam_message *messages;
617     struct pam_response *response;
618     int i, j, n_prompts = 0;
619
620     /* Not in authentication */
621     if (greeter->priv->authentication_session == NULL)
622         return;
623
624     messages_length = session_get_messages_length (greeter->priv->authentication_session);
625     messages = session_get_messages (greeter->priv->authentication_session);
626
627     /* Check correct number of responses */
628     for (i = 0; i < messages_length; i++)
629     {
630         int msg_style = messages[i].msg_style;
631         if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
632             n_prompts++;
633     }
634     if (g_strv_length (secrets) != n_prompts)
635     {
636         session_respond_error (greeter->priv->authentication_session, PAM_CONV_ERR);
637         return;
638     }
639
640     g_debug ("Continue authentication");
641
642     /* Build response */
643     response = calloc (messages_length, sizeof (struct pam_response));
644     for (i = 0, j = 0; i < messages_length; i++)
645     {
646         int msg_style = messages[i].msg_style;
647         if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
648         {
649             size_t secret_length = strlen (secrets[j]) + 1;
650             response[i].resp = secure_malloc (greeter, secret_length);
651             memcpy (response[i].resp, secrets[j], secret_length); // FIXME: Need to convert from UTF-8
652             j++;
653         }
654     }
655
656     session_respond (greeter->priv->authentication_session, response);
657
658     for (i = 0; i < messages_length; i++)
659         secure_free (greeter, response[i].resp);
660     free (response);
661 }
662
663 static void
664 handle_cancel_authentication (Greeter *greeter)
665 {
666     /* Not in authentication */
667     if (greeter->priv->authentication_session == NULL)
668         return;
669
670     g_debug ("Cancel authentication");
671     reset_session (greeter);
672 }
673
674 static void
675 handle_start_session (Greeter *greeter, const gchar *session)
676 {
677     gboolean result;
678     guint8 message[MAX_MESSAGE_LENGTH];
679     gsize offset = 0;
680     SessionType session_type = SESSION_TYPE_LOCAL;
681
682     if (strcmp (session, "") == 0)
683         session = NULL;
684
685     /* Use session type chosen in remote session */
686     if (greeter->priv->remote_session)
687     {
688         session_type = SESSION_TYPE_REMOTE;
689         session = greeter->priv->remote_session;
690     }
691
692     if (greeter->priv->guest_account_authenticated || session_get_is_authenticated (greeter->priv->authentication_session))
693     {
694         if (session)
695             g_debug ("Greeter requests session %s", session);
696         else
697             g_debug ("Greeter requests default session");
698         greeter->priv->start_session = TRUE;
699         g_signal_emit (greeter, signals[START_SESSION], 0, session_type, session, &result);
700     }
701     else
702     {
703         g_debug ("Ignoring start session request, user is not authorized");
704         result = FALSE;
705     }
706
707     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_SESSION_RESULT, int_length (), &offset);
708     write_int (message, MAX_MESSAGE_LENGTH, result ? 0 : 1, &offset);
709     write_message (greeter, message, offset);
710 }
711
712 static void
713 handle_set_language (Greeter *greeter, const gchar *language)
714 {
715     User *user;
716
717     if (!greeter->priv->guest_account_authenticated && !session_get_is_authenticated (greeter->priv->authentication_session))
718     {
719         g_debug ("Ignoring set language request, user is not authorized");
720         return;
721     }
722
723     // FIXME: Could use this
724     if (greeter->priv->guest_account_authenticated)
725     {
726         g_debug ("Ignoring set language request for guest user");
727         return;
728     }
729
730     g_debug ("Greeter sets language %s", language);
731     user = session_get_user (greeter->priv->authentication_session);
732     user_set_language (user, language);
733 }
734
735 static void
736 handle_ensure_shared_dir (Greeter *greeter, const gchar *username)
737 {
738     gchar *dir;
739     guint8 message[MAX_MESSAGE_LENGTH];
740     gsize offset = 0;
741
742     g_debug ("Greeter requests data directory for user %s", username);
743
744     dir = shared_data_manager_ensure_user_dir (shared_data_manager_get_instance (), username);
745
746     write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_SHARED_DIR_RESULT, string_length (dir), &offset);
747     write_string (message, MAX_MESSAGE_LENGTH, dir, &offset);
748     write_message (greeter, message, offset);
749
750     g_free (dir);
751 }
752
753 static guint32
754 read_int (Greeter *greeter, gsize *offset)
755 {
756     guint32 value;
757     guint8 *buffer;
758     if (greeter->priv->n_read - *offset < sizeof (guint32))
759     {
760         g_warning ("Not enough space for int, need %zu, got %zu", sizeof (guint32), greeter->priv->n_read - *offset);
761         return 0;
762     }
763     buffer = greeter->priv->read_buffer + *offset;
764     value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
765     *offset += int_length ();
766     return value;
767 }
768
769 static int
770 get_message_length (Greeter *greeter)
771 {
772     gsize offset;
773     int payload_length;
774
775     offset = int_length ();
776     payload_length = read_int (greeter, &offset);
777
778     if (HEADER_SIZE + payload_length < HEADER_SIZE)
779     {
780         g_warning ("Payload length of %u octets too long", payload_length);
781         return HEADER_SIZE;
782     }
783
784     return HEADER_SIZE + payload_length;
785 }
786
787 static gchar *
788 read_string_full (Greeter *greeter, gsize *offset, void* (*alloc_fn)(size_t n))
789 {
790     guint32 length;
791     gchar *value;
792
793     length = read_int (greeter, offset);
794     if (greeter->priv->n_read - *offset < length)
795     {
796         g_warning ("Not enough space for string, need %u, got %zu", length, greeter->priv->n_read - *offset);
797         return g_strdup ("");
798     }
799
800     value = (*alloc_fn) (sizeof (gchar) * (length + 1));
801     memcpy (value, greeter->priv->read_buffer + *offset, length);
802     value[length] = '\0';
803     *offset += length;
804
805     return value;
806 }
807
808 static gchar *
809 read_string (Greeter *greeter, gsize *offset)
810 {
811     return read_string_full (greeter, offset, g_malloc);
812 }
813
814 static gchar *
815 read_secret (Greeter *greeter, gsize *offset)
816 {
817     if (greeter->priv->use_secure_memory)
818         return read_string_full (greeter, offset, gcry_malloc_secure);
819     else
820         return read_string_full (greeter, offset, g_malloc);
821 }
822
823 static gboolean
824 read_cb (GIOChannel *source, GIOCondition condition, gpointer data)
825 {
826     Greeter *greeter = data;
827     gsize n_to_read, n_read, offset;
828     GIOStatus status;
829     int id, length, i;
830     guint32 sequence_number, n_secrets, max_secrets;
831     gchar *version, *username, *session_name, *language;
832     gchar **secrets;
833     gboolean resettable = FALSE;
834     GError *error = NULL;
835
836     if (condition == G_IO_HUP)
837     {
838         g_debug ("Greeter closed communication channel");
839         greeter->priv->from_greeter_watch = 0;
840         g_signal_emit (greeter, signals[DISCONNECTED], 0);
841         return FALSE;
842     }
843
844     n_to_read = HEADER_SIZE;
845     if (greeter->priv->n_read >= HEADER_SIZE)
846     {
847         n_to_read = get_message_length (greeter);
848         if (n_to_read <= HEADER_SIZE)
849         {
850             greeter->priv->from_greeter_watch = 0;
851             return FALSE;
852         }
853     }
854
855     status = g_io_channel_read_chars (greeter->priv->from_greeter_channel,
856                                       (gchar *) greeter->priv->read_buffer + greeter->priv->n_read,
857                                       n_to_read - greeter->priv->n_read,
858                                       &n_read,
859                                       &error);
860     if (error)
861         g_warning ("Error reading from greeter: %s", error->message);
862     g_clear_error (&error);
863     if (status == G_IO_STATUS_EOF)
864     {
865         g_debug ("Greeter closed communication channel");
866         greeter->priv->from_greeter_watch = 0;
867         g_signal_emit (greeter, signals[DISCONNECTED], 0);
868         return FALSE;
869     }
870     else if (status != G_IO_STATUS_NORMAL)
871         return TRUE;
872
873     greeter->priv->n_read += n_read;
874     if (greeter->priv->n_read != n_to_read)
875         return TRUE;
876
877     /* If have header, rerun for content */
878     if (greeter->priv->n_read == HEADER_SIZE)
879     {
880         n_to_read = get_message_length (greeter);
881         if (n_to_read > HEADER_SIZE)
882         {
883             greeter->priv->read_buffer = secure_realloc (greeter, greeter->priv->read_buffer, n_to_read);
884             read_cb (source, condition, greeter);
885             return TRUE;
886         }
887     }
888
889     offset = 0;
890     id = read_int (greeter, &offset);
891     length = HEADER_SIZE + read_int (greeter, &offset);
892     switch (id)
893     {
894     case GREETER_MESSAGE_CONNECT:
895         version = read_string (greeter, &offset);
896         if (offset < length)
897             resettable = read_int (greeter, &offset) != 0;
898         handle_connect (greeter, version, resettable);
899         g_free (version);
900         break;
901     case GREETER_MESSAGE_AUTHENTICATE:
902         sequence_number = read_int (greeter, &offset);
903         username = read_string (greeter, &offset);
904         handle_login (greeter, sequence_number, username);
905         g_free (username);
906         break;
907     case GREETER_MESSAGE_AUTHENTICATE_AS_GUEST:
908         sequence_number = read_int (greeter, &offset);
909         handle_login_as_guest (greeter, sequence_number);
910         break;
911     case GREETER_MESSAGE_AUTHENTICATE_REMOTE:
912         sequence_number = read_int (greeter, &offset);
913         session_name = read_string (greeter, &offset);
914         username = read_string (greeter, &offset);
915         handle_login_remote (greeter, session_name, username, sequence_number);
916         break;
917     case GREETER_MESSAGE_CONTINUE_AUTHENTICATION:
918         n_secrets = read_int (greeter, &offset);
919         max_secrets = (G_MAXUINT32 - 1) / sizeof (gchar *);
920         if (n_secrets > max_secrets)
921         {
922             g_warning ("Array length of %u elements too long", n_secrets);
923             greeter->priv->from_greeter_watch = 0;
924             return FALSE;
925         }
926         secrets = g_malloc (sizeof (gchar *) * (n_secrets + 1));
927         for (i = 0; i < n_secrets; i++)
928             secrets[i] = read_secret (greeter, &offset);
929         secrets[i] = NULL;
930         handle_continue_authentication (greeter, secrets);
931         for (i = 0; i < n_secrets; i++)
932             secure_free (greeter, secrets[i]);
933         g_free (secrets);
934         break;
935     case GREETER_MESSAGE_CANCEL_AUTHENTICATION:
936         handle_cancel_authentication (greeter);
937         break;
938     case GREETER_MESSAGE_START_SESSION:
939         session_name = read_string (greeter, &offset);
940         handle_start_session (greeter, session_name);
941         g_free (session_name);
942         break;
943     case GREETER_MESSAGE_SET_LANGUAGE:
944         language = read_string (greeter, &offset);
945         handle_set_language (greeter, language);
946         g_free (language);
947         break;
948     case GREETER_MESSAGE_ENSURE_SHARED_DIR:
949         username = read_string (greeter, &offset);
950         handle_ensure_shared_dir (greeter, username);
951         g_free (username);
952         break;
953     default:
954         g_warning ("Unknown message from greeter: %d", id);
955         break;
956     }
957
958     greeter->priv->n_read = 0;
959
960     return TRUE;
961 }
962
963 gboolean
964 greeter_get_guest_authenticated (Greeter *greeter)
965 {
966     g_return_val_if_fail (greeter != NULL, FALSE);
967     return greeter->priv->guest_account_authenticated;
968 }
969
970 Session *
971 greeter_get_authentication_session (Greeter *greeter)
972 {
973     g_return_val_if_fail (greeter != NULL, NULL);
974     return greeter->priv->authentication_session;
975 }
976
977 gboolean
978 greeter_get_resettable (Greeter *greeter)
979 {
980     g_return_val_if_fail (greeter != NULL, FALSE);
981     return greeter->priv->resettable;
982 }
983
984 gboolean
985 greeter_get_start_session (Greeter *greeter)
986 {
987     g_return_val_if_fail (greeter != NULL, FALSE);
988     return greeter->priv->start_session;
989 }
990
991 const gchar *
992 greeter_get_active_username (Greeter *greeter)
993 {
994     g_return_val_if_fail (greeter != NULL, NULL);
995     return greeter->priv->active_username;
996 }
997
998 static Session *
999 greeter_real_create_session (Greeter *greeter)
1000 {
1001     return NULL;
1002 }
1003
1004 static gboolean
1005 greeter_real_start_session (Greeter *greeter, SessionType type, const gchar *session)
1006 {
1007     return FALSE;
1008 }
1009
1010 static void
1011 greeter_init (Greeter *greeter)
1012 {
1013     greeter->priv = G_TYPE_INSTANCE_GET_PRIVATE (greeter, GREETER_TYPE, GreeterPrivate);
1014     greeter->priv->read_buffer = secure_malloc (greeter, HEADER_SIZE);
1015     greeter->priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1016     greeter->priv->use_secure_memory = config_get_boolean (config_get_instance (), "LightDM", "lock-memory");
1017     greeter->priv->to_greeter_input = -1;
1018     greeter->priv->from_greeter_output = -1;
1019 }
1020
1021 static void
1022 greeter_finalize (GObject *object)
1023 {
1024     Greeter *self = GREETER (object);
1025
1026     g_free (self->priv->pam_service);
1027     g_free (self->priv->autologin_pam_service);
1028     secure_free (self, self->priv->read_buffer);
1029     g_hash_table_unref (self->priv->hints);
1030     g_free (self->priv->remote_session);
1031     g_free (self->priv->active_username);
1032     if (self->priv->authentication_session)
1033     {
1034         g_signal_handlers_disconnect_matched (self->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
1035         g_object_unref (self->priv->authentication_session);
1036     }
1037     close (self->priv->to_greeter_input);
1038     close (self->priv->from_greeter_output);
1039     if (self->priv->to_greeter_channel)
1040         g_io_channel_unref (self->priv->to_greeter_channel);
1041     if (self->priv->from_greeter_channel)
1042         g_io_channel_unref (self->priv->from_greeter_channel);
1043     if (self->priv->from_greeter_watch)
1044         g_source_remove (self->priv->from_greeter_watch);
1045
1046     G_OBJECT_CLASS (greeter_parent_class)->finalize (object);
1047 }
1048
1049 static void
1050 greeter_set_property (GObject      *object,
1051                       guint         prop_id,
1052                       const GValue *value,
1053                       GParamSpec   *pspec)
1054 {
1055     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1056 }
1057
1058 static void
1059 greeter_get_property (GObject    *object,
1060                       guint       prop_id,
1061                       GValue     *value,
1062                       GParamSpec *pspec)
1063 {
1064     Greeter *greeter = GREETER (object);
1065
1066     switch (prop_id) {
1067     case PROP_ACTIVE_USERNAME:
1068         g_value_set_string (value, greeter_get_active_username (greeter));
1069         break;
1070     default:
1071         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1072         break;
1073     }
1074 }
1075
1076 static void
1077 greeter_class_init (GreeterClass *klass)
1078 {
1079     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1080
1081     klass->create_session = greeter_real_create_session;
1082     klass->start_session = greeter_real_start_session;
1083     object_class->finalize = greeter_finalize;
1084     object_class->get_property = greeter_get_property;
1085     object_class->set_property = greeter_set_property;
1086
1087     signals[CONNECTED] =
1088         g_signal_new (GREETER_SIGNAL_CONNECTED,
1089                       G_TYPE_FROM_CLASS (klass),
1090                       G_SIGNAL_RUN_LAST,
1091                       G_STRUCT_OFFSET (GreeterClass, connected),
1092                       NULL, NULL,
1093                       NULL,
1094                       G_TYPE_NONE, 0);
1095
1096     signals[DISCONNECTED] =
1097         g_signal_new (GREETER_SIGNAL_DISCONNECTED,
1098                       G_TYPE_FROM_CLASS (klass),
1099                       G_SIGNAL_RUN_LAST,
1100                       G_STRUCT_OFFSET (GreeterClass, disconnected),
1101                       NULL, NULL,
1102                       NULL,
1103                       G_TYPE_NONE, 0);
1104
1105     signals[CREATE_SESSION] =
1106         g_signal_new (GREETER_SIGNAL_CREATE_SESSION,
1107                       G_TYPE_FROM_CLASS (klass),
1108                       G_SIGNAL_RUN_LAST,
1109                       G_STRUCT_OFFSET (GreeterClass, create_session),
1110                       g_signal_accumulator_first_wins,
1111                       NULL,
1112                       NULL,
1113                       SESSION_TYPE, 0);
1114
1115     signals[START_SESSION] =
1116         g_signal_new (GREETER_SIGNAL_START_SESSION,
1117                       G_TYPE_FROM_CLASS (klass),
1118                       G_SIGNAL_RUN_LAST,
1119                       G_STRUCT_OFFSET (GreeterClass, start_session),
1120                       g_signal_accumulator_true_handled,
1121                       NULL,
1122                       NULL,
1123                       G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_STRING);
1124
1125     g_object_class_install_property (object_class,
1126                                      PROP_ACTIVE_USERNAME,
1127                                      g_param_spec_string (GREETER_PROPERTY_ACTIVE_USERNAME,
1128                                                           GREETER_PROPERTY_ACTIVE_USERNAME,
1129                                                           "Active username",
1130                                                           NULL,
1131                                                           G_PARAM_READABLE));
1132
1133     g_type_class_add_private (klass, sizeof (GreeterPrivate));
1134 }