]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - liblightdm-gobject/greeter.c
Really tidy up liblightdm
[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 3 of the License, or (at your option) any
8  * later version. See http://www.gnu.org/copyleft/lgpl.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 <security/pam_appl.h>
17
18 #include "lightdm/greeter.h"
19
20 enum {
21     PROP_0,
22     PROP_DEFAULT_SESSION_HINT,
23     PROP_HIDE_USERS_HINT,
24     PROP_HAS_GUEST_ACCOUNT_HINT,
25     PROP_SELECT_USER_HINT,
26     PROP_SELECT_GUEST_HINT,
27     PROP_AUTOLOGIN_USER_HINT,
28     PROP_AUTOLOGIN_GUEST_HINT,
29     PROP_AUTOLOGIN_TIMEOUT_HINT,
30     PROP_AUTHENTICATION_USER,
31     PROP_IN_AUTHENTICATION,
32     PROP_IS_AUTHENTICATED,
33 };
34
35 enum {
36     CONNECTED,
37     SHOW_PROMPT,
38     SHOW_MESSAGE,
39     AUTHENTICATION_COMPLETE,
40     SESSION_FAILED,
41     AUTOLOGIN_TIMER_EXPIRED,
42     QUIT,
43     LAST_SIGNAL
44 };
45 static guint signals[LAST_SIGNAL] = { 0 };
46
47 typedef struct
48 {
49     GIOChannel *to_server_channel, *from_server_channel;
50     guint8 *read_buffer;
51     gsize n_read;
52
53     GHashTable *hints;
54     guint autologin_timeout;
55
56     gchar *authentication_user;
57     gboolean in_authentication;
58     gboolean is_authenticated;
59     guint32 authenticate_sequence_number;
60     gboolean cancelling_authentication;
61 } LightDMGreeterPrivate;
62
63 G_DEFINE_TYPE (LightDMGreeter, lightdm_greeter, G_TYPE_OBJECT);
64
65 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_GREETER, LightDMGreeterPrivate)
66
67 #define HEADER_SIZE 8
68 #define MAX_MESSAGE_LENGTH 1024
69
70 /* Messages from the greeter to the server */
71 typedef enum
72 {
73     GREETER_MESSAGE_CONNECT = 0,
74     GREETER_MESSAGE_AUTHENTICATE,
75     GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
76     GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
77     GREETER_MESSAGE_START_SESSION,
78     GREETER_MESSAGE_CANCEL_AUTHENTICATION
79 } GreeterMessage;
80
81 /* Messages from the server to the greeter */
82 typedef enum
83 {
84     SERVER_MESSAGE_CONNECTED = 0,
85     SERVER_MESSAGE_QUIT,
86     SERVER_MESSAGE_PROMPT_AUTHENTICATION,
87     SERVER_MESSAGE_END_AUTHENTICATION,
88     SERVER_MESSAGE_SESSION_FAILED,
89 } ServerMessage;
90
91 /**
92  * lightdm_greeter_new:
93  *
94  * Create a new greeter.
95  *
96  * Return value: the new #LightDMGreeter
97  **/
98 LightDMGreeter *
99 lightdm_greeter_new ()
100 {
101     return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
102 }
103
104 static gboolean
105 timed_login_cb (gpointer data)
106 {
107     LightDMGreeter *greeter = data;
108     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
109
110     priv->autologin_timeout = 0;
111     g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
112
113     return FALSE;
114 }
115
116 static guint32
117 int_length ()
118 {
119     return 4;
120 }
121
122 static void
123 write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
124 {
125     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
126     GError *error = NULL;
127
128     if (g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, NULL) != G_IO_STATUS_NORMAL)
129         g_warning ("Error writing to daemon: %s", error->message);
130     else
131         g_debug ("Wrote %zi bytes to daemon", message_length);
132     g_clear_error (&error);
133     g_io_channel_flush (priv->to_server_channel, NULL);
134 }
135
136 static void
137 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
138 {
139     if (*offset + 4 >= buffer_length)
140         return;
141     buffer[*offset] = value >> 24;
142     buffer[*offset+1] = (value >> 16) & 0xFF;
143     buffer[*offset+2] = (value >> 8) & 0xFF;
144     buffer[*offset+3] = value & 0xFF;
145     *offset += 4;
146 }
147
148 static void
149 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
150 {
151     gint length = strlen (value);
152     write_int (buffer, buffer_length, length, offset);
153     if (*offset + length >= buffer_length)
154         return;
155     memcpy (buffer + *offset, value, length);
156     *offset += length;
157 }
158
159 static guint32
160 read_int (LightDMGreeter *greeter, gsize *offset)
161 {
162     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
163     guint32 value;
164     guint8 *buffer;
165
166     if (priv->n_read - *offset < int_length ())
167     {
168         g_warning ("Not enough space for int, need %i, got %zi", int_length (), priv->n_read - *offset);
169         return 0;
170     }
171
172     buffer = priv->read_buffer + *offset;
173     value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
174     *offset += int_length ();
175
176     return value;
177 }
178
179 static gchar *
180 read_string (LightDMGreeter *greeter, gsize *offset)
181 {
182     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
183     guint32 length;
184     gchar *value;
185
186     length = read_int (greeter, offset);
187     if (priv->n_read - *offset < length)
188     {
189         g_warning ("Not enough space for string, need %u, got %zu", length, priv->n_read - *offset);
190         return g_strdup ("");
191     }
192
193     value = g_malloc (sizeof (gchar) * (length + 1));
194     memcpy (value, priv->read_buffer + *offset, length);
195     value[length] = '\0';
196     *offset += length;
197
198     return value;
199 }
200
201 static guint32
202 string_length (const gchar *value)
203 {
204     return int_length () + strlen (value);
205 }
206
207 static void
208 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
209 {
210     write_int (buffer, buffer_length, id, offset);
211     write_int (buffer, buffer_length, length, offset);
212 }
213
214 static guint32 get_packet_length (LightDMGreeter *greeter)
215 {
216     gsize offset = 4;
217     return read_int (greeter, &offset);
218 }
219
220 static void
221 handle_connected (LightDMGreeter *greeter, guint32 length, gsize *offset)
222 {
223     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
224     gchar *version;
225     GString *hint_string;
226     int timeout;
227
228     version = read_string (greeter, offset);
229     hint_string = g_string_new ("");
230     while (*offset < length)
231     {
232         gchar *name, *value;
233       
234         name = read_string (greeter, offset);
235         value = read_string (greeter, offset);
236         g_hash_table_insert (priv->hints, name, value);
237         g_string_append_printf (hint_string, " %s=%s", name, value);
238     }
239
240     g_debug ("Connected version=%s%s", version, hint_string->str);
241     g_free (version);
242     g_string_free (hint_string, TRUE);
243
244     /* Set timeout for default login */
245     timeout = lightdm_greeter_get_autologin_timeout_hint (greeter);
246     if (timeout)
247     {
248         g_debug ("Setting autologin timer for %d seconds", timeout);
249         priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
250     }
251     g_signal_emit (G_OBJECT (greeter), signals[CONNECTED], 0);
252 }
253
254 static void
255 handle_prompt_authentication (LightDMGreeter *greeter, gsize *offset)
256 {
257     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
258     guint32 sequence_number, n_messages, i;
259
260     sequence_number = read_int (greeter, offset);
261     if (sequence_number != priv->authenticate_sequence_number)
262     {
263         g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
264         return;
265     }
266
267     if (priv->cancelling_authentication)
268     {
269         g_debug ("Ignoring prompt authentication as waiting for it to cancel");
270         return;
271     }
272
273     n_messages = read_int (greeter, offset);
274     g_debug ("Prompt user with %d message(s)", n_messages);
275
276     for (i = 0; i < n_messages; i++)
277     {
278         int msg_style;
279         gchar *msg;
280
281         msg_style = read_int (greeter, offset);
282         msg = read_string (greeter, offset);
283
284         // FIXME: Should stop on prompts?
285         switch (msg_style)
286         {
287         case PAM_PROMPT_ECHO_OFF:
288             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, msg, LIGHTDM_PROMPT_TYPE_SECRET);
289             break;
290         case PAM_PROMPT_ECHO_ON:
291             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, msg, LIGHTDM_PROMPT_TYPE_QUESTION);
292             break;
293         case PAM_ERROR_MSG:
294             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, msg, LIGHTDM_MESSAGE_TYPE_ERROR);
295             break;
296         case PAM_TEXT_INFO:
297             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, msg, LIGHTDM_MESSAGE_TYPE_INFO);
298             break;
299         }
300
301         g_free (msg);
302     }
303 }
304
305 static void
306 handle_end_authentication (LightDMGreeter *greeter, gsize *offset)
307 {
308     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
309     guint32 sequence_number, return_code;
310
311     sequence_number = read_int (greeter, offset);
312     return_code = read_int (greeter, offset);
313
314     if (sequence_number != priv->authenticate_sequence_number)
315     {
316         g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
317         return;
318     }
319
320     g_debug ("Authentication complete with return code %d", return_code);
321     priv->cancelling_authentication = FALSE;
322     priv->is_authenticated = (return_code == 0);
323     if (!priv->is_authenticated)
324     {
325         g_free (priv->authentication_user);
326         priv->authentication_user = NULL;
327     }
328     g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
329     priv->in_authentication = FALSE;
330 }
331
332 static void
333 handle_session_failed (LightDMGreeter *greeter, gsize *offset)
334
335     g_debug ("Session failed to start");
336     g_signal_emit (G_OBJECT (greeter), signals[SESSION_FAILED], 0);
337 }
338
339 static void
340 handle_quit (LightDMGreeter *greeter, gsize *offset)
341 {
342     g_debug ("Got quit request from server");
343     g_signal_emit (G_OBJECT (greeter), signals[QUIT], 0);
344 }
345
346 static gboolean
347 read_packet (LightDMGreeter *greeter, gboolean block)
348 {
349     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
350     gsize n_to_read, n_read;
351     GError *error = NULL;
352
353     /* Read the header, or the whole packet if we already have that */
354     n_to_read = HEADER_SIZE;
355     if (priv->n_read >= HEADER_SIZE)
356         n_to_read += get_packet_length (greeter);
357
358     do
359     {
360         GIOStatus status;
361         status = g_io_channel_read_chars (priv->from_server_channel,
362                                           (gchar *) priv->read_buffer + priv->n_read,
363                                           n_to_read - priv->n_read,
364                                           &n_read,
365                                           &error);
366         if (status == G_IO_STATUS_ERROR)
367             g_warning ("Error reading from server: %s", error->message);
368         g_clear_error (&error);
369         if (status != G_IO_STATUS_NORMAL)
370             break;
371
372         g_debug ("Read %zi bytes from daemon", n_read);
373
374         priv->n_read += n_read;
375     } while (priv->n_read < n_to_read && block);
376
377     /* Stop if haven't got all the data we want */
378     if (priv->n_read != n_to_read)
379         return FALSE;
380
381     /* If have header, rerun for content */
382     if (priv->n_read == HEADER_SIZE)
383     {
384         n_to_read = get_packet_length (greeter);
385         if (n_to_read > 0)
386         {
387             priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
388             return read_packet (greeter, block);
389         }
390     }
391
392     return TRUE;
393 }
394
395 static gboolean
396 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
397 {
398     LightDMGreeter *greeter = data;
399     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
400     gsize offset;
401     guint32 id, length;
402
403     if (!read_packet (greeter, FALSE))
404         return TRUE;
405
406     offset = 0;
407     id = read_int (greeter, &offset);
408     length = read_int (greeter, &offset);
409     switch (id)
410     {
411     case SERVER_MESSAGE_CONNECTED:
412         handle_connected (greeter, length, &offset);
413         break;
414     case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
415         handle_prompt_authentication (greeter, &offset);
416         break;
417     case SERVER_MESSAGE_END_AUTHENTICATION:
418         handle_end_authentication (greeter, &offset);
419         break;
420     case SERVER_MESSAGE_SESSION_FAILED:
421         handle_session_failed (greeter, &offset);
422         break;
423     case SERVER_MESSAGE_QUIT:
424         handle_quit (greeter, &offset);
425         break;
426     default:
427         g_warning ("Unknown message from server: %d", id);
428         break;
429     }
430
431     priv->n_read = 0;
432
433     return TRUE;
434 }
435
436 /**
437  * lightdm_greeter_connect_to_server:
438  * @greeter: The greeter to connect
439  *
440  * Connects the greeter to the display manager.
441  *
442  * Return value: #TRUE if successfully connected
443  **/
444 gboolean
445 lightdm_greeter_connect_to_server (LightDMGreeter *greeter)
446 {
447     LightDMGreeterPrivate *priv;
448     const gchar *fd;
449     guint8 message[MAX_MESSAGE_LENGTH];
450     gsize offset = 0;
451
452     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
453
454     priv = GET_PRIVATE (greeter);
455
456     fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
457     if (!fd)
458     {
459         g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
460         return FALSE;
461     }
462     priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
463     g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
464
465     fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
466     if (!fd)
467     {
468         g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
469         return FALSE;
470     }
471     priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
472     g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
473     g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
474
475     g_debug ("Connecting to display manager...");
476     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
477     write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
478     write_message (greeter, message, offset);
479
480     return TRUE;
481 }
482
483 /**
484  * lightdm_greeter_get_hint:
485  * @greeter: A #LightDMGreeter
486  * @name: The hint name to query.
487  *
488  * Get a hint.
489  *
490  * Return value: The value for this hint or #NULL if not set.
491  **/
492 const gchar *
493 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
494 {
495     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
496     return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
497 }
498
499 /**
500  * lightdm_greeter_get_default_session_hint:
501  * @greeter: A #LightDMGreeter
502  *
503  * Get the default session to use.
504  *
505  * Return value: The session name
506  **/
507 const gchar *
508 lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
509 {
510     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
511     return lightdm_greeter_get_hint (greeter, "default-session");
512 }
513
514 /**
515  * lightdm_greeter_get_hide_users_hint:
516  * @greeter: A #LightDMGreeter
517  *
518  * Check if user accounts should be shown.
519  *
520  * Return value: #TRUE if the available users should not be shown.
521  */
522 gboolean
523 lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
524 {
525     const gchar *value;
526
527     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
528     value = lightdm_greeter_get_hint (greeter, "hide-users");
529
530     return g_strcmp0 (value, "true") == 0;
531 }
532
533 /**
534  * lightdm_greeter_get_has_guest_account_hint:
535  * @greeter: A #LightDMGreeter
536  *
537  * Check if guest sessions are supported.
538  *
539  * Return value: #TRUE if guest sessions are supported.
540  */
541 gboolean
542 lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
543 {
544     const gchar *value;
545
546     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
547     value = lightdm_greeter_get_hint (greeter, "has-guest-account");
548   
549     return g_strcmp0 (value, "true") == 0;
550 }
551
552 /**
553  * lightdm_greeter_get_select_user_hint:
554  * @greeter: A #LightDMGreeter
555  *
556  * Get the user to select by default.
557  *
558  * Return value: A username
559  */
560 const gchar *
561 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
562 {
563     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
564     return lightdm_greeter_get_hint (greeter, "select-user");
565 }
566
567 /**
568  * lightdm_greeter_get_select_guest_hint:
569  * @greeter: A #LightDMGreeter
570  *
571  * Check if the guest account should be selected by default.
572  *
573  * Return value: #TRUE if the guest account should be selected by default.
574  */
575 gboolean
576 lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
577 {
578     const gchar *value;
579
580     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
581     value = lightdm_greeter_get_hint (greeter, "select-guest");
582   
583     return g_strcmp0 (value, "true") == 0;
584 }
585
586 /**
587  * lightdm_greeter_get_autologin_user_hint:
588  * @greeter: A #LightDMGreeter
589  *
590  * Get the user account to automatically logg into when the timer expires.
591  *
592  * Return value: The user account to automatically log into.
593  */
594 const gchar *
595 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
596 {
597     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
598     return lightdm_greeter_get_hint (greeter, "autologin-user");
599 }
600
601 /**
602  * lightdm_greeter_get_autologin_guest_hint:
603  * @greeter: A #LightDMGreeter
604  *
605  * Check if the guest account should be automatically logged into when the timer expires.
606  *
607  * Return value: #TRUE if the guest account should be automatically logged into.
608  */
609 gboolean
610 lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
611 {
612     const gchar *value;
613
614     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
615     value = lightdm_greeter_get_hint (greeter, "autologin-guest");
616   
617     return g_strcmp0 (value, "true") == 0;
618 }
619
620 /**
621  * lightdm_greeter_get_autologin_timeout_hint:
622  * @greeter: A #LightDMGreeter
623  *
624  * Get the number of seconds to wait before automaitcally logging in.
625  *
626  * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
627  */
628 gint
629 lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
630 {
631     const gchar *value;
632     gint timeout = 0;
633
634     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
635     value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
636     if (value)
637         timeout = atoi (value);
638     if (timeout < 0)
639         timeout = 0;
640
641     return timeout;
642 }
643
644 /**
645  * lightdm_greeter_cancel_autologin:
646  * @greeter: A #LightDMGreeter
647  *
648  * Cancel the automatic login.
649  */
650 void
651 lightdm_greeter_cancel_autologin (LightDMGreeter *greeter)
652 {
653     LightDMGreeterPrivate *priv;
654
655     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
656
657     priv = GET_PRIVATE (greeter);
658
659     if (priv->autologin_timeout)
660        g_source_remove (priv->autologin_timeout);
661     priv->autologin_timeout = 0;
662 }
663
664 /**
665  * lightdm_greeter_authenticate:
666  * @greeter: A #LightDMGreeter
667  * @username: (allow-none): A username or #NULL to prompt for a username.
668  *
669  * Starts the authentication procedure for a user.
670  **/
671 void
672 lightdm_greeter_authenticate (LightDMGreeter *greeter, const char *username)
673 {
674     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
675     guint8 message[MAX_MESSAGE_LENGTH];
676     gsize offset = 0;
677
678     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
679
680     if (!username)
681         username = "";
682
683     priv->cancelling_authentication = FALSE;
684     priv->authenticate_sequence_number++;
685     priv->in_authentication = TRUE;  
686     priv->is_authenticated = FALSE;
687     g_free (priv->authentication_user);
688     priv->authentication_user = g_strdup (username);
689
690     g_debug ("Starting authentication for user %s...", username);
691     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset);
692     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
693     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
694     write_message (greeter, message, offset);
695 }
696
697 /**
698  * lightdm_greeter_authenticate_as_guest:
699  * @greeter: A #LightDMGreeter
700  *
701  * Starts the authentication procedure for the guest user.
702  **/
703 void
704 lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter)
705 {
706     LightDMGreeterPrivate *priv;
707     guint8 message[MAX_MESSAGE_LENGTH];
708     gsize offset = 0;
709
710     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
711
712     priv = GET_PRIVATE (greeter);
713
714     priv->cancelling_authentication = FALSE;
715     priv->authenticate_sequence_number++;
716     priv->in_authentication = TRUE;
717     priv->is_authenticated = FALSE;
718     g_free (priv->authentication_user);
719     priv->authentication_user = NULL;
720
721     g_debug ("Starting authentication for guest account...");
722     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset);
723     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
724     write_message (greeter, message, offset);
725 }
726
727 /**
728  * lightdm_greeter_respond:
729  * @greeter: A #LightDMGreeter
730  * @response: Response to a prompt
731  *
732  * Provide response to a prompt.
733  **/
734 void
735 lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response)
736 {
737     guint8 message[MAX_MESSAGE_LENGTH];
738     gsize offset = 0;
739
740     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
741     g_return_if_fail (response != NULL);
742
743     g_debug ("Providing response to display manager");
744     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, int_length () + string_length (response), &offset);
745     // FIXME: Could be multiple responses required
746     write_int (message, MAX_MESSAGE_LENGTH, 1, &offset);
747     write_string (message, MAX_MESSAGE_LENGTH, response, &offset);
748     write_message (greeter, message, offset);
749 }
750
751 /**
752  * lightdm_greeter_cancel_authentication:
753  * @greeter: A #LightDMGreeter
754  *
755  * Cancel the current user authentication.
756  **/
757 void
758 lightdm_greeter_cancel_authentication (LightDMGreeter *greeter)
759 {
760     LightDMGreeterPrivate *priv;
761     guint8 message[MAX_MESSAGE_LENGTH];
762     gsize offset = 0;
763
764     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
765
766     priv = GET_PRIVATE (greeter);
767
768     priv->cancelling_authentication = TRUE;
769     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
770     write_message (greeter, message, offset);
771 }
772
773 /**
774  * lightdm_greeter_get_in_authentication:
775  * @greeter: A #LightDMGreeter
776  *
777  * Checks if the greeter is in the process of authenticating.
778  *
779  * Return value: #TRUE if the greeter is authenticating a user.
780  **/
781 gboolean
782 lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
783 {
784     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
785     return GET_PRIVATE (greeter)->in_authentication;
786 }
787
788 /**
789  * lightdm_greeter_get_is_authenticated:
790  * @greeter: A #LightDMGreeter
791  *
792  * Checks if the greeter has successfully authenticated.
793  *
794  * Return value: #TRUE if the greeter is authenticated for login.
795  **/
796 gboolean
797 lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
798 {
799     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
800     return GET_PRIVATE (greeter)->is_authenticated;
801 }
802
803 /**
804  * lightdm_greeter_get_authentication_user:
805  * @greeter: A #LightDMGreeter
806  *
807  * Get the user that is being authenticated.
808  *
809  * Return value: The username of the authentication user being authenticated or #NULL if no authentication in progress.
810  */
811 const gchar *
812 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
813 {
814     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
815     return GET_PRIVATE (greeter)->authentication_user;
816 }
817
818 /**
819  * lightdm_greeter_start_session:
820  * @greeter: A #LightDMGreeter
821  * @session: (allow-none): The session to log into or #NULL to use the default
822  *
823  * Start a session for the logged in user.
824  **/
825 void
826 lightdm_greeter_start_session (LightDMGreeter *greeter, const gchar *session)
827 {
828     guint8 message[MAX_MESSAGE_LENGTH];
829     gsize offset = 0;
830
831     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
832   
833     if (!session)
834         session = "";
835
836     g_debug ("Starting session %s", session);
837     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
838     write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
839     write_message (greeter, message, offset);
840 }
841
842 /**
843  * lightdm_greeter_start_default_session:
844  * @greeter: A #LightDMGreeter
845  *
846  * Start the default session for the authenticated user.
847  **/
848 void
849 lightdm_greeter_start_default_session (LightDMGreeter *greeter)
850 {
851     lightdm_greeter_start_session (greeter, NULL);
852 }
853
854 static void
855 lightdm_greeter_init (LightDMGreeter *greeter)
856 {
857     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
858
859     priv->read_buffer = g_malloc (HEADER_SIZE);
860     priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
861 }
862
863 static void
864 lightdm_greeter_set_property (GObject      *object,
865                           guint         prop_id,
866                           const GValue *value,
867                           GParamSpec   *pspec)
868 {
869     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
870 }
871
872 static void
873 lightdm_greeter_get_property (GObject    *object,
874                           guint       prop_id,
875                           GValue     *value,
876                           GParamSpec *pspec)
877 {
878     LightDMGreeter *self;
879
880     self = LIGHTDM_GREETER (object);
881
882     switch (prop_id) {
883     case PROP_DEFAULT_SESSION_HINT:
884         g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
885         break;
886     case PROP_HIDE_USERS_HINT:
887         g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
888         break;
889     case PROP_HAS_GUEST_ACCOUNT_HINT:
890         g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
891         break;
892     case PROP_SELECT_USER_HINT:
893         g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
894         break;
895     case PROP_SELECT_GUEST_HINT:
896         g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
897         break;
898     case PROP_AUTOLOGIN_USER_HINT:
899         g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
900         break;
901     case PROP_AUTOLOGIN_GUEST_HINT:
902         g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
903         break;
904     case PROP_AUTOLOGIN_TIMEOUT_HINT:
905         g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
906         break;
907     case PROP_AUTHENTICATION_USER:
908         g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
909         break;
910     case PROP_IN_AUTHENTICATION:
911         g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
912         break;
913     case PROP_IS_AUTHENTICATED:
914         g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
915         break;
916     default:
917         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
918         break;
919     }
920 }
921
922 static void
923 marshal_VOID__STRING_INT (GClosure     *closure,
924                           GValue       *return_value G_GNUC_UNUSED,
925                           guint         n_param_values,
926                           const GValue *param_values,
927                           gpointer      invocation_hint G_GNUC_UNUSED,
928                           gpointer      marshal_data)
929 {
930     typedef void (*GMarshalFunc_VOID__STRING_INT) (gpointer     data1,
931                                                    gpointer     arg_1,
932                                                    gint         arg_2,
933                                                    gpointer     data2);
934     register GMarshalFunc_VOID__STRING_INT callback;
935     register GCClosure *cc = (GCClosure*) closure;
936     register gpointer data1, data2;
937
938     g_return_if_fail (n_param_values == 3);
939
940     if (G_CCLOSURE_SWAP_DATA (closure))
941     {
942         data1 = closure->data;
943         data2 = g_value_peek_pointer (param_values + 0);
944     }
945     else
946     {
947         data1 = g_value_peek_pointer (param_values + 0);
948         data2 = closure->data;
949     }
950     callback = (GMarshalFunc_VOID__STRING_INT) (marshal_data ? marshal_data : cc->callback);
951
952     callback (data1,
953               (param_values + 1)->data[0].v_pointer,
954               (param_values + 2)->data[0].v_int,
955               data2);
956 }
957
958 static void
959 lightdm_greeter_finalize (GObject *object)
960 {
961     LightDMGreeter *self = LIGHTDM_GREETER (object);
962     LightDMGreeterPrivate *priv = GET_PRIVATE (self);
963
964     if (priv->to_server_channel)
965         g_io_channel_unref (priv->to_server_channel);
966     if (priv->from_server_channel)
967         g_io_channel_unref (priv->from_server_channel);
968     g_free (priv->authentication_user);
969     g_hash_table_unref (priv->hints);
970
971     G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
972 }
973
974 static void
975 lightdm_greeter_class_init (LightDMGreeterClass *klass)
976 {
977     GObjectClass *object_class = G_OBJECT_CLASS (klass);
978
979     g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
980
981     object_class->set_property = lightdm_greeter_set_property;
982     object_class->get_property = lightdm_greeter_get_property;
983     object_class->finalize = lightdm_greeter_finalize;
984
985     g_object_class_install_property (object_class,
986                                      PROP_DEFAULT_SESSION_HINT,
987                                      g_param_spec_string ("default-session-hint",
988                                                           "default-session-hint",
989                                                           "Default session hint",
990                                                           NULL,
991                                                           G_PARAM_READWRITE));
992
993     g_object_class_install_property (object_class,
994                                      PROP_HIDE_USERS_HINT,
995                                      g_param_spec_boolean ("hide-users-hint",
996                                                            "hide-users-hint",
997                                                            "hide users hint",
998                                                            FALSE,
999                                                            G_PARAM_READABLE));
1000
1001     g_object_class_install_property (object_class,
1002                                      PROP_HAS_GUEST_ACCOUNT_HINT,
1003                                      g_param_spec_boolean ("has-guest-account-hint",
1004                                                            "has-guest-account-hint",
1005                                                            "Has guest account hint",
1006                                                            FALSE,
1007                                                            G_PARAM_READABLE));
1008
1009     g_object_class_install_property (object_class,
1010                                      PROP_SELECT_USER_HINT,
1011                                      g_param_spec_string ("select-user-hint",
1012                                                           "select-user-hint",
1013                                                           "Select user hint",
1014                                                           NULL,
1015                                                           G_PARAM_READABLE));
1016
1017     g_object_class_install_property (object_class,
1018                                      PROP_SELECT_GUEST_HINT,
1019                                      g_param_spec_boolean ("select-guest-hint",
1020                                                            "select-guest-hint",
1021                                                            "Select guest account hint",
1022                                                            FALSE,
1023                                                            G_PARAM_READABLE));
1024
1025     g_object_class_install_property (object_class,
1026                                      PROP_AUTOLOGIN_USER_HINT,
1027                                      g_param_spec_string ("autologin-user-hint",
1028                                                           "autologin-user-hint",
1029                                                           "Autologin user hint",
1030                                                           NULL,
1031                                                           G_PARAM_READABLE));
1032
1033     g_object_class_install_property (object_class,
1034                                      PROP_AUTOLOGIN_GUEST_HINT,
1035                                      g_param_spec_boolean ("autologin-guest-hint",
1036                                                            "autologin-guest-hint",
1037                                                            "Autologin guest account hint",
1038                                                            FALSE,
1039                                                            G_PARAM_READABLE));
1040
1041     g_object_class_install_property (object_class,
1042                                      PROP_AUTOLOGIN_TIMEOUT_HINT,
1043                                      g_param_spec_int ("autologin-timeout-hint",
1044                                                        "autologin-timeout-hint",
1045                                                        "Autologin timeout hint",
1046                                                        0, G_MAXINT, 0,
1047                                                        G_PARAM_READABLE));
1048
1049     g_object_class_install_property (object_class,
1050                                      PROP_AUTHENTICATION_USER,
1051                                      g_param_spec_string ("authentication-user",
1052                                                           "authentication-user",
1053                                                           "The user being authenticated",
1054                                                           NULL,
1055                                                           G_PARAM_READABLE));
1056     g_object_class_install_property (object_class,
1057                                      PROP_IN_AUTHENTICATION,
1058                                      g_param_spec_boolean ("in-authentication",
1059                                                            "in-authentication",
1060                                                            "TRUE if a user is being authenticated",
1061                                                            FALSE,
1062                                                            G_PARAM_READABLE));
1063     g_object_class_install_property (object_class,
1064                                      PROP_IS_AUTHENTICATED,
1065                                      g_param_spec_boolean ("is-authenticated",
1066                                                            "is-authenticated",
1067                                                            "TRUE if the selected user is authenticated",
1068                                                            FALSE,
1069                                                            G_PARAM_READABLE));
1070
1071     /**
1072      * LightDMGreeter::connected:
1073      * @greeter: A #LightDMGreeter
1074      *
1075      * The ::connected signal gets emitted when the greeter connects to the
1076      * LightDM server.
1077      **/
1078     signals[CONNECTED] =
1079         g_signal_new ("connected",
1080                       G_TYPE_FROM_CLASS (klass),
1081                       G_SIGNAL_RUN_LAST,
1082                       G_STRUCT_OFFSET (LightDMGreeterClass, connected),
1083                       NULL, NULL,
1084                       g_cclosure_marshal_VOID__VOID,
1085                       G_TYPE_NONE, 0);
1086
1087     /**
1088      * LightDMGreeter::show-prompt:
1089      * @greeter: A #LightDMGreeter
1090      * @text: Prompt text
1091      * @type: Prompt type
1092      *
1093      * The ::show-prompt signal gets emitted when the greeter should show a
1094      * prompt to the user.  The given text should be displayed and an input
1095      * field for the user to provide a response.
1096      *
1097      * Call lightdm_greeter_respond() with the resultant input or
1098      * lightdm_greeter_cancel_authentication() to abort the authentication.
1099      **/
1100     signals[SHOW_PROMPT] =
1101         g_signal_new ("show-prompt",
1102                       G_TYPE_FROM_CLASS (klass),
1103                       G_SIGNAL_RUN_LAST,
1104                       G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
1105                       NULL, NULL,
1106                       marshal_VOID__STRING_INT,
1107                       G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1108
1109     /**
1110      * LightDMGreeter::show-message:
1111      * @greeter: A #LightDMGreeter
1112      * @text: Message text
1113      * @type: Message type
1114      *
1115      * The ::show-message signal gets emitted when the greeter
1116      * should show a message to the user.
1117      **/
1118     signals[SHOW_MESSAGE] =
1119         g_signal_new ("show-message",
1120                       G_TYPE_FROM_CLASS (klass),
1121                       G_SIGNAL_RUN_LAST,
1122                       G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
1123                       NULL, NULL,
1124                       marshal_VOID__STRING_INT,
1125                       G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1126
1127     /**
1128      * LightDMGreeter::authentication-complete:
1129      * @greeter: A #LightDMGreeter
1130      *
1131      * The ::authentication-complete signal gets emitted when the greeter
1132      * has completed authentication.
1133      *
1134      * Call lightdm_greeter_get_is_authenticated() to check if the authentication
1135      * was successful.
1136      **/
1137     signals[AUTHENTICATION_COMPLETE] =
1138         g_signal_new ("authentication-complete",
1139                       G_TYPE_FROM_CLASS (klass),
1140                       G_SIGNAL_RUN_LAST,
1141                       G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
1142                       NULL, NULL,
1143                       g_cclosure_marshal_VOID__VOID,
1144                       G_TYPE_NONE, 0);
1145
1146     /**
1147      * LightDMGreeter::session-failed:
1148      * @greeter: A #LightDMGreeter
1149      *
1150      * The ::session-failed signal gets emitted when the deamon has failed
1151      * to start the requested session.
1152      **/
1153     signals[SESSION_FAILED] =
1154         g_signal_new ("session-failed",
1155                       G_TYPE_FROM_CLASS (klass),
1156                       G_SIGNAL_RUN_LAST,
1157                       G_STRUCT_OFFSET (LightDMGreeterClass, session_failed),
1158                       NULL, NULL,
1159                       g_cclosure_marshal_VOID__VOID,
1160                       G_TYPE_NONE, 0);
1161
1162     /**
1163      * LightDMGreeter::autologin-timer-expired:
1164      * @greeter: A #LightDMGreeter
1165      *
1166      * The ::timed-login signal gets emitted when the automatic login timer has expired.
1167      * The application should then call lightdm_greeter_login().
1168      **/
1169     signals[AUTOLOGIN_TIMER_EXPIRED] =
1170         g_signal_new ("autologin-timer-expired",
1171                       G_TYPE_FROM_CLASS (klass),
1172                       G_SIGNAL_RUN_LAST,
1173                       G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),
1174                       NULL, NULL,
1175                       g_cclosure_marshal_VOID__VOID,
1176                       G_TYPE_NONE, 0);
1177
1178     /**
1179      * LightDMGreeter::quit:
1180      * @greeter: A #LightDMGreeter
1181      *
1182      * The ::quit signal gets emitted when the greeter should exit.
1183      **/
1184     signals[QUIT] =
1185         g_signal_new ("quit",
1186                       G_TYPE_FROM_CLASS (klass),
1187                       G_SIGNAL_RUN_LAST,
1188                       G_STRUCT_OFFSET (LightDMGreeterClass, quit),
1189                       NULL, NULL,
1190                       g_cclosure_marshal_VOID__VOID,
1191                       G_TYPE_NONE, 0);
1192 }