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
87 /* Messages from the server to the greeter */
90 SERVER_MESSAGE_CONNECTED = 0,
91 SERVER_MESSAGE_PROMPT_AUTHENTICATION,
92 SERVER_MESSAGE_END_AUTHENTICATION,
93 SERVER_MESSAGE_SESSION_RESULT
97 * lightdm_greeter_new:
99 * Create a new greeter.
101 * Return value: the new #LightDMGreeter
104 lightdm_greeter_new ()
106 return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
110 timed_login_cb (gpointer data)
112 LightDMGreeter *greeter = data;
113 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
115 priv->autologin_timeout = 0;
116 g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
128 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
130 if (*offset + 4 >= buffer_length)
132 buffer[*offset] = value >> 24;
133 buffer[*offset+1] = (value >> 16) & 0xFF;
134 buffer[*offset+2] = (value >> 8) & 0xFF;
135 buffer[*offset+3] = value & 0xFF;
140 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
145 length = strlen (value);
146 write_int (buffer, buffer_length, length, offset);
147 if (*offset + length >= buffer_length)
149 memcpy (buffer + *offset, value, length);
154 read_int (guint8 *message, gsize message_length, gsize *offset)
159 if (message_length - *offset < int_length ())
161 g_warning ("Not enough space for int, need %i, got %zi", int_length (), message_length - *offset);
165 buffer = message + *offset;
166 value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
167 *offset += int_length ();
173 read_string (guint8 *message, gsize message_length, gsize *offset)
178 length = read_int (message, message_length, offset);
179 if (message_length - *offset < length)
181 g_warning ("Not enough space for string, need %u, got %zu", length, message_length - *offset);
182 return g_strdup ("");
185 value = g_malloc (sizeof (gchar) * (length + 1));
186 memcpy (value, message + *offset, length);
187 value[length] = '\0';
194 string_length (const gchar *value)
197 return int_length () + strlen (value);
199 return int_length ();
203 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
205 write_int (buffer, buffer_length, id, offset);
206 write_int (buffer, buffer_length, length, offset);
210 get_message_length (guint8 *message, gsize message_length)
213 return read_int (message, message_length, &offset);
217 write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
219 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
221 GError *error = NULL;
222 guint32 stated_length;
224 /* Double check that we're sending well-formed messages. If we say we're
225 sending more than we do, we end up DOS'ing lightdm as it waits for the
226 rest. If we say we're sending less than we do, we confuse the heck out
227 of lightdm, as it starts reading headers from the middle of our
229 stated_length = HEADER_SIZE + get_message_length (message, message_length);
230 if (stated_length != message_length)
232 g_warning ("Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu", stated_length, message_length);
236 status = g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, &error);
238 g_warning ("Error writing to daemon: %s", error->message);
239 g_clear_error (&error);
240 if (status == G_IO_STATUS_NORMAL)
241 g_debug ("Wrote %zi bytes to daemon", message_length);
242 g_io_channel_flush (priv->to_server_channel, NULL);
246 handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
248 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
250 GString *hint_string;
253 version = read_string (message, message_length, offset);
254 hint_string = g_string_new ("");
255 while (*offset < message_length)
259 name = read_string (message, message_length, offset);
260 value = read_string (message, message_length, offset);
261 g_hash_table_insert (priv->hints, name, value);
262 g_string_append_printf (hint_string, " %s=%s", name, value);
265 g_debug ("Connected version=%s%s", version, hint_string->str);
267 g_string_free (hint_string, TRUE);
269 /* Set timeout for default login */
270 timeout = lightdm_greeter_get_autologin_timeout_hint (greeter);
273 g_debug ("Setting autologin timer for %d seconds", timeout);
274 priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
279 handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
281 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
282 guint32 sequence_number, n_messages, i;
285 sequence_number = read_int (message, message_length, offset);
286 if (sequence_number != priv->authenticate_sequence_number)
288 g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
292 if (priv->cancelling_authentication)
294 g_debug ("Ignoring prompt authentication as waiting for it to cancel");
298 /* Update username */
299 username = read_string (message, message_length, offset);
300 if (strcmp (username, "") == 0)
305 g_free (priv->authentication_user);
306 priv->authentication_user = username;
308 g_list_free_full (priv->responses_received, g_free);
309 priv->responses_received = NULL;
310 priv->n_responses_waiting = 0;
312 n_messages = read_int (message, message_length, offset);
313 g_debug ("Prompt user with %d message(s)", n_messages);
315 for (i = 0; i < n_messages; i++)
320 style = read_int (message, message_length, offset);
321 text = read_string (message, message_length, offset);
323 // FIXME: Should stop on prompts?
326 case PAM_PROMPT_ECHO_OFF:
327 priv->n_responses_waiting++;
328 g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_SECRET);
330 case PAM_PROMPT_ECHO_ON:
331 priv->n_responses_waiting++;
332 g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_QUESTION);
335 g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_ERROR);
338 g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_INFO);
347 handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
349 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
350 guint32 sequence_number, return_code;
353 sequence_number = read_int (message, message_length, offset);
355 if (sequence_number != priv->authenticate_sequence_number)
357 g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
361 username = read_string (message, message_length, offset);
362 return_code = read_int (message, message_length, offset);
364 g_debug ("Authentication complete for user %s with return code %d", username, return_code);
366 /* Update username */
367 if (strcmp (username, "") == 0)
372 g_free (priv->authentication_user);
373 priv->authentication_user = username;
375 priv->cancelling_authentication = FALSE;
376 priv->is_authenticated = (return_code == 0);
378 priv->in_authentication = FALSE;
379 g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
383 read_message (LightDMGreeter *greeter, gsize *length, gboolean block)
385 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
386 gsize n_to_read, n_read;
388 GError *error = NULL;
390 /* Read the header, or the whole message if we already have that */
391 n_to_read = HEADER_SIZE;
392 if (priv->n_read >= HEADER_SIZE)
393 n_to_read += get_message_length (priv->read_buffer, priv->n_read);
398 status = g_io_channel_read_chars (priv->from_server_channel,
399 (gchar *) priv->read_buffer + priv->n_read,
400 n_to_read - priv->n_read,
404 g_warning ("Error reading from server: %s", error->message);
405 g_clear_error (&error);
406 if (status != G_IO_STATUS_NORMAL)
409 g_debug ("Read %zi bytes from daemon", n_read);
411 priv->n_read += n_read;
412 } while (priv->n_read < n_to_read && block);
414 /* Stop if haven't got all the data we want */
415 if (priv->n_read != n_to_read)
418 /* If have header, rerun for content */
419 if (priv->n_read == HEADER_SIZE)
421 n_to_read = get_message_length (priv->read_buffer, priv->n_read);
424 priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
425 return read_message (greeter, length, block);
429 buffer = priv->read_buffer;
430 *length = priv->n_read;
432 priv->read_buffer = g_malloc (priv->n_read);
439 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
441 LightDMGreeter *greeter = data;
443 gsize message_length, offset;
446 message = read_message (greeter, &message_length, FALSE);
451 id = read_int (message, message_length, &offset);
452 read_int (message, message_length, &offset);
455 case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
456 handle_prompt_authentication (greeter, message, message_length, &offset);
458 case SERVER_MESSAGE_END_AUTHENTICATION:
459 handle_end_authentication (greeter, message, message_length, &offset);
462 g_warning ("Unknown message from server: %d", id);
471 * lightdm_greeter_connect_sync:
472 * @greeter: The greeter to connect
473 * @error: return location for a #GError, or %NULL
475 * Connects the greeter to the display manager. Will block until connected.
477 * Return value: #TRUE if successfully connected
480 lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
482 LightDMGreeterPrivate *priv;
484 guint8 message[MAX_MESSAGE_LENGTH];
486 gsize response_length, offset = 0;
489 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
491 priv = GET_PRIVATE (greeter);
493 fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
496 g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
499 priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
500 g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
502 fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
505 g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
508 priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
509 g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
510 g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
512 g_debug ("Connecting to display manager...");
513 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
514 write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
515 write_message (greeter, message, offset);
517 response = read_message (greeter, &response_length, TRUE);
522 id = read_int (response, response_length, &offset);
523 read_int (response, response_length, &offset);
524 if (id == SERVER_MESSAGE_CONNECTED)
525 handle_connected (greeter, response, response_length, &offset);
527 if (id != SERVER_MESSAGE_CONNECTED)
529 g_warning ("Expected CONNECTED message, got %d", id);
533 priv->connected = TRUE;
539 * lightdm_greeter_get_hint:
540 * @greeter: A #LightDMGreeter
541 * @name: The hint name to query.
545 * Return value: The value for this hint or #NULL if not set.
548 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
550 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
551 return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
555 * lightdm_greeter_get_default_session_hint:
556 * @greeter: A #LightDMGreeter
558 * Get the default session to use.
560 * Return value: The session name
563 lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
565 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
566 return lightdm_greeter_get_hint (greeter, "default-session");
570 * lightdm_greeter_get_hide_users_hint:
571 * @greeter: A #LightDMGreeter
573 * Check if user accounts should be shown. If this is TRUE then the list of
574 * accounts should be taken from #LightDMUserList and displayed in the greeter
575 * for the user to choose from. Note that this list can be empty and it is
576 * recommended you show a method for the user to enter a username manually.
578 * If this option is shown the greeter should only allow these users to be
579 * chosen for login unless the manual login hint is set.
581 * Return value: #TRUE if the available users should not be shown.
584 lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
588 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
589 value = lightdm_greeter_get_hint (greeter, "hide-users");
591 return g_strcmp0 (value, "true") == 0;
595 * lightdm_greeter_get_show_manual_login_hint:
596 * @greeter: A #LightDMGreeter
598 * Check if a manual login option should be shown. If set the GUI
599 * should provide a way for a username to be entered manually.
600 * Without this hint a greeter which is showing a user list can
601 * limit logins to only those users.
603 * Return value: #TRUE if a manual login option should be shown.
606 lightdm_greeter_get_show_manual_login_hint (LightDMGreeter *greeter)
610 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
611 value = lightdm_greeter_get_hint (greeter, "show-manual-login");
613 return g_strcmp0 (value, "true") == 0;
617 * lightdm_greeter_get_show_remote_login_hint:
618 * @greeter: A #LightDMGreeter
620 * Check if a remote login option should be shown. If set the GUI
621 * should provide a way for a user to log into a remote desktop server.
623 * Return value: #TRUE if a remote login option should be shown.
626 lightdm_greeter_get_show_remote_login_hint (LightDMGreeter *greeter)
630 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
631 value = lightdm_greeter_get_hint (greeter, "show-remote-login");
633 return g_strcmp0 (value, "true") == 0;
637 * lightdm_greeter_get_lock_hint:
638 * @greeter: A #LightDMGreeter
640 * Check if the greeter is acting as a lock screen.
642 * Return value: #TRUE if the greeter was triggered by locking the seat.
645 lightdm_greeter_get_lock_hint (LightDMGreeter *greeter)
649 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
650 value = lightdm_greeter_get_hint (greeter, "lock-screen");
652 return g_strcmp0 (value, "true") == 0;
656 * lightdm_greeter_get_has_guest_account_hint:
657 * @greeter: A #LightDMGreeter
659 * Check if guest sessions are supported.
661 * Return value: #TRUE if guest sessions are supported.
664 lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
668 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
669 value = lightdm_greeter_get_hint (greeter, "has-guest-account");
671 return g_strcmp0 (value, "true") == 0;
675 * lightdm_greeter_get_select_user_hint:
676 * @greeter: A #LightDMGreeter
678 * Get the user to select by default.
680 * Return value: A username
683 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
685 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
686 return lightdm_greeter_get_hint (greeter, "select-user");
690 * lightdm_greeter_get_select_guest_hint:
691 * @greeter: A #LightDMGreeter
693 * Check if the guest account should be selected by default.
695 * Return value: #TRUE if the guest account should be selected by default.
698 lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
702 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
703 value = lightdm_greeter_get_hint (greeter, "select-guest");
705 return g_strcmp0 (value, "true") == 0;
709 * lightdm_greeter_get_autologin_user_hint:
710 * @greeter: A #LightDMGreeter
712 * Get the user account to automatically logg into when the timer expires.
714 * Return value: The user account to automatically log into.
717 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
719 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
720 return lightdm_greeter_get_hint (greeter, "autologin-user");
724 * lightdm_greeter_get_autologin_guest_hint:
725 * @greeter: A #LightDMGreeter
727 * Check if the guest account should be automatically logged into when the timer expires.
729 * Return value: #TRUE if the guest account should be automatically logged into.
732 lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
736 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
737 value = lightdm_greeter_get_hint (greeter, "autologin-guest");
739 return g_strcmp0 (value, "true") == 0;
743 * lightdm_greeter_get_autologin_timeout_hint:
744 * @greeter: A #LightDMGreeter
746 * Get the number of seconds to wait before automaitcally logging in.
748 * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
751 lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
756 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
757 value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
759 timeout = atoi (value);
767 * lightdm_greeter_cancel_autologin:
768 * @greeter: A #LightDMGreeter
770 * Cancel the automatic login.
773 lightdm_greeter_cancel_autologin (LightDMGreeter *greeter)
775 LightDMGreeterPrivate *priv;
777 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
779 priv = GET_PRIVATE (greeter);
781 if (priv->autologin_timeout)
782 g_source_remove (priv->autologin_timeout);
783 priv->autologin_timeout = 0;
787 * lightdm_greeter_authenticate:
788 * @greeter: A #LightDMGreeter
789 * @username: (allow-none): A username or #NULL to prompt for a username.
791 * Starts the authentication procedure for a user.
794 lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username)
796 LightDMGreeterPrivate *priv;
797 guint8 message[MAX_MESSAGE_LENGTH];
800 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
802 priv = GET_PRIVATE (greeter);
804 g_return_if_fail (priv->connected);
806 priv->cancelling_authentication = FALSE;
807 priv->authenticate_sequence_number++;
808 priv->in_authentication = TRUE;
809 priv->is_authenticated = FALSE;
810 if (username != priv->authentication_user)
812 g_free (priv->authentication_user);
813 priv->authentication_user = g_strdup (username);
816 g_debug ("Starting authentication for user %s...", username);
817 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset);
818 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
819 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
820 write_message (greeter, message, offset);
824 * lightdm_greeter_authenticate_as_guest:
825 * @greeter: A #LightDMGreeter
827 * Starts the authentication procedure for the guest user.
830 lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter)
832 LightDMGreeterPrivate *priv;
833 guint8 message[MAX_MESSAGE_LENGTH];
836 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
838 priv = GET_PRIVATE (greeter);
840 g_return_if_fail (priv->connected);
842 priv->cancelling_authentication = FALSE;
843 priv->authenticate_sequence_number++;
844 priv->in_authentication = TRUE;
845 priv->is_authenticated = FALSE;
846 g_free (priv->authentication_user);
847 priv->authentication_user = NULL;
849 g_debug ("Starting authentication for guest account...");
850 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset);
851 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
852 write_message (greeter, message, offset);
856 * lightdm_greeter_authenticate_autologin:
857 * @greeter: A #LightDMGreeter
859 * Starts the authentication procedure for the automatic login user.
862 lightdm_greeter_authenticate_autologin (LightDMGreeter *greeter)
866 user = lightdm_greeter_get_autologin_user_hint (greeter);
867 if (lightdm_greeter_get_autologin_guest_hint (greeter))
868 lightdm_greeter_authenticate_as_guest (greeter);
870 lightdm_greeter_authenticate (greeter, user);
874 * lightdm_greeter_authenticate_remote:
875 * @greeter: A #LightDMGreeter
876 * @session: The name of a remote session
877 * @username: (allow-none): A username of #NULL to prompt for a username.
879 * Start authentication for a remote session type.
882 lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *session, const gchar *username)
884 LightDMGreeterPrivate *priv;
885 guint8 message[MAX_MESSAGE_LENGTH];
888 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
890 priv = GET_PRIVATE (greeter);
892 g_return_if_fail (priv->connected);
894 priv->cancelling_authentication = FALSE;
895 priv->authenticate_sequence_number++;
896 priv->in_authentication = TRUE;
897 priv->is_authenticated = FALSE;
898 g_free (priv->authentication_user);
899 priv->authentication_user = NULL;
902 g_debug ("Starting authentication for remote session %s as user %s...", session, username);
904 g_debug ("Starting authentication for remote session %s...", session);
905 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_REMOTE, int_length () + string_length (session) + string_length (username), &offset);
906 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
907 write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
908 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
909 write_message (greeter, message, offset);
913 * lightdm_greeter_respond:
914 * @greeter: A #LightDMGreeter
915 * @response: Response to a prompt
917 * Provide response to a prompt. May be one in a series.
920 lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response)
922 LightDMGreeterPrivate *priv;
923 guint8 message[MAX_MESSAGE_LENGTH];
926 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
927 g_return_if_fail (response != NULL);
929 priv = GET_PRIVATE (greeter);
931 g_return_if_fail (priv->connected);
932 g_return_if_fail (priv->n_responses_waiting > 0);
934 priv->n_responses_waiting--;
935 priv->responses_received = g_list_append (priv->responses_received, g_strdup (response));
937 if (priv->n_responses_waiting == 0)
942 g_debug ("Providing response to display manager");
944 msg_length = int_length ();
945 for (iter = priv->responses_received; iter; iter = iter->next)
947 msg_length += string_length ((gchar *)iter->data);
950 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, msg_length, &offset);
951 write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset);
952 for (iter = priv->responses_received; iter; iter = iter->next)
954 write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset);
956 write_message (greeter, message, offset);
958 g_list_free_full (priv->responses_received, g_free);
959 priv->responses_received = NULL;
964 * lightdm_greeter_cancel_authentication:
965 * @greeter: A #LightDMGreeter
967 * Cancel the current user authentication.
970 lightdm_greeter_cancel_authentication (LightDMGreeter *greeter)
972 LightDMGreeterPrivate *priv;
973 guint8 message[MAX_MESSAGE_LENGTH];
976 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
978 priv = GET_PRIVATE (greeter);
980 g_return_if_fail (priv->connected);
982 priv->cancelling_authentication = TRUE;
983 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
984 write_message (greeter, message, offset);
988 * lightdm_greeter_get_in_authentication:
989 * @greeter: A #LightDMGreeter
991 * Checks if the greeter is in the process of authenticating.
993 * Return value: #TRUE if the greeter is authenticating a user.
996 lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
998 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
999 return GET_PRIVATE (greeter)->in_authentication;
1003 * lightdm_greeter_get_is_authenticated:
1004 * @greeter: A #LightDMGreeter
1006 * Checks if the greeter has successfully authenticated.
1008 * Return value: #TRUE if the greeter is authenticated for login.
1011 lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
1013 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1014 return GET_PRIVATE (greeter)->is_authenticated;
1018 * lightdm_greeter_get_authentication_user:
1019 * @greeter: A #LightDMGreeter
1021 * Get the user that is being authenticated.
1023 * Return value: The username of the authentication user being authenticated or #NULL if no authentication in progress.
1026 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
1028 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1029 return GET_PRIVATE (greeter)->authentication_user;
1033 * lightdm_greeter_set_language:
1034 * @greeter: A #LightDMGreeter
1035 * @language: The language to use for this user in the form of a locale specification (e.g. "de_DE.UTF-8").
1037 * Set the language for the currently authenticated user.
1040 lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language)
1042 LightDMGreeterPrivate *priv;
1043 guint8 message[MAX_MESSAGE_LENGTH];
1046 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1048 priv = GET_PRIVATE (greeter);
1050 g_return_if_fail (priv->connected);
1052 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset);
1053 write_string (message, MAX_MESSAGE_LENGTH, language, &offset);
1054 write_message (greeter, message, offset);
1058 * lightdm_greeter_start_session_sync:
1059 * @greeter: A #LightDMGreeter
1060 * @session: (allow-none): The session to log into or #NULL to use the default.
1061 * @error: return location for a #GError, or %NULL
1063 * Start a session for the authenticated user.
1065 * Return value: TRUE if the session was started.
1068 lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
1070 LightDMGreeterPrivate *priv;
1071 guint8 message[MAX_MESSAGE_LENGTH];
1073 gsize response_length, offset = 0;
1074 guint32 id, return_code = 1;
1076 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1078 priv = GET_PRIVATE (greeter);
1080 g_return_val_if_fail (priv->connected, FALSE);
1081 g_return_val_if_fail (priv->is_authenticated, FALSE);
1084 g_debug ("Starting session %s", session);
1086 g_debug ("Starting default session");
1088 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
1089 write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
1090 write_message (greeter, message, offset);
1092 response = read_message (greeter, &response_length, TRUE);
1097 id = read_int (response, response_length, &offset);
1098 read_int (response, response_length, &offset);
1099 if (id == SERVER_MESSAGE_SESSION_RESULT)
1100 return_code = read_int (response, response_length, &offset);
1102 g_warning ("Expected SESSION_RESULT message, got %d", id);
1106 return return_code == 0;
1110 lightdm_greeter_init (LightDMGreeter *greeter)
1112 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1114 priv->read_buffer = g_malloc (HEADER_SIZE);
1115 priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1119 lightdm_greeter_set_property (GObject *object,
1121 const GValue *value,
1124 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1128 lightdm_greeter_get_property (GObject *object,
1133 LightDMGreeter *self;
1135 self = LIGHTDM_GREETER (object);
1138 case PROP_DEFAULT_SESSION_HINT:
1139 g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
1141 case PROP_HIDE_USERS_HINT:
1142 g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
1144 case PROP_SHOW_MANUAL_LOGIN_HINT:
1145 g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
1147 case PROP_SHOW_REMOTE_LOGIN_HINT:
1148 g_value_set_boolean (value, lightdm_greeter_get_show_remote_login_hint (self));
1150 case PROP_LOCK_HINT:
1151 g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
1153 case PROP_HAS_GUEST_ACCOUNT_HINT:
1154 g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
1156 case PROP_SELECT_USER_HINT:
1157 g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
1159 case PROP_SELECT_GUEST_HINT:
1160 g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
1162 case PROP_AUTOLOGIN_USER_HINT:
1163 g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
1165 case PROP_AUTOLOGIN_GUEST_HINT:
1166 g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
1168 case PROP_AUTOLOGIN_TIMEOUT_HINT:
1169 g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
1171 case PROP_AUTHENTICATION_USER:
1172 g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
1174 case PROP_IN_AUTHENTICATION:
1175 g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
1177 case PROP_IS_AUTHENTICATED:
1178 g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
1181 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1187 lightdm_greeter_finalize (GObject *object)
1189 LightDMGreeter *self = LIGHTDM_GREETER (object);
1190 LightDMGreeterPrivate *priv = GET_PRIVATE (self);
1192 if (priv->to_server_channel)
1193 g_io_channel_unref (priv->to_server_channel);
1194 if (priv->from_server_channel)
1195 g_io_channel_unref (priv->from_server_channel);
1196 g_free (priv->authentication_user);
1197 g_hash_table_unref (priv->hints);
1199 G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
1203 lightdm_greeter_class_init (LightDMGreeterClass *klass)
1205 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1207 g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
1209 object_class->set_property = lightdm_greeter_set_property;
1210 object_class->get_property = lightdm_greeter_get_property;
1211 object_class->finalize = lightdm_greeter_finalize;
1213 g_object_class_install_property (object_class,
1214 PROP_DEFAULT_SESSION_HINT,
1215 g_param_spec_string ("default-session-hint",
1216 "default-session-hint",
1217 "Default session hint",
1219 G_PARAM_READWRITE));
1221 g_object_class_install_property (object_class,
1222 PROP_HIDE_USERS_HINT,
1223 g_param_spec_boolean ("hide-users-hint",
1229 g_object_class_install_property (object_class,
1230 PROP_SHOW_MANUAL_LOGIN_HINT,
1231 g_param_spec_boolean ("show-manual-login-hint",
1232 "show-manual-login-hint",
1233 "Show manual login hint",
1237 g_object_class_install_property (object_class,
1238 PROP_SHOW_REMOTE_LOGIN_HINT,
1239 g_param_spec_boolean ("show-remote-login-hint",
1240 "show-remote-login-hint",
1241 "Show remote login hint",
1245 g_object_class_install_property (object_class,
1247 g_param_spec_boolean ("lock-hint",
1253 g_object_class_install_property (object_class,
1254 PROP_HAS_GUEST_ACCOUNT_HINT,
1255 g_param_spec_boolean ("has-guest-account-hint",
1256 "has-guest-account-hint",
1257 "Has guest account hint",
1261 g_object_class_install_property (object_class,
1262 PROP_SELECT_USER_HINT,
1263 g_param_spec_string ("select-user-hint",
1269 g_object_class_install_property (object_class,
1270 PROP_SELECT_GUEST_HINT,
1271 g_param_spec_boolean ("select-guest-hint",
1272 "select-guest-hint",
1273 "Select guest account hint",
1277 g_object_class_install_property (object_class,
1278 PROP_AUTOLOGIN_USER_HINT,
1279 g_param_spec_string ("autologin-user-hint",
1280 "autologin-user-hint",
1281 "Autologin user hint",
1285 g_object_class_install_property (object_class,
1286 PROP_AUTOLOGIN_GUEST_HINT,
1287 g_param_spec_boolean ("autologin-guest-hint",
1288 "autologin-guest-hint",
1289 "Autologin guest account hint",
1293 g_object_class_install_property (object_class,
1294 PROP_AUTOLOGIN_TIMEOUT_HINT,
1295 g_param_spec_int ("autologin-timeout-hint",
1296 "autologin-timeout-hint",
1297 "Autologin timeout hint",
1301 g_object_class_install_property (object_class,
1302 PROP_AUTHENTICATION_USER,
1303 g_param_spec_string ("authentication-user",
1304 "authentication-user",
1305 "The user being authenticated",
1308 g_object_class_install_property (object_class,
1309 PROP_IN_AUTHENTICATION,
1310 g_param_spec_boolean ("in-authentication",
1311 "in-authentication",
1312 "TRUE if a user is being authenticated",
1315 g_object_class_install_property (object_class,
1316 PROP_IS_AUTHENTICATED,
1317 g_param_spec_boolean ("is-authenticated",
1319 "TRUE if the selected user is authenticated",
1324 * LightDMGreeter::show-prompt:
1325 * @greeter: A #LightDMGreeter
1326 * @text: Prompt text
1327 * @type: Prompt type
1329 * The ::show-prompt signal gets emitted when the greeter should show a
1330 * prompt to the user. The given text should be displayed and an input
1331 * field for the user to provide a response.
1333 * Call lightdm_greeter_respond() with the resultant input or
1334 * lightdm_greeter_cancel_authentication() to abort the authentication.
1336 signals[SHOW_PROMPT] =
1337 g_signal_new ("show-prompt",
1338 G_TYPE_FROM_CLASS (klass),
1340 G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
1343 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1346 * LightDMGreeter::show-message:
1347 * @greeter: A #LightDMGreeter
1348 * @text: Message text
1349 * @type: Message type
1351 * The ::show-message signal gets emitted when the greeter
1352 * should show a message to the user.
1354 signals[SHOW_MESSAGE] =
1355 g_signal_new ("show-message",
1356 G_TYPE_FROM_CLASS (klass),
1358 G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
1361 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1364 * LightDMGreeter::authentication-complete:
1365 * @greeter: A #LightDMGreeter
1367 * The ::authentication-complete signal gets emitted when the greeter
1368 * has completed authentication.
1370 * Call lightdm_greeter_get_is_authenticated() to check if the authentication
1373 signals[AUTHENTICATION_COMPLETE] =
1374 g_signal_new ("authentication-complete",
1375 G_TYPE_FROM_CLASS (klass),
1377 G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
1383 * LightDMGreeter::autologin-timer-expired:
1384 * @greeter: A #LightDMGreeter
1386 * The ::timed-login signal gets emitted when the automatic login timer has expired.
1387 * The application should then call lightdm_greeter_login().
1389 signals[AUTOLOGIN_TIMER_EXPIRED] =
1390 g_signal_new ("autologin-timer-expired",
1391 G_TYPE_FROM_CLASS (klass),
1393 G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),