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,
44 static guint signals[LAST_SIGNAL] = { 0 };
50 GIOChannel *to_server_channel, *from_server_channel;
54 gsize n_responses_waiting;
55 GList *responses_received;
58 guint autologin_timeout;
60 gchar *authentication_user;
61 gboolean in_authentication;
62 gboolean is_authenticated;
63 guint32 authenticate_sequence_number;
64 gboolean cancelling_authentication;
65 } LightDMGreeterPrivate;
67 G_DEFINE_TYPE (LightDMGreeter, lightdm_greeter, G_TYPE_OBJECT);
69 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_GREETER, LightDMGreeterPrivate)
72 #define MAX_MESSAGE_LENGTH 1024
74 /* Messages from the greeter to the server */
77 GREETER_MESSAGE_CONNECT = 0,
78 GREETER_MESSAGE_AUTHENTICATE,
79 GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
80 GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
81 GREETER_MESSAGE_START_SESSION,
82 GREETER_MESSAGE_CANCEL_AUTHENTICATION,
83 GREETER_MESSAGE_SET_LANGUAGE,
84 GREETER_MESSAGE_AUTHENTICATE_REMOTE,
85 GREETER_MESSAGE_ENSURE_SHARED_DIR,
88 /* Messages from the server to the greeter */
91 SERVER_MESSAGE_CONNECTED = 0,
92 SERVER_MESSAGE_PROMPT_AUTHENTICATION,
93 SERVER_MESSAGE_END_AUTHENTICATION,
94 SERVER_MESSAGE_SESSION_RESULT
98 * lightdm_greeter_new:
100 * Create a new greeter.
102 * Return value: the new #LightDMGreeter
105 lightdm_greeter_new ()
107 return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
111 timed_login_cb (gpointer data)
113 LightDMGreeter *greeter = data;
114 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
116 priv->autologin_timeout = 0;
117 g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
129 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
131 if (*offset + 4 >= buffer_length)
133 buffer[*offset] = value >> 24;
134 buffer[*offset+1] = (value >> 16) & 0xFF;
135 buffer[*offset+2] = (value >> 8) & 0xFF;
136 buffer[*offset+3] = value & 0xFF;
141 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
146 length = strlen (value);
147 write_int (buffer, buffer_length, length, offset);
148 if (*offset + length >= buffer_length)
150 memcpy (buffer + *offset, value, length);
155 read_int (guint8 *message, gsize message_length, gsize *offset)
160 if (message_length - *offset < int_length ())
162 g_warning ("Not enough space for int, need %i, got %zi", int_length (), message_length - *offset);
166 buffer = message + *offset;
167 value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
168 *offset += int_length ();
174 read_string (guint8 *message, gsize message_length, gsize *offset)
179 length = read_int (message, message_length, offset);
180 if (message_length - *offset < length)
182 g_warning ("Not enough space for string, need %u, got %zu", length, message_length - *offset);
183 return g_strdup ("");
186 value = g_malloc (sizeof (gchar) * (length + 1));
187 memcpy (value, message + *offset, length);
188 value[length] = '\0';
195 string_length (const gchar *value)
198 return int_length () + strlen (value);
200 return int_length ();
204 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
206 write_int (buffer, buffer_length, id, offset);
207 write_int (buffer, buffer_length, length, offset);
211 get_message_length (guint8 *message, gsize message_length)
214 return read_int (message, message_length, &offset);
218 write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
220 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
222 GError *error = NULL;
223 guint32 stated_length;
225 /* Double check that we're sending well-formed messages. If we say we're
226 sending more than we do, we end up DOS'ing lightdm as it waits for the
227 rest. If we say we're sending less than we do, we confuse the heck out
228 of lightdm, as it starts reading headers from the middle of our
230 stated_length = HEADER_SIZE + get_message_length (message, message_length);
231 if (stated_length != message_length)
233 g_warning ("Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu", stated_length, message_length);
237 status = g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, &error);
239 g_warning ("Error writing to daemon: %s", error->message);
240 g_clear_error (&error);
241 if (status == G_IO_STATUS_NORMAL)
242 g_debug ("Wrote %zi bytes to daemon", message_length);
243 g_io_channel_flush (priv->to_server_channel, NULL);
247 handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
249 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
251 GString *hint_string;
254 version = read_string (message, message_length, offset);
255 hint_string = g_string_new ("");
256 while (*offset < message_length)
260 name = read_string (message, message_length, offset);
261 value = read_string (message, message_length, offset);
262 g_hash_table_insert (priv->hints, name, value);
263 g_string_append_printf (hint_string, " %s=%s", name, value);
266 g_debug ("Connected version=%s%s", version, hint_string->str);
268 g_string_free (hint_string, TRUE);
270 /* Set timeout for default login */
271 timeout = lightdm_greeter_get_autologin_timeout_hint (greeter);
274 g_debug ("Setting autologin timer for %d seconds", timeout);
275 priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
280 handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
282 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
283 guint32 sequence_number, n_messages, i;
286 sequence_number = read_int (message, message_length, offset);
287 if (sequence_number != priv->authenticate_sequence_number)
289 g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
293 if (priv->cancelling_authentication)
295 g_debug ("Ignoring prompt authentication as waiting for it to cancel");
299 /* Update username */
300 username = read_string (message, message_length, offset);
301 if (strcmp (username, "") == 0)
306 g_free (priv->authentication_user);
307 priv->authentication_user = username;
309 g_list_free_full (priv->responses_received, g_free);
310 priv->responses_received = NULL;
311 priv->n_responses_waiting = 0;
313 n_messages = read_int (message, message_length, offset);
314 g_debug ("Prompt user with %d message(s)", n_messages);
316 for (i = 0; i < n_messages; i++)
321 style = read_int (message, message_length, offset);
322 text = read_string (message, message_length, offset);
324 // FIXME: Should stop on prompts?
327 case PAM_PROMPT_ECHO_OFF:
328 priv->n_responses_waiting++;
329 g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_SECRET);
331 case PAM_PROMPT_ECHO_ON:
332 priv->n_responses_waiting++;
333 g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_QUESTION);
336 g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_ERROR);
339 g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_INFO);
348 handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
350 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
351 guint32 sequence_number, return_code;
354 sequence_number = read_int (message, message_length, offset);
356 if (sequence_number != priv->authenticate_sequence_number)
358 g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
362 username = read_string (message, message_length, offset);
363 return_code = read_int (message, message_length, offset);
365 g_debug ("Authentication complete for user %s with return code %d", username, return_code);
367 /* Update username */
368 if (strcmp (username, "") == 0)
373 g_free (priv->authentication_user);
374 priv->authentication_user = username;
376 priv->cancelling_authentication = FALSE;
377 priv->is_authenticated = (return_code == 0);
379 priv->in_authentication = FALSE;
380 g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
384 read_message (LightDMGreeter *greeter, gsize *length, gboolean block)
386 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
387 gsize n_to_read, n_read;
389 GError *error = NULL;
391 /* Read the header, or the whole message if we already have that */
392 n_to_read = HEADER_SIZE;
393 if (priv->n_read >= HEADER_SIZE)
394 n_to_read += get_message_length (priv->read_buffer, priv->n_read);
399 status = g_io_channel_read_chars (priv->from_server_channel,
400 (gchar *) priv->read_buffer + priv->n_read,
401 n_to_read - priv->n_read,
405 g_warning ("Error reading from server: %s", error->message);
406 g_clear_error (&error);
407 if (status != G_IO_STATUS_NORMAL)
410 g_debug ("Read %zi bytes from daemon", n_read);
412 priv->n_read += n_read;
413 } while (priv->n_read < n_to_read && block);
415 /* Stop if haven't got all the data we want */
416 if (priv->n_read != n_to_read)
419 /* If have header, rerun for content */
420 if (priv->n_read == HEADER_SIZE)
422 n_to_read = get_message_length (priv->read_buffer, priv->n_read);
425 priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
426 return read_message (greeter, length, block);
430 buffer = priv->read_buffer;
431 *length = priv->n_read;
433 priv->read_buffer = g_malloc (priv->n_read);
440 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
442 LightDMGreeter *greeter = data;
444 gsize message_length, offset;
447 message = read_message (greeter, &message_length, FALSE);
452 id = read_int (message, message_length, &offset);
453 read_int (message, message_length, &offset);
456 case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
457 handle_prompt_authentication (greeter, message, message_length, &offset);
459 case SERVER_MESSAGE_END_AUTHENTICATION:
460 handle_end_authentication (greeter, message, message_length, &offset);
463 g_warning ("Unknown message from server: %d", id);
472 * lightdm_greeter_connect_sync:
473 * @greeter: The greeter to connect
474 * @error: return location for a #GError, or %NULL
476 * Connects the greeter to the display manager. Will block until connected.
478 * Return value: #TRUE if successfully connected
481 lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
483 LightDMGreeterPrivate *priv;
485 guint8 message[MAX_MESSAGE_LENGTH];
487 gsize response_length, offset = 0;
490 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
492 priv = GET_PRIVATE (greeter);
494 fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
497 g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
500 priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
501 g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
503 fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
506 g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
509 priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
510 g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
511 g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
513 g_debug ("Connecting to display manager...");
514 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
515 write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
516 write_message (greeter, message, offset);
518 response = read_message (greeter, &response_length, TRUE);
523 id = read_int (response, response_length, &offset);
524 read_int (response, response_length, &offset);
525 if (id == SERVER_MESSAGE_CONNECTED)
526 handle_connected (greeter, response, response_length, &offset);
528 if (id != SERVER_MESSAGE_CONNECTED)
530 g_warning ("Expected CONNECTED message, got %d", id);
534 priv->connected = TRUE;
540 * lightdm_greeter_get_hint:
541 * @greeter: A #LightDMGreeter
542 * @name: The hint name to query.
546 * Return value: The value for this hint or #NULL if not set.
549 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
551 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
552 return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
556 * lightdm_greeter_get_default_session_hint:
557 * @greeter: A #LightDMGreeter
559 * Get the default session to use.
561 * Return value: The session name
564 lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
566 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
567 return lightdm_greeter_get_hint (greeter, "default-session");
571 * lightdm_greeter_get_hide_users_hint:
572 * @greeter: A #LightDMGreeter
574 * Check if user accounts should be shown. If this is TRUE then the list of
575 * accounts should be taken from #LightDMUserList and displayed in the greeter
576 * for the user to choose from. Note that this list can be empty and it is
577 * recommended you show a method for the user to enter a username manually.
579 * If this option is shown the greeter should only allow these users to be
580 * chosen for login unless the manual login hint is set.
582 * Return value: #TRUE if the available users should not be shown.
585 lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
589 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
590 value = lightdm_greeter_get_hint (greeter, "hide-users");
592 return g_strcmp0 (value, "true") == 0;
596 * lightdm_greeter_get_show_manual_login_hint:
597 * @greeter: A #LightDMGreeter
599 * Check if a manual login option should be shown. If set the GUI
600 * should provide a way for a username to be entered manually.
601 * Without this hint a greeter which is showing a user list can
602 * limit logins to only those users.
604 * Return value: #TRUE if a manual login option should be shown.
607 lightdm_greeter_get_show_manual_login_hint (LightDMGreeter *greeter)
611 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
612 value = lightdm_greeter_get_hint (greeter, "show-manual-login");
614 return g_strcmp0 (value, "true") == 0;
618 * lightdm_greeter_get_show_remote_login_hint:
619 * @greeter: A #LightDMGreeter
621 * Check if a remote login option should be shown. If set the GUI
622 * should provide a way for a user to log into a remote desktop server.
624 * Return value: #TRUE if a remote login option should be shown.
627 lightdm_greeter_get_show_remote_login_hint (LightDMGreeter *greeter)
631 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
632 value = lightdm_greeter_get_hint (greeter, "show-remote-login");
634 return g_strcmp0 (value, "true") == 0;
638 * lightdm_greeter_get_lock_hint:
639 * @greeter: A #LightDMGreeter
641 * Check if the greeter is acting as a lock screen.
643 * Return value: #TRUE if the greeter was triggered by locking the seat.
646 lightdm_greeter_get_lock_hint (LightDMGreeter *greeter)
650 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
651 value = lightdm_greeter_get_hint (greeter, "lock-screen");
653 return g_strcmp0 (value, "true") == 0;
657 * lightdm_greeter_get_has_guest_account_hint:
658 * @greeter: A #LightDMGreeter
660 * Check if guest sessions are supported.
662 * Return value: #TRUE if guest sessions are supported.
665 lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
669 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
670 value = lightdm_greeter_get_hint (greeter, "has-guest-account");
672 return g_strcmp0 (value, "true") == 0;
676 * lightdm_greeter_get_select_user_hint:
677 * @greeter: A #LightDMGreeter
679 * Get the user to select by default.
681 * Return value: A username
684 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
686 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
687 return lightdm_greeter_get_hint (greeter, "select-user");
691 * lightdm_greeter_get_select_guest_hint:
692 * @greeter: A #LightDMGreeter
694 * Check if the guest account should be selected by default.
696 * Return value: #TRUE if the guest account should be selected by default.
699 lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
703 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
704 value = lightdm_greeter_get_hint (greeter, "select-guest");
706 return g_strcmp0 (value, "true") == 0;
710 * lightdm_greeter_get_autologin_user_hint:
711 * @greeter: A #LightDMGreeter
713 * Get the user account to automatically logg into when the timer expires.
715 * Return value: The user account to automatically log into.
718 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
720 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
721 return lightdm_greeter_get_hint (greeter, "autologin-user");
725 * lightdm_greeter_get_autologin_guest_hint:
726 * @greeter: A #LightDMGreeter
728 * Check if the guest account should be automatically logged into when the timer expires.
730 * Return value: #TRUE if the guest account should be automatically logged into.
733 lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
737 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
738 value = lightdm_greeter_get_hint (greeter, "autologin-guest");
740 return g_strcmp0 (value, "true") == 0;
744 * lightdm_greeter_get_autologin_timeout_hint:
745 * @greeter: A #LightDMGreeter
747 * Get the number of seconds to wait before automaitcally logging in.
749 * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
752 lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
757 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
758 value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
760 timeout = atoi (value);
768 * lightdm_greeter_cancel_autologin:
769 * @greeter: A #LightDMGreeter
771 * Cancel the automatic login.
774 lightdm_greeter_cancel_autologin (LightDMGreeter *greeter)
776 LightDMGreeterPrivate *priv;
778 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
780 priv = GET_PRIVATE (greeter);
782 if (priv->autologin_timeout)
783 g_source_remove (priv->autologin_timeout);
784 priv->autologin_timeout = 0;
788 * lightdm_greeter_authenticate:
789 * @greeter: A #LightDMGreeter
790 * @username: (allow-none): A username or #NULL to prompt for a username.
792 * Starts the authentication procedure for a user.
795 lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username)
797 LightDMGreeterPrivate *priv;
798 guint8 message[MAX_MESSAGE_LENGTH];
801 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
803 priv = GET_PRIVATE (greeter);
805 g_return_if_fail (priv->connected);
807 priv->cancelling_authentication = FALSE;
808 priv->authenticate_sequence_number++;
809 priv->in_authentication = TRUE;
810 priv->is_authenticated = FALSE;
811 if (username != priv->authentication_user)
813 g_free (priv->authentication_user);
814 priv->authentication_user = g_strdup (username);
817 g_debug ("Starting authentication for user %s...", username);
818 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset);
819 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
820 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
821 write_message (greeter, message, offset);
825 * lightdm_greeter_authenticate_as_guest:
826 * @greeter: A #LightDMGreeter
828 * Starts the authentication procedure for the guest user.
831 lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter)
833 LightDMGreeterPrivate *priv;
834 guint8 message[MAX_MESSAGE_LENGTH];
837 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
839 priv = GET_PRIVATE (greeter);
841 g_return_if_fail (priv->connected);
843 priv->cancelling_authentication = FALSE;
844 priv->authenticate_sequence_number++;
845 priv->in_authentication = TRUE;
846 priv->is_authenticated = FALSE;
847 g_free (priv->authentication_user);
848 priv->authentication_user = NULL;
850 g_debug ("Starting authentication for guest account...");
851 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset);
852 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
853 write_message (greeter, message, offset);
857 * lightdm_greeter_authenticate_autologin:
858 * @greeter: A #LightDMGreeter
860 * Starts the authentication procedure for the automatic login user.
863 lightdm_greeter_authenticate_autologin (LightDMGreeter *greeter)
867 user = lightdm_greeter_get_autologin_user_hint (greeter);
868 if (lightdm_greeter_get_autologin_guest_hint (greeter))
869 lightdm_greeter_authenticate_as_guest (greeter);
871 lightdm_greeter_authenticate (greeter, user);
875 * lightdm_greeter_authenticate_remote:
876 * @greeter: A #LightDMGreeter
877 * @session: The name of a remote session
878 * @username: (allow-none): A username of #NULL to prompt for a username.
880 * Start authentication for a remote session type.
883 lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *session, const gchar *username)
885 LightDMGreeterPrivate *priv;
886 guint8 message[MAX_MESSAGE_LENGTH];
889 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
891 priv = GET_PRIVATE (greeter);
893 g_return_if_fail (priv->connected);
895 priv->cancelling_authentication = FALSE;
896 priv->authenticate_sequence_number++;
897 priv->in_authentication = TRUE;
898 priv->is_authenticated = FALSE;
899 g_free (priv->authentication_user);
900 priv->authentication_user = NULL;
903 g_debug ("Starting authentication for remote session %s as user %s...", session, username);
905 g_debug ("Starting authentication for remote session %s...", session);
906 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_REMOTE, int_length () + string_length (session) + string_length (username), &offset);
907 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
908 write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
909 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
910 write_message (greeter, message, offset);
914 * lightdm_greeter_respond:
915 * @greeter: A #LightDMGreeter
916 * @response: Response to a prompt
918 * Provide response to a prompt. May be one in a series.
921 lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response)
923 LightDMGreeterPrivate *priv;
924 guint8 message[MAX_MESSAGE_LENGTH];
927 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
928 g_return_if_fail (response != NULL);
930 priv = GET_PRIVATE (greeter);
932 g_return_if_fail (priv->connected);
933 g_return_if_fail (priv->n_responses_waiting > 0);
935 priv->n_responses_waiting--;
936 priv->responses_received = g_list_append (priv->responses_received, g_strdup (response));
938 if (priv->n_responses_waiting == 0)
943 g_debug ("Providing response to display manager");
945 msg_length = int_length ();
946 for (iter = priv->responses_received; iter; iter = iter->next)
948 msg_length += string_length ((gchar *)iter->data);
951 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, msg_length, &offset);
952 write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset);
953 for (iter = priv->responses_received; iter; iter = iter->next)
955 write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset);
957 write_message (greeter, message, offset);
959 g_list_free_full (priv->responses_received, g_free);
960 priv->responses_received = NULL;
965 * lightdm_greeter_cancel_authentication:
966 * @greeter: A #LightDMGreeter
968 * Cancel the current user authentication.
971 lightdm_greeter_cancel_authentication (LightDMGreeter *greeter)
973 LightDMGreeterPrivate *priv;
974 guint8 message[MAX_MESSAGE_LENGTH];
977 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
979 priv = GET_PRIVATE (greeter);
981 g_return_if_fail (priv->connected);
983 priv->cancelling_authentication = TRUE;
984 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
985 write_message (greeter, message, offset);
989 * lightdm_greeter_get_in_authentication:
990 * @greeter: A #LightDMGreeter
992 * Checks if the greeter is in the process of authenticating.
994 * Return value: #TRUE if the greeter is authenticating a user.
997 lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
999 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1000 return GET_PRIVATE (greeter)->in_authentication;
1004 * lightdm_greeter_get_is_authenticated:
1005 * @greeter: A #LightDMGreeter
1007 * Checks if the greeter has successfully authenticated.
1009 * Return value: #TRUE if the greeter is authenticated for login.
1012 lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
1014 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1015 return GET_PRIVATE (greeter)->is_authenticated;
1019 * lightdm_greeter_get_authentication_user:
1020 * @greeter: A #LightDMGreeter
1022 * Get the user that is being authenticated.
1024 * Return value: The username of the authentication user being authenticated or #NULL if no authentication in progress.
1027 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
1029 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1030 return GET_PRIVATE (greeter)->authentication_user;
1034 * lightdm_greeter_set_language:
1035 * @greeter: A #LightDMGreeter
1036 * @language: The language to use for this user in the form of a locale specification (e.g. "de_DE.UTF-8").
1038 * Set the language for the currently authenticated user.
1041 lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language)
1043 LightDMGreeterPrivate *priv;
1044 guint8 message[MAX_MESSAGE_LENGTH];
1047 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1049 priv = GET_PRIVATE (greeter);
1051 g_return_if_fail (priv->connected);
1053 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset);
1054 write_string (message, MAX_MESSAGE_LENGTH, language, &offset);
1055 write_message (greeter, message, offset);
1059 * lightdm_greeter_start_session_sync:
1060 * @greeter: A #LightDMGreeter
1061 * @session: (allow-none): The session to log into or #NULL to use the default.
1062 * @error: return location for a #GError, or %NULL
1064 * Start a session for the authenticated user.
1066 * Return value: TRUE if the session was started.
1069 lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
1071 LightDMGreeterPrivate *priv;
1072 guint8 message[MAX_MESSAGE_LENGTH];
1074 gsize response_length, offset = 0;
1075 guint32 id, return_code = 1;
1077 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1079 priv = GET_PRIVATE (greeter);
1081 g_return_val_if_fail (priv->connected, FALSE);
1082 g_return_val_if_fail (priv->is_authenticated, FALSE);
1085 g_debug ("Starting session %s", session);
1087 g_debug ("Starting default session");
1089 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
1090 write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
1091 write_message (greeter, message, offset);
1093 response = read_message (greeter, &response_length, TRUE);
1098 id = read_int (response, response_length, &offset);
1099 read_int (response, response_length, &offset);
1100 if (id == SERVER_MESSAGE_SESSION_RESULT)
1101 return_code = read_int (response, response_length, &offset);
1103 g_warning ("Expected SESSION_RESULT message, got %d", id);
1107 return return_code == 0;
1111 * lightdm_greeter_ensure_shared_data_dir:
1112 * @greeter: A #LightDMGreeter
1113 * @username: A username
1115 * Ensure that a shared data dir for the given user is available. This will
1116 * be created at /var/lib/lightdm-data/@username. Both the greeter user and
1117 * @username will have write access to that folder. The intention is that
1118 * larger pieces of shared data would be stored there (files that the greeter
1119 * creates but wants to give to a user -- like camera photos -- or files that
1120 * the user creates but wants the greeter to see -- like contact avatars).
1122 * LightDM will automatically create these if the user actually logs in, so
1123 * greeters only need to call this method if they want to store something in
1124 * the directory themselves.
1127 lightdm_greeter_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username)
1129 LightDMGreeterPrivate *priv;
1130 guint8 message[MAX_MESSAGE_LENGTH];
1133 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1135 priv = GET_PRIVATE (greeter);
1137 g_return_if_fail (priv->connected);
1139 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_ENSURE_SHARED_DIR, string_length (username), &offset);
1140 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
1141 write_message (greeter, message, offset);
1145 lightdm_greeter_init (LightDMGreeter *greeter)
1147 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1149 priv->read_buffer = g_malloc (HEADER_SIZE);
1150 priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1154 lightdm_greeter_set_property (GObject *object,
1156 const GValue *value,
1159 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1163 lightdm_greeter_get_property (GObject *object,
1168 LightDMGreeter *self;
1170 self = LIGHTDM_GREETER (object);
1173 case PROP_DEFAULT_SESSION_HINT:
1174 g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
1176 case PROP_HIDE_USERS_HINT:
1177 g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
1179 case PROP_SHOW_MANUAL_LOGIN_HINT:
1180 g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
1182 case PROP_SHOW_REMOTE_LOGIN_HINT:
1183 g_value_set_boolean (value, lightdm_greeter_get_show_remote_login_hint (self));
1185 case PROP_LOCK_HINT:
1186 g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
1188 case PROP_HAS_GUEST_ACCOUNT_HINT:
1189 g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
1191 case PROP_SELECT_USER_HINT:
1192 g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
1194 case PROP_SELECT_GUEST_HINT:
1195 g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
1197 case PROP_AUTOLOGIN_USER_HINT:
1198 g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
1200 case PROP_AUTOLOGIN_GUEST_HINT:
1201 g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
1203 case PROP_AUTOLOGIN_TIMEOUT_HINT:
1204 g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
1206 case PROP_AUTHENTICATION_USER:
1207 g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
1209 case PROP_IN_AUTHENTICATION:
1210 g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
1212 case PROP_IS_AUTHENTICATED:
1213 g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
1216 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1222 lightdm_greeter_finalize (GObject *object)
1224 LightDMGreeter *self = LIGHTDM_GREETER (object);
1225 LightDMGreeterPrivate *priv = GET_PRIVATE (self);
1227 if (priv->to_server_channel)
1228 g_io_channel_unref (priv->to_server_channel);
1229 if (priv->from_server_channel)
1230 g_io_channel_unref (priv->from_server_channel);
1231 g_free (priv->authentication_user);
1232 g_hash_table_unref (priv->hints);
1234 G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
1238 lightdm_greeter_class_init (LightDMGreeterClass *klass)
1240 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1242 g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
1244 object_class->set_property = lightdm_greeter_set_property;
1245 object_class->get_property = lightdm_greeter_get_property;
1246 object_class->finalize = lightdm_greeter_finalize;
1248 g_object_class_install_property (object_class,
1249 PROP_DEFAULT_SESSION_HINT,
1250 g_param_spec_string ("default-session-hint",
1251 "default-session-hint",
1252 "Default session hint",
1254 G_PARAM_READWRITE));
1256 g_object_class_install_property (object_class,
1257 PROP_HIDE_USERS_HINT,
1258 g_param_spec_boolean ("hide-users-hint",
1264 g_object_class_install_property (object_class,
1265 PROP_SHOW_MANUAL_LOGIN_HINT,
1266 g_param_spec_boolean ("show-manual-login-hint",
1267 "show-manual-login-hint",
1268 "Show manual login hint",
1272 g_object_class_install_property (object_class,
1273 PROP_SHOW_REMOTE_LOGIN_HINT,
1274 g_param_spec_boolean ("show-remote-login-hint",
1275 "show-remote-login-hint",
1276 "Show remote login hint",
1280 g_object_class_install_property (object_class,
1282 g_param_spec_boolean ("lock-hint",
1288 g_object_class_install_property (object_class,
1289 PROP_HAS_GUEST_ACCOUNT_HINT,
1290 g_param_spec_boolean ("has-guest-account-hint",
1291 "has-guest-account-hint",
1292 "Has guest account hint",
1296 g_object_class_install_property (object_class,
1297 PROP_SELECT_USER_HINT,
1298 g_param_spec_string ("select-user-hint",
1304 g_object_class_install_property (object_class,
1305 PROP_SELECT_GUEST_HINT,
1306 g_param_spec_boolean ("select-guest-hint",
1307 "select-guest-hint",
1308 "Select guest account hint",
1312 g_object_class_install_property (object_class,
1313 PROP_AUTOLOGIN_USER_HINT,
1314 g_param_spec_string ("autologin-user-hint",
1315 "autologin-user-hint",
1316 "Autologin user hint",
1320 g_object_class_install_property (object_class,
1321 PROP_AUTOLOGIN_GUEST_HINT,
1322 g_param_spec_boolean ("autologin-guest-hint",
1323 "autologin-guest-hint",
1324 "Autologin guest account hint",
1328 g_object_class_install_property (object_class,
1329 PROP_AUTOLOGIN_TIMEOUT_HINT,
1330 g_param_spec_int ("autologin-timeout-hint",
1331 "autologin-timeout-hint",
1332 "Autologin timeout hint",
1336 g_object_class_install_property (object_class,
1337 PROP_AUTHENTICATION_USER,
1338 g_param_spec_string ("authentication-user",
1339 "authentication-user",
1340 "The user being authenticated",
1343 g_object_class_install_property (object_class,
1344 PROP_IN_AUTHENTICATION,
1345 g_param_spec_boolean ("in-authentication",
1346 "in-authentication",
1347 "TRUE if a user is being authenticated",
1350 g_object_class_install_property (object_class,
1351 PROP_IS_AUTHENTICATED,
1352 g_param_spec_boolean ("is-authenticated",
1354 "TRUE if the selected user is authenticated",
1359 * LightDMGreeter::show-prompt:
1360 * @greeter: A #LightDMGreeter
1361 * @text: Prompt text
1362 * @type: Prompt type
1364 * The ::show-prompt signal gets emitted when the greeter should show a
1365 * prompt to the user. The given text should be displayed and an input
1366 * field for the user to provide a response.
1368 * Call lightdm_greeter_respond() with the resultant input or
1369 * lightdm_greeter_cancel_authentication() to abort the authentication.
1371 signals[SHOW_PROMPT] =
1372 g_signal_new ("show-prompt",
1373 G_TYPE_FROM_CLASS (klass),
1375 G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
1378 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1381 * LightDMGreeter::show-message:
1382 * @greeter: A #LightDMGreeter
1383 * @text: Message text
1384 * @type: Message type
1386 * The ::show-message signal gets emitted when the greeter
1387 * should show a message to the user.
1389 signals[SHOW_MESSAGE] =
1390 g_signal_new ("show-message",
1391 G_TYPE_FROM_CLASS (klass),
1393 G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
1396 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1399 * LightDMGreeter::authentication-complete:
1400 * @greeter: A #LightDMGreeter
1402 * The ::authentication-complete signal gets emitted when the greeter
1403 * has completed authentication.
1405 * Call lightdm_greeter_get_is_authenticated() to check if the authentication
1408 signals[AUTHENTICATION_COMPLETE] =
1409 g_signal_new ("authentication-complete",
1410 G_TYPE_FROM_CLASS (klass),
1412 G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
1418 * LightDMGreeter::autologin-timer-expired:
1419 * @greeter: A #LightDMGreeter
1421 * The ::timed-login signal gets emitted when the automatic login timer has expired.
1422 * The application should then call lightdm_greeter_login().
1424 signals[AUTOLOGIN_TIMER_EXPIRED] =
1425 g_signal_new ("autologin-timer-expired",
1426 G_TYPE_FROM_CLASS (klass),
1428 G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),