2 * Copyright (C) 2010 Robert Ancell.
3 * Author: Robert Ancell <robert.ancell@canonical.com>
5 * This library is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Lesser General Public License as published by the Free
7 * Software Foundation; either version 2 or version 3 of the License.
8 * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
15 #include <security/pam_appl.h>
17 #include "lightdm/greeter.h"
21 PROP_DEFAULT_SESSION_HINT,
23 PROP_SHOW_MANUAL_LOGIN_HINT,
24 PROP_SHOW_REMOTE_LOGIN_HINT,
26 PROP_HAS_GUEST_ACCOUNT_HINT,
27 PROP_SELECT_USER_HINT,
28 PROP_SELECT_GUEST_HINT,
29 PROP_AUTOLOGIN_USER_HINT,
30 PROP_AUTOLOGIN_GUEST_HINT,
31 PROP_AUTOLOGIN_TIMEOUT_HINT,
32 PROP_AUTHENTICATION_USER,
33 PROP_IN_AUTHENTICATION,
34 PROP_IS_AUTHENTICATED,
40 AUTHENTICATION_COMPLETE,
41 AUTOLOGIN_TIMER_EXPIRED,
46 static guint signals[LAST_SIGNAL] = { 0 };
52 GIOChannel *to_server_channel, *from_server_channel;
56 gsize n_responses_waiting;
57 GList *responses_received;
60 guint autologin_timeout;
62 gchar *authentication_user;
63 gboolean in_authentication;
64 gboolean is_authenticated;
65 guint32 authenticate_sequence_number;
66 gboolean cancelling_authentication;
67 } LightDMGreeterPrivate;
69 G_DEFINE_TYPE (LightDMGreeter, lightdm_greeter, G_TYPE_OBJECT);
71 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_GREETER, LightDMGreeterPrivate)
74 #define MAX_MESSAGE_LENGTH 1024
76 /* Messages from the greeter to the server */
79 GREETER_MESSAGE_CONNECT = 0,
80 GREETER_MESSAGE_AUTHENTICATE,
81 GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
82 GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
83 GREETER_MESSAGE_START_SESSION,
84 GREETER_MESSAGE_CANCEL_AUTHENTICATION,
85 GREETER_MESSAGE_SET_LANGUAGE,
86 GREETER_MESSAGE_AUTHENTICATE_REMOTE,
87 GREETER_MESSAGE_ENSURE_SHARED_DIR,
88 GREETER_MESSAGE_SET_RESETTABLE,
91 /* Messages from the server to the greeter */
94 SERVER_MESSAGE_CONNECTED = 0,
95 SERVER_MESSAGE_PROMPT_AUTHENTICATION,
96 SERVER_MESSAGE_END_AUTHENTICATION,
97 SERVER_MESSAGE_SESSION_RESULT,
98 SERVER_MESSAGE_SHARED_DIR_RESULT,
100 SERVER_MESSAGE_RESET,
104 * lightdm_greeter_new:
106 * Create a new greeter.
108 * Return value: the new #LightDMGreeter
111 lightdm_greeter_new ()
113 return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
117 timed_login_cb (gpointer data)
119 LightDMGreeter *greeter = data;
120 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
122 priv->autologin_timeout = 0;
123 g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
135 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
137 if (*offset + 4 >= buffer_length)
139 buffer[*offset] = value >> 24;
140 buffer[*offset+1] = (value >> 16) & 0xFF;
141 buffer[*offset+2] = (value >> 8) & 0xFF;
142 buffer[*offset+3] = value & 0xFF;
147 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
152 length = strlen (value);
153 write_int (buffer, buffer_length, length, offset);
154 if (*offset + length >= buffer_length)
156 memcpy (buffer + *offset, value, length);
161 read_int (guint8 *message, gsize message_length, gsize *offset)
166 if (message_length - *offset < int_length ())
168 g_warning ("Not enough space for int, need %i, got %zi", int_length (), message_length - *offset);
172 buffer = message + *offset;
173 value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
174 *offset += int_length ();
180 read_string (guint8 *message, gsize message_length, gsize *offset)
185 length = read_int (message, message_length, offset);
186 if (message_length - *offset < length)
188 g_warning ("Not enough space for string, need %u, got %zu", length, message_length - *offset);
189 return g_strdup ("");
192 value = g_malloc (sizeof (gchar) * (length + 1));
193 memcpy (value, message + *offset, length);
194 value[length] = '\0';
201 string_length (const gchar *value)
204 return int_length () + strlen (value);
206 return int_length ();
210 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
212 write_int (buffer, buffer_length, id, offset);
213 write_int (buffer, buffer_length, length, offset);
217 get_message_length (guint8 *message, gsize message_length)
220 return read_int (message, message_length, &offset);
224 write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
226 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
228 GError *error = NULL;
229 guint32 stated_length;
231 /* Double check that we're sending well-formed messages. If we say we're
232 sending more than we do, we end up DOS'ing lightdm as it waits for the
233 rest. If we say we're sending less than we do, we confuse the heck out
234 of lightdm, as it starts reading headers from the middle of our
236 stated_length = HEADER_SIZE + get_message_length (message, message_length);
237 if (stated_length != message_length)
239 g_warning ("Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu", stated_length, message_length);
243 status = g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, &error);
245 g_warning ("Error writing to daemon: %s", error->message);
246 g_clear_error (&error);
247 if (status == G_IO_STATUS_NORMAL)
248 g_debug ("Wrote %zi bytes to daemon", message_length);
249 g_io_channel_flush (priv->to_server_channel, NULL);
253 handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
255 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
257 GString *hint_string;
260 version = read_string (message, message_length, offset);
261 hint_string = g_string_new ("");
262 while (*offset < message_length)
266 name = read_string (message, message_length, offset);
267 value = read_string (message, message_length, offset);
268 g_hash_table_insert (priv->hints, name, value);
269 g_string_append_printf (hint_string, " %s=%s", name, value);
272 g_debug ("Connected version=%s%s", version, hint_string->str);
274 g_string_free (hint_string, TRUE);
276 /* Set timeout for default login */
277 timeout = lightdm_greeter_get_autologin_timeout_hint (greeter);
280 g_debug ("Setting autologin timer for %d seconds", timeout);
281 priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
286 handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
288 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
289 guint32 sequence_number, n_messages, i;
292 sequence_number = read_int (message, message_length, offset);
293 if (sequence_number != priv->authenticate_sequence_number)
295 g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
299 if (priv->cancelling_authentication)
301 g_debug ("Ignoring prompt authentication as waiting for it to cancel");
305 /* Update username */
306 username = read_string (message, message_length, offset);
307 if (strcmp (username, "") == 0)
312 g_free (priv->authentication_user);
313 priv->authentication_user = username;
315 g_list_free_full (priv->responses_received, g_free);
316 priv->responses_received = NULL;
317 priv->n_responses_waiting = 0;
319 n_messages = read_int (message, message_length, offset);
320 g_debug ("Prompt user with %d message(s)", n_messages);
322 for (i = 0; i < n_messages; i++)
327 style = read_int (message, message_length, offset);
328 text = read_string (message, message_length, offset);
330 // FIXME: Should stop on prompts?
333 case PAM_PROMPT_ECHO_OFF:
334 priv->n_responses_waiting++;
335 g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_SECRET);
337 case PAM_PROMPT_ECHO_ON:
338 priv->n_responses_waiting++;
339 g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_QUESTION);
342 g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_ERROR);
345 g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_INFO);
354 handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
356 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
357 guint32 sequence_number, return_code;
360 sequence_number = read_int (message, message_length, offset);
362 if (sequence_number != priv->authenticate_sequence_number)
364 g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
368 username = read_string (message, message_length, offset);
369 return_code = read_int (message, message_length, offset);
371 g_debug ("Authentication complete for user %s with return code %d", username, return_code);
373 /* Update username */
374 if (strcmp (username, "") == 0)
379 g_free (priv->authentication_user);
380 priv->authentication_user = username;
382 priv->cancelling_authentication = FALSE;
383 priv->is_authenticated = (return_code == 0);
385 priv->in_authentication = FALSE;
386 g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
390 handle_reset (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
392 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
393 GString *hint_string;
395 g_hash_table_remove_all (priv->hints);
397 hint_string = g_string_new ("");
398 while (*offset < message_length)
402 name = read_string (message, message_length, offset);
403 value = read_string (message, message_length, offset);
404 g_hash_table_insert (priv->hints, name, value);
405 g_string_append_printf (hint_string, " %s=%s", name, value);
408 g_debug ("Reset%s", hint_string->str);
409 g_string_free (hint_string, TRUE);
411 g_signal_emit (G_OBJECT (greeter), signals[RESET], 0);
415 read_message (LightDMGreeter *greeter, gsize *length, gboolean block)
417 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
418 gsize n_to_read, n_read;
420 GError *error = NULL;
422 /* Read the header, or the whole message if we already have that */
423 n_to_read = HEADER_SIZE;
424 if (priv->n_read >= HEADER_SIZE)
425 n_to_read += get_message_length (priv->read_buffer, priv->n_read);
430 status = g_io_channel_read_chars (priv->from_server_channel,
431 (gchar *) priv->read_buffer + priv->n_read,
432 n_to_read - priv->n_read,
436 g_warning ("Error reading from server: %s", error->message);
437 g_clear_error (&error);
438 if (status != G_IO_STATUS_NORMAL)
441 g_debug ("Read %zi bytes from daemon", n_read);
443 priv->n_read += n_read;
444 } while (priv->n_read < n_to_read && block);
446 /* Stop if haven't got all the data we want */
447 if (priv->n_read != n_to_read)
450 /* If have header, rerun for content */
451 if (priv->n_read == HEADER_SIZE)
453 n_to_read = get_message_length (priv->read_buffer, priv->n_read);
456 priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
457 return read_message (greeter, length, block);
461 buffer = priv->read_buffer;
462 *length = priv->n_read;
464 priv->read_buffer = g_malloc (priv->n_read);
471 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
473 LightDMGreeter *greeter = data;
475 gsize message_length, offset;
478 message = read_message (greeter, &message_length, FALSE);
483 id = read_int (message, message_length, &offset);
484 read_int (message, message_length, &offset);
487 case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
488 handle_prompt_authentication (greeter, message, message_length, &offset);
490 case SERVER_MESSAGE_END_AUTHENTICATION:
491 handle_end_authentication (greeter, message, message_length, &offset);
493 case SERVER_MESSAGE_IDLE:
494 g_signal_emit (G_OBJECT (greeter), signals[IDLE], 0);
496 case SERVER_MESSAGE_RESET:
497 handle_reset (greeter, message, message_length, &offset);
500 g_warning ("Unknown message from server: %d", id);
509 * lightdm_greeter_connect_sync:
510 * @greeter: The greeter to connect
511 * @error: return location for a #GError, or %NULL
513 * Connects the greeter to the display manager. Will block until connected.
515 * Return value: #TRUE if successfully connected
518 lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
520 LightDMGreeterPrivate *priv;
522 guint8 message[MAX_MESSAGE_LENGTH];
524 gsize response_length, offset = 0;
527 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
529 priv = GET_PRIVATE (greeter);
531 fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
534 g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
537 priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
538 g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
540 fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
543 g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
546 priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
547 g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
548 g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
550 g_debug ("Connecting to display manager...");
551 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
552 write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
553 write_message (greeter, message, offset);
555 response = read_message (greeter, &response_length, TRUE);
560 id = read_int (response, response_length, &offset);
561 read_int (response, response_length, &offset);
562 if (id == SERVER_MESSAGE_CONNECTED)
563 handle_connected (greeter, response, response_length, &offset);
565 if (id != SERVER_MESSAGE_CONNECTED)
567 g_warning ("Expected CONNECTED message, got %d", id);
571 priv->connected = TRUE;
577 * lightdm_greeter_get_hint:
578 * @greeter: A #LightDMGreeter
579 * @name: The hint name to query.
583 * Return value: The value for this hint or #NULL if not set.
586 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
588 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
589 return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
593 * lightdm_greeter_get_default_session_hint:
594 * @greeter: A #LightDMGreeter
596 * Get the default session to use.
598 * Return value: The session name
601 lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
603 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
604 return lightdm_greeter_get_hint (greeter, "default-session");
608 * lightdm_greeter_get_hide_users_hint:
609 * @greeter: A #LightDMGreeter
611 * Check if user accounts should be shown. If this is TRUE then the list of
612 * accounts should be taken from #LightDMUserList and displayed in the greeter
613 * for the user to choose from. Note that this list can be empty and it is
614 * recommended you show a method for the user to enter a username manually.
616 * If this option is shown the greeter should only allow these users to be
617 * chosen for login unless the manual login hint is set.
619 * Return value: #TRUE if the available users should not be shown.
622 lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
626 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
627 value = lightdm_greeter_get_hint (greeter, "hide-users");
629 return g_strcmp0 (value, "true") == 0;
633 * lightdm_greeter_get_show_manual_login_hint:
634 * @greeter: A #LightDMGreeter
636 * Check if a manual login option should be shown. If set the GUI
637 * should provide a way for a username to be entered manually.
638 * Without this hint a greeter which is showing a user list can
639 * limit logins to only those users.
641 * Return value: #TRUE if a manual login option should be shown.
644 lightdm_greeter_get_show_manual_login_hint (LightDMGreeter *greeter)
648 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
649 value = lightdm_greeter_get_hint (greeter, "show-manual-login");
651 return g_strcmp0 (value, "true") == 0;
655 * lightdm_greeter_get_show_remote_login_hint:
656 * @greeter: A #LightDMGreeter
658 * Check if a remote login option should be shown. If set the GUI
659 * should provide a way for a user to log into a remote desktop server.
661 * Return value: #TRUE if a remote login option should be shown.
664 lightdm_greeter_get_show_remote_login_hint (LightDMGreeter *greeter)
668 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
669 value = lightdm_greeter_get_hint (greeter, "show-remote-login");
671 return g_strcmp0 (value, "true") == 0;
675 * lightdm_greeter_get_lock_hint:
676 * @greeter: A #LightDMGreeter
678 * Check if the greeter is acting as a lock screen.
680 * Return value: #TRUE if the greeter was triggered by locking the seat.
683 lightdm_greeter_get_lock_hint (LightDMGreeter *greeter)
687 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
688 value = lightdm_greeter_get_hint (greeter, "lock-screen");
690 return g_strcmp0 (value, "true") == 0;
694 * lightdm_greeter_get_has_guest_account_hint:
695 * @greeter: A #LightDMGreeter
697 * Check if guest sessions are supported.
699 * Return value: #TRUE if guest sessions are supported.
702 lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
706 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
707 value = lightdm_greeter_get_hint (greeter, "has-guest-account");
709 return g_strcmp0 (value, "true") == 0;
713 * lightdm_greeter_get_select_user_hint:
714 * @greeter: A #LightDMGreeter
716 * Get the user to select by default.
718 * Return value: A username
721 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
723 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
724 return lightdm_greeter_get_hint (greeter, "select-user");
728 * lightdm_greeter_get_select_guest_hint:
729 * @greeter: A #LightDMGreeter
731 * Check if the guest account should be selected by default.
733 * Return value: #TRUE if the guest account should be selected by default.
736 lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
740 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
741 value = lightdm_greeter_get_hint (greeter, "select-guest");
743 return g_strcmp0 (value, "true") == 0;
747 * lightdm_greeter_get_autologin_user_hint:
748 * @greeter: A #LightDMGreeter
750 * Get the user account to automatically logg into when the timer expires.
752 * Return value: The user account to automatically log into.
755 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
757 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
758 return lightdm_greeter_get_hint (greeter, "autologin-user");
762 * lightdm_greeter_get_autologin_guest_hint:
763 * @greeter: A #LightDMGreeter
765 * Check if the guest account should be automatically logged into when the timer expires.
767 * Return value: #TRUE if the guest account should be automatically logged into.
770 lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
774 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
775 value = lightdm_greeter_get_hint (greeter, "autologin-guest");
777 return g_strcmp0 (value, "true") == 0;
781 * lightdm_greeter_get_autologin_timeout_hint:
782 * @greeter: A #LightDMGreeter
784 * Get the number of seconds to wait before automaitcally logging in.
786 * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
789 lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
794 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
795 value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
797 timeout = atoi (value);
805 * lightdm_greeter_cancel_autologin:
806 * @greeter: A #LightDMGreeter
808 * Cancel the automatic login.
811 lightdm_greeter_cancel_autologin (LightDMGreeter *greeter)
813 LightDMGreeterPrivate *priv;
815 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
817 priv = GET_PRIVATE (greeter);
819 if (priv->autologin_timeout)
820 g_source_remove (priv->autologin_timeout);
821 priv->autologin_timeout = 0;
825 * lightdm_greeter_authenticate:
826 * @greeter: A #LightDMGreeter
827 * @username: (allow-none): A username or #NULL to prompt for a username.
829 * Starts the authentication procedure for a user.
832 lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username)
834 LightDMGreeterPrivate *priv;
835 guint8 message[MAX_MESSAGE_LENGTH];
838 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
840 priv = GET_PRIVATE (greeter);
842 g_return_if_fail (priv->connected);
844 priv->cancelling_authentication = FALSE;
845 priv->authenticate_sequence_number++;
846 priv->in_authentication = TRUE;
847 priv->is_authenticated = FALSE;
848 if (username != priv->authentication_user)
850 g_free (priv->authentication_user);
851 priv->authentication_user = g_strdup (username);
854 g_debug ("Starting authentication for user %s...", username);
855 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset);
856 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
857 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
858 write_message (greeter, message, offset);
862 * lightdm_greeter_authenticate_as_guest:
863 * @greeter: A #LightDMGreeter
865 * Starts the authentication procedure for the guest user.
868 lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter)
870 LightDMGreeterPrivate *priv;
871 guint8 message[MAX_MESSAGE_LENGTH];
874 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
876 priv = GET_PRIVATE (greeter);
878 g_return_if_fail (priv->connected);
880 priv->cancelling_authentication = FALSE;
881 priv->authenticate_sequence_number++;
882 priv->in_authentication = TRUE;
883 priv->is_authenticated = FALSE;
884 g_free (priv->authentication_user);
885 priv->authentication_user = NULL;
887 g_debug ("Starting authentication for guest account...");
888 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset);
889 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
890 write_message (greeter, message, offset);
894 * lightdm_greeter_authenticate_autologin:
895 * @greeter: A #LightDMGreeter
897 * Starts the authentication procedure for the automatic login user.
900 lightdm_greeter_authenticate_autologin (LightDMGreeter *greeter)
904 user = lightdm_greeter_get_autologin_user_hint (greeter);
905 if (lightdm_greeter_get_autologin_guest_hint (greeter))
906 lightdm_greeter_authenticate_as_guest (greeter);
908 lightdm_greeter_authenticate (greeter, user);
912 * lightdm_greeter_authenticate_remote:
913 * @greeter: A #LightDMGreeter
914 * @session: The name of a remote session
915 * @username: (allow-none): A username of #NULL to prompt for a username.
917 * Start authentication for a remote session type.
920 lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *session, const gchar *username)
922 LightDMGreeterPrivate *priv;
923 guint8 message[MAX_MESSAGE_LENGTH];
926 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
928 priv = GET_PRIVATE (greeter);
930 g_return_if_fail (priv->connected);
932 priv->cancelling_authentication = FALSE;
933 priv->authenticate_sequence_number++;
934 priv->in_authentication = TRUE;
935 priv->is_authenticated = FALSE;
936 g_free (priv->authentication_user);
937 priv->authentication_user = NULL;
940 g_debug ("Starting authentication for remote session %s as user %s...", session, username);
942 g_debug ("Starting authentication for remote session %s...", session);
943 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_REMOTE, int_length () + string_length (session) + string_length (username), &offset);
944 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
945 write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
946 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
947 write_message (greeter, message, offset);
951 * lightdm_greeter_respond:
952 * @greeter: A #LightDMGreeter
953 * @response: Response to a prompt
955 * Provide response to a prompt. May be one in a series.
958 lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response)
960 LightDMGreeterPrivate *priv;
961 guint8 message[MAX_MESSAGE_LENGTH];
964 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
965 g_return_if_fail (response != NULL);
967 priv = GET_PRIVATE (greeter);
969 g_return_if_fail (priv->connected);
970 g_return_if_fail (priv->n_responses_waiting > 0);
972 priv->n_responses_waiting--;
973 priv->responses_received = g_list_append (priv->responses_received, g_strdup (response));
975 if (priv->n_responses_waiting == 0)
980 g_debug ("Providing response to display manager");
982 msg_length = int_length ();
983 for (iter = priv->responses_received; iter; iter = iter->next)
985 msg_length += string_length ((gchar *)iter->data);
988 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, msg_length, &offset);
989 write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset);
990 for (iter = priv->responses_received; iter; iter = iter->next)
992 write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset);
994 write_message (greeter, message, offset);
996 g_list_free_full (priv->responses_received, g_free);
997 priv->responses_received = NULL;
1002 * lightdm_greeter_cancel_authentication:
1003 * @greeter: A #LightDMGreeter
1005 * Cancel the current user authentication.
1008 lightdm_greeter_cancel_authentication (LightDMGreeter *greeter)
1010 LightDMGreeterPrivate *priv;
1011 guint8 message[MAX_MESSAGE_LENGTH];
1014 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1016 priv = GET_PRIVATE (greeter);
1018 g_return_if_fail (priv->connected);
1020 priv->cancelling_authentication = TRUE;
1021 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
1022 write_message (greeter, message, offset);
1026 * lightdm_greeter_get_in_authentication:
1027 * @greeter: A #LightDMGreeter
1029 * Checks if the greeter is in the process of authenticating.
1031 * Return value: #TRUE if the greeter is authenticating a user.
1034 lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
1036 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1037 return GET_PRIVATE (greeter)->in_authentication;
1041 * lightdm_greeter_get_is_authenticated:
1042 * @greeter: A #LightDMGreeter
1044 * Checks if the greeter has successfully authenticated.
1046 * Return value: #TRUE if the greeter is authenticated for login.
1049 lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
1051 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1052 return GET_PRIVATE (greeter)->is_authenticated;
1056 * lightdm_greeter_get_authentication_user:
1057 * @greeter: A #LightDMGreeter
1059 * Get the user that is being authenticated.
1061 * Return value: The username of the authentication user being authenticated or #NULL if no authentication in progress.
1064 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
1066 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1067 return GET_PRIVATE (greeter)->authentication_user;
1071 * lightdm_greeter_set_language:
1072 * @greeter: A #LightDMGreeter
1073 * @language: The language to use for this user in the form of a locale specification (e.g. "de_DE.UTF-8").
1075 * Set the language for the currently authenticated user.
1078 lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language)
1080 LightDMGreeterPrivate *priv;
1081 guint8 message[MAX_MESSAGE_LENGTH];
1084 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1086 priv = GET_PRIVATE (greeter);
1088 g_return_if_fail (priv->connected);
1090 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset);
1091 write_string (message, MAX_MESSAGE_LENGTH, language, &offset);
1092 write_message (greeter, message, offset);
1096 * lightdm_greeter_set_resettable:
1097 * @greeter: A #LightDMGreeter
1098 * @resettable: Whether the greeter wants to be reset instead of killed after the user logs in
1100 * Set whether the greeter will be reset instead of killed after the user logs in.
1103 lightdm_greeter_set_resettable (LightDMGreeter *greeter, gboolean resettable)
1105 LightDMGreeterPrivate *priv;
1106 guint8 message[MAX_MESSAGE_LENGTH];
1109 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1111 priv = GET_PRIVATE (greeter);
1113 g_return_if_fail (priv->connected);
1115 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_RESETTABLE, int_length (), &offset);
1116 write_int (message, MAX_MESSAGE_LENGTH, resettable ? 1 : 0, &offset);
1117 write_message (greeter, message, offset);
1121 * lightdm_greeter_start_session_sync:
1122 * @greeter: A #LightDMGreeter
1123 * @session: (allow-none): The session to log into or #NULL to use the default.
1124 * @error: return location for a #GError, or %NULL
1126 * Start a session for the authenticated user.
1128 * Return value: TRUE if the session was started.
1131 lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
1133 LightDMGreeterPrivate *priv;
1134 guint8 message[MAX_MESSAGE_LENGTH];
1136 gsize response_length, offset = 0;
1137 guint32 id, return_code = 1;
1139 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1141 priv = GET_PRIVATE (greeter);
1143 g_return_val_if_fail (priv->connected, FALSE);
1144 g_return_val_if_fail (priv->is_authenticated, FALSE);
1147 g_debug ("Starting session %s", session);
1149 g_debug ("Starting default session");
1151 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
1152 write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
1153 write_message (greeter, message, offset);
1155 response = read_message (greeter, &response_length, TRUE);
1160 id = read_int (response, response_length, &offset);
1161 read_int (response, response_length, &offset);
1162 if (id == SERVER_MESSAGE_SESSION_RESULT)
1163 return_code = read_int (response, response_length, &offset);
1165 g_warning ("Expected SESSION_RESULT message, got %d", id);
1169 return return_code == 0;
1173 * lightdm_greeter_ensure_shared_data_dir_sync:
1174 * @greeter: A #LightDMGreeter
1175 * @username: A username
1177 * Ensure that a shared data dir for the given user is available. Both the
1178 * greeter user and @username will have write access to that folder. The
1179 * intention is that larger pieces of shared data would be stored there (files
1180 * that the greeter creates but wants to give to a user -- like camera
1181 * photos -- or files that the user creates but wants the greeter to
1182 * see -- like contact avatars).
1184 * LightDM will automatically create these if the user actually logs in, so
1185 * greeters only need to call this method if they want to store something in
1186 * the directory themselves.
1188 * Return value: The path to the shared directory, free with g_free
1191 lightdm_greeter_ensure_shared_data_dir_sync (LightDMGreeter *greeter, const gchar *username)
1193 LightDMGreeterPrivate *priv;
1194 guint8 message[MAX_MESSAGE_LENGTH];
1196 gsize response_length, offset = 0;
1198 gchar *data_dir = NULL;
1200 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1202 priv = GET_PRIVATE (greeter);
1204 g_return_val_if_fail (priv->connected, NULL);
1206 g_debug ("Ensuring data directory for user %s", username);
1208 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_ENSURE_SHARED_DIR, string_length (username), &offset);
1209 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
1210 write_message (greeter, message, offset);
1212 response = read_message (greeter, &response_length, TRUE);
1217 id = read_int (response, response_length, &offset);
1218 read_int (response, response_length, &offset);
1219 if (id == SERVER_MESSAGE_SHARED_DIR_RESULT)
1220 data_dir = read_string (response, response_length, &offset);
1222 g_warning ("Expected SHARED_DIR_RESULT message, got %d", id);
1224 /* Blank data dir means invalid user */
1225 if (g_strcmp0 (data_dir, "") == 0)
1237 lightdm_greeter_init (LightDMGreeter *greeter)
1239 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1241 priv->read_buffer = g_malloc (HEADER_SIZE);
1242 priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1246 lightdm_greeter_set_property (GObject *object,
1248 const GValue *value,
1251 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1255 lightdm_greeter_get_property (GObject *object,
1260 LightDMGreeter *self;
1262 self = LIGHTDM_GREETER (object);
1265 case PROP_DEFAULT_SESSION_HINT:
1266 g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
1268 case PROP_HIDE_USERS_HINT:
1269 g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
1271 case PROP_SHOW_MANUAL_LOGIN_HINT:
1272 g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
1274 case PROP_SHOW_REMOTE_LOGIN_HINT:
1275 g_value_set_boolean (value, lightdm_greeter_get_show_remote_login_hint (self));
1277 case PROP_LOCK_HINT:
1278 g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
1280 case PROP_HAS_GUEST_ACCOUNT_HINT:
1281 g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
1283 case PROP_SELECT_USER_HINT:
1284 g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
1286 case PROP_SELECT_GUEST_HINT:
1287 g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
1289 case PROP_AUTOLOGIN_USER_HINT:
1290 g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
1292 case PROP_AUTOLOGIN_GUEST_HINT:
1293 g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
1295 case PROP_AUTOLOGIN_TIMEOUT_HINT:
1296 g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
1298 case PROP_AUTHENTICATION_USER:
1299 g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
1301 case PROP_IN_AUTHENTICATION:
1302 g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
1304 case PROP_IS_AUTHENTICATED:
1305 g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
1308 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1314 lightdm_greeter_finalize (GObject *object)
1316 LightDMGreeter *self = LIGHTDM_GREETER (object);
1317 LightDMGreeterPrivate *priv = GET_PRIVATE (self);
1319 if (priv->to_server_channel)
1320 g_io_channel_unref (priv->to_server_channel);
1321 if (priv->from_server_channel)
1322 g_io_channel_unref (priv->from_server_channel);
1323 g_free (priv->authentication_user);
1324 g_hash_table_unref (priv->hints);
1326 G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
1330 lightdm_greeter_class_init (LightDMGreeterClass *klass)
1332 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1334 g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
1336 object_class->set_property = lightdm_greeter_set_property;
1337 object_class->get_property = lightdm_greeter_get_property;
1338 object_class->finalize = lightdm_greeter_finalize;
1340 g_object_class_install_property (object_class,
1341 PROP_DEFAULT_SESSION_HINT,
1342 g_param_spec_string ("default-session-hint",
1343 "default-session-hint",
1344 "Default session hint",
1346 G_PARAM_READWRITE));
1348 g_object_class_install_property (object_class,
1349 PROP_HIDE_USERS_HINT,
1350 g_param_spec_boolean ("hide-users-hint",
1356 g_object_class_install_property (object_class,
1357 PROP_SHOW_MANUAL_LOGIN_HINT,
1358 g_param_spec_boolean ("show-manual-login-hint",
1359 "show-manual-login-hint",
1360 "Show manual login hint",
1364 g_object_class_install_property (object_class,
1365 PROP_SHOW_REMOTE_LOGIN_HINT,
1366 g_param_spec_boolean ("show-remote-login-hint",
1367 "show-remote-login-hint",
1368 "Show remote login hint",
1372 g_object_class_install_property (object_class,
1374 g_param_spec_boolean ("lock-hint",
1380 g_object_class_install_property (object_class,
1381 PROP_HAS_GUEST_ACCOUNT_HINT,
1382 g_param_spec_boolean ("has-guest-account-hint",
1383 "has-guest-account-hint",
1384 "Has guest account hint",
1388 g_object_class_install_property (object_class,
1389 PROP_SELECT_USER_HINT,
1390 g_param_spec_string ("select-user-hint",
1396 g_object_class_install_property (object_class,
1397 PROP_SELECT_GUEST_HINT,
1398 g_param_spec_boolean ("select-guest-hint",
1399 "select-guest-hint",
1400 "Select guest account hint",
1404 g_object_class_install_property (object_class,
1405 PROP_AUTOLOGIN_USER_HINT,
1406 g_param_spec_string ("autologin-user-hint",
1407 "autologin-user-hint",
1408 "Autologin user hint",
1412 g_object_class_install_property (object_class,
1413 PROP_AUTOLOGIN_GUEST_HINT,
1414 g_param_spec_boolean ("autologin-guest-hint",
1415 "autologin-guest-hint",
1416 "Autologin guest account hint",
1420 g_object_class_install_property (object_class,
1421 PROP_AUTOLOGIN_TIMEOUT_HINT,
1422 g_param_spec_int ("autologin-timeout-hint",
1423 "autologin-timeout-hint",
1424 "Autologin timeout hint",
1428 g_object_class_install_property (object_class,
1429 PROP_AUTHENTICATION_USER,
1430 g_param_spec_string ("authentication-user",
1431 "authentication-user",
1432 "The user being authenticated",
1435 g_object_class_install_property (object_class,
1436 PROP_IN_AUTHENTICATION,
1437 g_param_spec_boolean ("in-authentication",
1438 "in-authentication",
1439 "TRUE if a user is being authenticated",
1442 g_object_class_install_property (object_class,
1443 PROP_IS_AUTHENTICATED,
1444 g_param_spec_boolean ("is-authenticated",
1446 "TRUE if the selected user is authenticated",
1451 * LightDMGreeter::show-prompt:
1452 * @greeter: A #LightDMGreeter
1453 * @text: Prompt text
1454 * @type: Prompt type
1456 * The ::show-prompt signal gets emitted when the greeter should show a
1457 * prompt to the user. The given text should be displayed and an input
1458 * field for the user to provide a response.
1460 * Call lightdm_greeter_respond() with the resultant input or
1461 * lightdm_greeter_cancel_authentication() to abort the authentication.
1463 signals[SHOW_PROMPT] =
1464 g_signal_new ("show-prompt",
1465 G_TYPE_FROM_CLASS (klass),
1467 G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
1470 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1473 * LightDMGreeter::show-message:
1474 * @greeter: A #LightDMGreeter
1475 * @text: Message text
1476 * @type: Message type
1478 * The ::show-message signal gets emitted when the greeter
1479 * should show a message to the user.
1481 signals[SHOW_MESSAGE] =
1482 g_signal_new ("show-message",
1483 G_TYPE_FROM_CLASS (klass),
1485 G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
1488 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1491 * LightDMGreeter::authentication-complete:
1492 * @greeter: A #LightDMGreeter
1494 * The ::authentication-complete signal gets emitted when the greeter
1495 * has completed authentication.
1497 * Call lightdm_greeter_get_is_authenticated() to check if the authentication
1500 signals[AUTHENTICATION_COMPLETE] =
1501 g_signal_new ("authentication-complete",
1502 G_TYPE_FROM_CLASS (klass),
1504 G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
1510 * LightDMGreeter::autologin-timer-expired:
1511 * @greeter: A #LightDMGreeter
1513 * The ::timed-login signal gets emitted when the automatic login timer has expired.
1514 * The application should then call lightdm_greeter_login().
1516 signals[AUTOLOGIN_TIMER_EXPIRED] =
1517 g_signal_new ("autologin-timer-expired",
1518 G_TYPE_FROM_CLASS (klass),
1520 G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),
1526 * LightDMGreeter::idle:
1527 * @greeter: A #LightDMGreeter
1529 * The ::idle signal gets emitted when the user has logged in and the
1530 * greeter is no longer needed.
1532 * This signal only matters if the greeter has marked itself as
1533 * resettable using lightdm_greeter_set_resettable().
1536 g_signal_new ("idle",
1537 G_TYPE_FROM_CLASS (klass),
1539 G_STRUCT_OFFSET (LightDMGreeterClass, idle),
1545 * LightDMGreeter::reset:
1546 * @greeter: A #LightDMGreeter
1548 * The ::reset signal gets emitted when the user is returning to a greeter
1549 * that was previously marked idle.
1551 * This signal only matters if the greeter has marked itself as
1552 * resettable using lightdm_greeter_set_resettable().
1555 g_signal_new ("reset",
1556 G_TYPE_FROM_CLASS (klass),
1558 G_STRUCT_OFFSET (LightDMGreeterClass, reset),