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_START_MIR_SESSION
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_start_mir_session_sync:
1112 * @greeter: A #LightDMGreeter
1113 * @session: (allow-none): The Mir session to log into or #NULL to use the default.
1114 * @error: return location for a #GError, or %NULL
1116 * Start a session for the authenticated user.
1118 * Return value: TRUE if the session was started.
1121 lightdm_greeter_start_mir_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
1123 LightDMGreeterPrivate *priv;
1124 guint8 message[MAX_MESSAGE_LENGTH];
1126 gsize response_length, offset = 0;
1127 guint32 id, return_code = 1;
1129 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1131 priv = GET_PRIVATE (greeter);
1133 g_return_val_if_fail (priv->connected, FALSE);
1134 g_return_val_if_fail (priv->is_authenticated, FALSE);
1137 g_debug ("Starting Mir session %s", session);
1139 g_debug ("Starting default Mir session");
1141 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_MIR_SESSION, string_length (session), &offset);
1142 write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
1143 write_message (greeter, message, offset);
1145 response = read_message (greeter, &response_length, TRUE);
1150 id = read_int (response, response_length, &offset);
1151 read_int (response, response_length, &offset);
1152 if (id == SERVER_MESSAGE_SESSION_RESULT)
1153 return_code = read_int (response, response_length, &offset);
1155 g_warning ("Expected SESSION_RESULT message, got %d", id);
1159 return return_code == 0;
1163 lightdm_greeter_init (LightDMGreeter *greeter)
1165 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1167 priv->read_buffer = g_malloc (HEADER_SIZE);
1168 priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1172 lightdm_greeter_set_property (GObject *object,
1174 const GValue *value,
1177 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1181 lightdm_greeter_get_property (GObject *object,
1186 LightDMGreeter *self;
1188 self = LIGHTDM_GREETER (object);
1191 case PROP_DEFAULT_SESSION_HINT:
1192 g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
1194 case PROP_HIDE_USERS_HINT:
1195 g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
1197 case PROP_SHOW_MANUAL_LOGIN_HINT:
1198 g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
1200 case PROP_SHOW_REMOTE_LOGIN_HINT:
1201 g_value_set_boolean (value, lightdm_greeter_get_show_remote_login_hint (self));
1203 case PROP_LOCK_HINT:
1204 g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
1206 case PROP_HAS_GUEST_ACCOUNT_HINT:
1207 g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
1209 case PROP_SELECT_USER_HINT:
1210 g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
1212 case PROP_SELECT_GUEST_HINT:
1213 g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
1215 case PROP_AUTOLOGIN_USER_HINT:
1216 g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
1218 case PROP_AUTOLOGIN_GUEST_HINT:
1219 g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
1221 case PROP_AUTOLOGIN_TIMEOUT_HINT:
1222 g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
1224 case PROP_AUTHENTICATION_USER:
1225 g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
1227 case PROP_IN_AUTHENTICATION:
1228 g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
1230 case PROP_IS_AUTHENTICATED:
1231 g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
1234 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1240 marshal_VOID__STRING_INT (GClosure *closure,
1241 GValue *return_value G_GNUC_UNUSED,
1242 guint n_param_values,
1243 const GValue *param_values,
1244 gpointer invocation_hint G_GNUC_UNUSED,
1245 gpointer marshal_data)
1247 typedef void (*GMarshalFunc_VOID__STRING_INT) (gpointer data1,
1251 register GMarshalFunc_VOID__STRING_INT callback;
1252 register GCClosure *cc = (GCClosure*) closure;
1253 register gpointer data1, data2;
1255 g_return_if_fail (n_param_values == 3);
1257 if (G_CCLOSURE_SWAP_DATA (closure))
1259 data1 = closure->data;
1260 data2 = g_value_peek_pointer (param_values + 0);
1264 data1 = g_value_peek_pointer (param_values + 0);
1265 data2 = closure->data;
1267 callback = (GMarshalFunc_VOID__STRING_INT) (marshal_data ? marshal_data : cc->callback);
1270 (param_values + 1)->data[0].v_pointer,
1271 (param_values + 2)->data[0].v_int,
1276 lightdm_greeter_finalize (GObject *object)
1278 LightDMGreeter *self = LIGHTDM_GREETER (object);
1279 LightDMGreeterPrivate *priv = GET_PRIVATE (self);
1281 if (priv->to_server_channel)
1282 g_io_channel_unref (priv->to_server_channel);
1283 if (priv->from_server_channel)
1284 g_io_channel_unref (priv->from_server_channel);
1285 g_free (priv->authentication_user);
1286 g_hash_table_unref (priv->hints);
1288 G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
1292 lightdm_greeter_class_init (LightDMGreeterClass *klass)
1294 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1296 g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
1298 object_class->set_property = lightdm_greeter_set_property;
1299 object_class->get_property = lightdm_greeter_get_property;
1300 object_class->finalize = lightdm_greeter_finalize;
1302 g_object_class_install_property (object_class,
1303 PROP_DEFAULT_SESSION_HINT,
1304 g_param_spec_string ("default-session-hint",
1305 "default-session-hint",
1306 "Default session hint",
1308 G_PARAM_READWRITE));
1310 g_object_class_install_property (object_class,
1311 PROP_HIDE_USERS_HINT,
1312 g_param_spec_boolean ("hide-users-hint",
1318 g_object_class_install_property (object_class,
1319 PROP_SHOW_MANUAL_LOGIN_HINT,
1320 g_param_spec_boolean ("show-manual-login-hint",
1321 "show-manual-login-hint",
1322 "Show manual login hint",
1326 g_object_class_install_property (object_class,
1327 PROP_SHOW_REMOTE_LOGIN_HINT,
1328 g_param_spec_boolean ("show-remote-login-hint",
1329 "show-remote-login-hint",
1330 "Show remote login hint",
1334 g_object_class_install_property (object_class,
1336 g_param_spec_boolean ("lock-hint",
1342 g_object_class_install_property (object_class,
1343 PROP_HAS_GUEST_ACCOUNT_HINT,
1344 g_param_spec_boolean ("has-guest-account-hint",
1345 "has-guest-account-hint",
1346 "Has guest account hint",
1350 g_object_class_install_property (object_class,
1351 PROP_SELECT_USER_HINT,
1352 g_param_spec_string ("select-user-hint",
1358 g_object_class_install_property (object_class,
1359 PROP_SELECT_GUEST_HINT,
1360 g_param_spec_boolean ("select-guest-hint",
1361 "select-guest-hint",
1362 "Select guest account hint",
1366 g_object_class_install_property (object_class,
1367 PROP_AUTOLOGIN_USER_HINT,
1368 g_param_spec_string ("autologin-user-hint",
1369 "autologin-user-hint",
1370 "Autologin user hint",
1374 g_object_class_install_property (object_class,
1375 PROP_AUTOLOGIN_GUEST_HINT,
1376 g_param_spec_boolean ("autologin-guest-hint",
1377 "autologin-guest-hint",
1378 "Autologin guest account hint",
1382 g_object_class_install_property (object_class,
1383 PROP_AUTOLOGIN_TIMEOUT_HINT,
1384 g_param_spec_int ("autologin-timeout-hint",
1385 "autologin-timeout-hint",
1386 "Autologin timeout hint",
1390 g_object_class_install_property (object_class,
1391 PROP_AUTHENTICATION_USER,
1392 g_param_spec_string ("authentication-user",
1393 "authentication-user",
1394 "The user being authenticated",
1397 g_object_class_install_property (object_class,
1398 PROP_IN_AUTHENTICATION,
1399 g_param_spec_boolean ("in-authentication",
1400 "in-authentication",
1401 "TRUE if a user is being authenticated",
1404 g_object_class_install_property (object_class,
1405 PROP_IS_AUTHENTICATED,
1406 g_param_spec_boolean ("is-authenticated",
1408 "TRUE if the selected user is authenticated",
1413 * LightDMGreeter::show-prompt:
1414 * @greeter: A #LightDMGreeter
1415 * @text: Prompt text
1416 * @type: Prompt type
1418 * The ::show-prompt signal gets emitted when the greeter should show a
1419 * prompt to the user. The given text should be displayed and an input
1420 * field for the user to provide a response.
1422 * Call lightdm_greeter_respond() with the resultant input or
1423 * lightdm_greeter_cancel_authentication() to abort the authentication.
1425 signals[SHOW_PROMPT] =
1426 g_signal_new ("show-prompt",
1427 G_TYPE_FROM_CLASS (klass),
1429 G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
1431 marshal_VOID__STRING_INT,
1432 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1435 * LightDMGreeter::show-message:
1436 * @greeter: A #LightDMGreeter
1437 * @text: Message text
1438 * @type: Message type
1440 * The ::show-message signal gets emitted when the greeter
1441 * should show a message to the user.
1443 signals[SHOW_MESSAGE] =
1444 g_signal_new ("show-message",
1445 G_TYPE_FROM_CLASS (klass),
1447 G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
1449 marshal_VOID__STRING_INT,
1450 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1453 * LightDMGreeter::authentication-complete:
1454 * @greeter: A #LightDMGreeter
1456 * The ::authentication-complete signal gets emitted when the greeter
1457 * has completed authentication.
1459 * Call lightdm_greeter_get_is_authenticated() to check if the authentication
1462 signals[AUTHENTICATION_COMPLETE] =
1463 g_signal_new ("authentication-complete",
1464 G_TYPE_FROM_CLASS (klass),
1466 G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
1468 g_cclosure_marshal_VOID__VOID,
1472 * LightDMGreeter::autologin-timer-expired:
1473 * @greeter: A #LightDMGreeter
1475 * The ::timed-login signal gets emitted when the automatic login timer has expired.
1476 * The application should then call lightdm_greeter_login().
1478 signals[AUTOLOGIN_TIMER_EXPIRED] =
1479 g_signal_new ("autologin-timer-expired",
1480 G_TYPE_FROM_CLASS (klass),
1482 G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),
1484 g_cclosure_marshal_VOID__VOID,