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