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,
95 SERVER_MESSAGE_SHARED_DIR_RESULT,
99 * lightdm_greeter_new:
101 * Create a new greeter.
103 * Return value: the new #LightDMGreeter
106 lightdm_greeter_new ()
108 return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
112 timed_login_cb (gpointer data)
114 LightDMGreeter *greeter = data;
115 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
117 priv->autologin_timeout = 0;
118 g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
130 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
132 if (*offset + 4 >= buffer_length)
134 buffer[*offset] = value >> 24;
135 buffer[*offset+1] = (value >> 16) & 0xFF;
136 buffer[*offset+2] = (value >> 8) & 0xFF;
137 buffer[*offset+3] = value & 0xFF;
142 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
147 length = strlen (value);
148 write_int (buffer, buffer_length, length, offset);
149 if (*offset + length >= buffer_length)
151 memcpy (buffer + *offset, value, length);
156 read_int (guint8 *message, gsize message_length, gsize *offset)
161 if (message_length - *offset < int_length ())
163 g_warning ("Not enough space for int, need %i, got %zi", int_length (), message_length - *offset);
167 buffer = message + *offset;
168 value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
169 *offset += int_length ();
175 read_string (guint8 *message, gsize message_length, gsize *offset)
180 length = read_int (message, message_length, offset);
181 if (message_length - *offset < length)
183 g_warning ("Not enough space for string, need %u, got %zu", length, message_length - *offset);
184 return g_strdup ("");
187 value = g_malloc (sizeof (gchar) * (length + 1));
188 memcpy (value, message + *offset, length);
189 value[length] = '\0';
196 string_length (const gchar *value)
199 return int_length () + strlen (value);
201 return int_length ();
205 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
207 write_int (buffer, buffer_length, id, offset);
208 write_int (buffer, buffer_length, length, offset);
212 get_message_length (guint8 *message, gsize message_length)
215 return read_int (message, message_length, &offset);
219 write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
221 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
223 GError *error = NULL;
224 guint32 stated_length;
226 /* Double check that we're sending well-formed messages. If we say we're
227 sending more than we do, we end up DOS'ing lightdm as it waits for the
228 rest. If we say we're sending less than we do, we confuse the heck out
229 of lightdm, as it starts reading headers from the middle of our
231 stated_length = HEADER_SIZE + get_message_length (message, message_length);
232 if (stated_length != message_length)
234 g_warning ("Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu", stated_length, message_length);
238 status = g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, &error);
240 g_warning ("Error writing to daemon: %s", error->message);
241 g_clear_error (&error);
242 if (status == G_IO_STATUS_NORMAL)
243 g_debug ("Wrote %zi bytes to daemon", message_length);
244 g_io_channel_flush (priv->to_server_channel, NULL);
248 handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
250 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
252 GString *hint_string;
255 version = read_string (message, message_length, offset);
256 hint_string = g_string_new ("");
257 while (*offset < message_length)
261 name = read_string (message, message_length, offset);
262 value = read_string (message, message_length, offset);
263 g_hash_table_insert (priv->hints, name, value);
264 g_string_append_printf (hint_string, " %s=%s", name, value);
267 g_debug ("Connected version=%s%s", version, hint_string->str);
269 g_string_free (hint_string, TRUE);
271 /* Set timeout for default login */
272 timeout = lightdm_greeter_get_autologin_timeout_hint (greeter);
275 g_debug ("Setting autologin timer for %d seconds", timeout);
276 priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
281 handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
283 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
284 guint32 sequence_number, n_messages, i;
287 sequence_number = read_int (message, message_length, offset);
288 if (sequence_number != priv->authenticate_sequence_number)
290 g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
294 if (priv->cancelling_authentication)
296 g_debug ("Ignoring prompt authentication as waiting for it to cancel");
300 /* Update username */
301 username = read_string (message, message_length, offset);
302 if (strcmp (username, "") == 0)
307 g_free (priv->authentication_user);
308 priv->authentication_user = username;
310 g_list_free_full (priv->responses_received, g_free);
311 priv->responses_received = NULL;
312 priv->n_responses_waiting = 0;
314 n_messages = read_int (message, message_length, offset);
315 g_debug ("Prompt user with %d message(s)", n_messages);
317 for (i = 0; i < n_messages; i++)
322 style = read_int (message, message_length, offset);
323 text = read_string (message, message_length, offset);
325 // FIXME: Should stop on prompts?
328 case PAM_PROMPT_ECHO_OFF:
329 priv->n_responses_waiting++;
330 g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_SECRET);
332 case PAM_PROMPT_ECHO_ON:
333 priv->n_responses_waiting++;
334 g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_QUESTION);
337 g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_ERROR);
340 g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_INFO);
349 handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
351 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
352 guint32 sequence_number, return_code;
355 sequence_number = read_int (message, message_length, offset);
357 if (sequence_number != priv->authenticate_sequence_number)
359 g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
363 username = read_string (message, message_length, offset);
364 return_code = read_int (message, message_length, offset);
366 g_debug ("Authentication complete for user %s with return code %d", username, return_code);
368 /* Update username */
369 if (strcmp (username, "") == 0)
374 g_free (priv->authentication_user);
375 priv->authentication_user = username;
377 priv->cancelling_authentication = FALSE;
378 priv->is_authenticated = (return_code == 0);
380 priv->in_authentication = FALSE;
381 g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
385 read_message (LightDMGreeter *greeter, gsize *length, gboolean block)
387 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
388 gsize n_to_read, n_read;
390 GError *error = NULL;
392 /* Read the header, or the whole message if we already have that */
393 n_to_read = HEADER_SIZE;
394 if (priv->n_read >= HEADER_SIZE)
395 n_to_read += get_message_length (priv->read_buffer, priv->n_read);
400 status = g_io_channel_read_chars (priv->from_server_channel,
401 (gchar *) priv->read_buffer + priv->n_read,
402 n_to_read - priv->n_read,
406 g_warning ("Error reading from server: %s", error->message);
407 g_clear_error (&error);
408 if (status != G_IO_STATUS_NORMAL)
411 g_debug ("Read %zi bytes from daemon", n_read);
413 priv->n_read += n_read;
414 } while (priv->n_read < n_to_read && block);
416 /* Stop if haven't got all the data we want */
417 if (priv->n_read != n_to_read)
420 /* If have header, rerun for content */
421 if (priv->n_read == HEADER_SIZE)
423 n_to_read = get_message_length (priv->read_buffer, priv->n_read);
426 priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
427 return read_message (greeter, length, block);
431 buffer = priv->read_buffer;
432 *length = priv->n_read;
434 priv->read_buffer = g_malloc (priv->n_read);
441 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
443 LightDMGreeter *greeter = data;
445 gsize message_length, offset;
448 message = read_message (greeter, &message_length, FALSE);
453 id = read_int (message, message_length, &offset);
454 read_int (message, message_length, &offset);
457 case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
458 handle_prompt_authentication (greeter, message, message_length, &offset);
460 case SERVER_MESSAGE_END_AUTHENTICATION:
461 handle_end_authentication (greeter, message, message_length, &offset);
464 g_warning ("Unknown message from server: %d", id);
473 * lightdm_greeter_connect_sync:
474 * @greeter: The greeter to connect
475 * @error: return location for a #GError, or %NULL
477 * Connects the greeter to the display manager. Will block until connected.
479 * Return value: #TRUE if successfully connected
482 lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
484 LightDMGreeterPrivate *priv;
486 guint8 message[MAX_MESSAGE_LENGTH];
488 gsize response_length, offset = 0;
491 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
493 priv = GET_PRIVATE (greeter);
495 fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
498 g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
501 priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
502 g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
504 fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
507 g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
510 priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
511 g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
512 g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
514 g_debug ("Connecting to display manager...");
515 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
516 write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
517 write_message (greeter, message, offset);
519 response = read_message (greeter, &response_length, TRUE);
524 id = read_int (response, response_length, &offset);
525 read_int (response, response_length, &offset);
526 if (id == SERVER_MESSAGE_CONNECTED)
527 handle_connected (greeter, response, response_length, &offset);
529 if (id != SERVER_MESSAGE_CONNECTED)
531 g_warning ("Expected CONNECTED message, got %d", id);
535 priv->connected = TRUE;
541 * lightdm_greeter_get_hint:
542 * @greeter: A #LightDMGreeter
543 * @name: The hint name to query.
547 * Return value: The value for this hint or #NULL if not set.
550 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
552 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
553 return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
557 * lightdm_greeter_get_default_session_hint:
558 * @greeter: A #LightDMGreeter
560 * Get the default session to use.
562 * Return value: The session name
565 lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
567 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
568 return lightdm_greeter_get_hint (greeter, "default-session");
572 * lightdm_greeter_get_hide_users_hint:
573 * @greeter: A #LightDMGreeter
575 * Check if user accounts should be shown. If this is TRUE then the list of
576 * accounts should be taken from #LightDMUserList and displayed in the greeter
577 * for the user to choose from. Note that this list can be empty and it is
578 * recommended you show a method for the user to enter a username manually.
580 * If this option is shown the greeter should only allow these users to be
581 * chosen for login unless the manual login hint is set.
583 * Return value: #TRUE if the available users should not be shown.
586 lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
590 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
591 value = lightdm_greeter_get_hint (greeter, "hide-users");
593 return g_strcmp0 (value, "true") == 0;
597 * lightdm_greeter_get_show_manual_login_hint:
598 * @greeter: A #LightDMGreeter
600 * Check if a manual login option should be shown. If set the GUI
601 * should provide a way for a username to be entered manually.
602 * Without this hint a greeter which is showing a user list can
603 * limit logins to only those users.
605 * Return value: #TRUE if a manual login option should be shown.
608 lightdm_greeter_get_show_manual_login_hint (LightDMGreeter *greeter)
612 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
613 value = lightdm_greeter_get_hint (greeter, "show-manual-login");
615 return g_strcmp0 (value, "true") == 0;
619 * lightdm_greeter_get_show_remote_login_hint:
620 * @greeter: A #LightDMGreeter
622 * Check if a remote login option should be shown. If set the GUI
623 * should provide a way for a user to log into a remote desktop server.
625 * Return value: #TRUE if a remote login option should be shown.
628 lightdm_greeter_get_show_remote_login_hint (LightDMGreeter *greeter)
632 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
633 value = lightdm_greeter_get_hint (greeter, "show-remote-login");
635 return g_strcmp0 (value, "true") == 0;
639 * lightdm_greeter_get_lock_hint:
640 * @greeter: A #LightDMGreeter
642 * Check if the greeter is acting as a lock screen.
644 * Return value: #TRUE if the greeter was triggered by locking the seat.
647 lightdm_greeter_get_lock_hint (LightDMGreeter *greeter)
651 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
652 value = lightdm_greeter_get_hint (greeter, "lock-screen");
654 return g_strcmp0 (value, "true") == 0;
658 * lightdm_greeter_get_has_guest_account_hint:
659 * @greeter: A #LightDMGreeter
661 * Check if guest sessions are supported.
663 * Return value: #TRUE if guest sessions are supported.
666 lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
670 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
671 value = lightdm_greeter_get_hint (greeter, "has-guest-account");
673 return g_strcmp0 (value, "true") == 0;
677 * lightdm_greeter_get_select_user_hint:
678 * @greeter: A #LightDMGreeter
680 * Get the user to select by default.
682 * Return value: A username
685 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
687 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
688 return lightdm_greeter_get_hint (greeter, "select-user");
692 * lightdm_greeter_get_select_guest_hint:
693 * @greeter: A #LightDMGreeter
695 * Check if the guest account should be selected by default.
697 * Return value: #TRUE if the guest account should be selected by default.
700 lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
704 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
705 value = lightdm_greeter_get_hint (greeter, "select-guest");
707 return g_strcmp0 (value, "true") == 0;
711 * lightdm_greeter_get_autologin_user_hint:
712 * @greeter: A #LightDMGreeter
714 * Get the user account to automatically logg into when the timer expires.
716 * Return value: The user account to automatically log into.
719 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
721 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
722 return lightdm_greeter_get_hint (greeter, "autologin-user");
726 * lightdm_greeter_get_autologin_guest_hint:
727 * @greeter: A #LightDMGreeter
729 * Check if the guest account should be automatically logged into when the timer expires.
731 * Return value: #TRUE if the guest account should be automatically logged into.
734 lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
738 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
739 value = lightdm_greeter_get_hint (greeter, "autologin-guest");
741 return g_strcmp0 (value, "true") == 0;
745 * lightdm_greeter_get_autologin_timeout_hint:
746 * @greeter: A #LightDMGreeter
748 * Get the number of seconds to wait before automaitcally logging in.
750 * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
753 lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
758 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
759 value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
761 timeout = atoi (value);
769 * lightdm_greeter_cancel_autologin:
770 * @greeter: A #LightDMGreeter
772 * Cancel the automatic login.
775 lightdm_greeter_cancel_autologin (LightDMGreeter *greeter)
777 LightDMGreeterPrivate *priv;
779 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
781 priv = GET_PRIVATE (greeter);
783 if (priv->autologin_timeout)
784 g_source_remove (priv->autologin_timeout);
785 priv->autologin_timeout = 0;
789 * lightdm_greeter_authenticate:
790 * @greeter: A #LightDMGreeter
791 * @username: (allow-none): A username or #NULL to prompt for a username.
793 * Starts the authentication procedure for a user.
796 lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username)
798 LightDMGreeterPrivate *priv;
799 guint8 message[MAX_MESSAGE_LENGTH];
802 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
804 priv = GET_PRIVATE (greeter);
806 g_return_if_fail (priv->connected);
808 priv->cancelling_authentication = FALSE;
809 priv->authenticate_sequence_number++;
810 priv->in_authentication = TRUE;
811 priv->is_authenticated = FALSE;
812 if (username != priv->authentication_user)
814 g_free (priv->authentication_user);
815 priv->authentication_user = g_strdup (username);
818 g_debug ("Starting authentication for user %s...", username);
819 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset);
820 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
821 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
822 write_message (greeter, message, offset);
826 * lightdm_greeter_authenticate_as_guest:
827 * @greeter: A #LightDMGreeter
829 * Starts the authentication procedure for the guest user.
832 lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter)
834 LightDMGreeterPrivate *priv;
835 guint8 message[MAX_MESSAGE_LENGTH];
838 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
840 priv = GET_PRIVATE (greeter);
842 g_return_if_fail (priv->connected);
844 priv->cancelling_authentication = FALSE;
845 priv->authenticate_sequence_number++;
846 priv->in_authentication = TRUE;
847 priv->is_authenticated = FALSE;
848 g_free (priv->authentication_user);
849 priv->authentication_user = NULL;
851 g_debug ("Starting authentication for guest account...");
852 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset);
853 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
854 write_message (greeter, message, offset);
858 * lightdm_greeter_authenticate_autologin:
859 * @greeter: A #LightDMGreeter
861 * Starts the authentication procedure for the automatic login user.
864 lightdm_greeter_authenticate_autologin (LightDMGreeter *greeter)
868 user = lightdm_greeter_get_autologin_user_hint (greeter);
869 if (lightdm_greeter_get_autologin_guest_hint (greeter))
870 lightdm_greeter_authenticate_as_guest (greeter);
872 lightdm_greeter_authenticate (greeter, user);
876 * lightdm_greeter_authenticate_remote:
877 * @greeter: A #LightDMGreeter
878 * @session: The name of a remote session
879 * @username: (allow-none): A username of #NULL to prompt for a username.
881 * Start authentication for a remote session type.
884 lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *session, const gchar *username)
886 LightDMGreeterPrivate *priv;
887 guint8 message[MAX_MESSAGE_LENGTH];
890 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
892 priv = GET_PRIVATE (greeter);
894 g_return_if_fail (priv->connected);
896 priv->cancelling_authentication = FALSE;
897 priv->authenticate_sequence_number++;
898 priv->in_authentication = TRUE;
899 priv->is_authenticated = FALSE;
900 g_free (priv->authentication_user);
901 priv->authentication_user = NULL;
904 g_debug ("Starting authentication for remote session %s as user %s...", session, username);
906 g_debug ("Starting authentication for remote session %s...", session);
907 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_REMOTE, int_length () + string_length (session) + string_length (username), &offset);
908 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
909 write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
910 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
911 write_message (greeter, message, offset);
915 * lightdm_greeter_respond:
916 * @greeter: A #LightDMGreeter
917 * @response: Response to a prompt
919 * Provide response to a prompt. May be one in a series.
922 lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response)
924 LightDMGreeterPrivate *priv;
925 guint8 message[MAX_MESSAGE_LENGTH];
928 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
929 g_return_if_fail (response != NULL);
931 priv = GET_PRIVATE (greeter);
933 g_return_if_fail (priv->connected);
934 g_return_if_fail (priv->n_responses_waiting > 0);
936 priv->n_responses_waiting--;
937 priv->responses_received = g_list_append (priv->responses_received, g_strdup (response));
939 if (priv->n_responses_waiting == 0)
944 g_debug ("Providing response to display manager");
946 msg_length = int_length ();
947 for (iter = priv->responses_received; iter; iter = iter->next)
949 msg_length += string_length ((gchar *)iter->data);
952 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, msg_length, &offset);
953 write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset);
954 for (iter = priv->responses_received; iter; iter = iter->next)
956 write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset);
958 write_message (greeter, message, offset);
960 g_list_free_full (priv->responses_received, g_free);
961 priv->responses_received = NULL;
966 * lightdm_greeter_cancel_authentication:
967 * @greeter: A #LightDMGreeter
969 * Cancel the current user authentication.
972 lightdm_greeter_cancel_authentication (LightDMGreeter *greeter)
974 LightDMGreeterPrivate *priv;
975 guint8 message[MAX_MESSAGE_LENGTH];
978 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
980 priv = GET_PRIVATE (greeter);
982 g_return_if_fail (priv->connected);
984 priv->cancelling_authentication = TRUE;
985 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
986 write_message (greeter, message, offset);
990 * lightdm_greeter_get_in_authentication:
991 * @greeter: A #LightDMGreeter
993 * Checks if the greeter is in the process of authenticating.
995 * Return value: #TRUE if the greeter is authenticating a user.
998 lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
1000 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1001 return GET_PRIVATE (greeter)->in_authentication;
1005 * lightdm_greeter_get_is_authenticated:
1006 * @greeter: A #LightDMGreeter
1008 * Checks if the greeter has successfully authenticated.
1010 * Return value: #TRUE if the greeter is authenticated for login.
1013 lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
1015 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1016 return GET_PRIVATE (greeter)->is_authenticated;
1020 * lightdm_greeter_get_authentication_user:
1021 * @greeter: A #LightDMGreeter
1023 * Get the user that is being authenticated.
1025 * Return value: The username of the authentication user being authenticated or #NULL if no authentication in progress.
1028 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
1030 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1031 return GET_PRIVATE (greeter)->authentication_user;
1035 * lightdm_greeter_set_language:
1036 * @greeter: A #LightDMGreeter
1037 * @language: The language to use for this user in the form of a locale specification (e.g. "de_DE.UTF-8").
1039 * Set the language for the currently authenticated user.
1042 lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language)
1044 LightDMGreeterPrivate *priv;
1045 guint8 message[MAX_MESSAGE_LENGTH];
1048 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1050 priv = GET_PRIVATE (greeter);
1052 g_return_if_fail (priv->connected);
1054 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset);
1055 write_string (message, MAX_MESSAGE_LENGTH, language, &offset);
1056 write_message (greeter, message, offset);
1060 * lightdm_greeter_start_session_sync:
1061 * @greeter: A #LightDMGreeter
1062 * @session: (allow-none): The session to log into or #NULL to use the default.
1063 * @error: return location for a #GError, or %NULL
1065 * Start a session for the authenticated user.
1067 * Return value: TRUE if the session was started.
1070 lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
1072 LightDMGreeterPrivate *priv;
1073 guint8 message[MAX_MESSAGE_LENGTH];
1075 gsize response_length, offset = 0;
1076 guint32 id, return_code = 1;
1078 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1080 priv = GET_PRIVATE (greeter);
1082 g_return_val_if_fail (priv->connected, FALSE);
1083 g_return_val_if_fail (priv->is_authenticated, FALSE);
1086 g_debug ("Starting session %s", session);
1088 g_debug ("Starting default session");
1090 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
1091 write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
1092 write_message (greeter, message, offset);
1094 response = read_message (greeter, &response_length, TRUE);
1099 id = read_int (response, response_length, &offset);
1100 read_int (response, response_length, &offset);
1101 if (id == SERVER_MESSAGE_SESSION_RESULT)
1102 return_code = read_int (response, response_length, &offset);
1104 g_warning ("Expected SESSION_RESULT message, got %d", id);
1108 return return_code == 0;
1112 * lightdm_greeter_ensure_shared_data_dir_sync:
1113 * @greeter: A #LightDMGreeter
1114 * @username: A username
1116 * Ensure that a shared data dir for the given user is available. This will
1117 * be created at /var/lib/lightdm-data/@username. Both the greeter user and
1118 * @username will have write access to that folder. The intention is that
1119 * larger pieces of shared data would be stored there (files that the greeter
1120 * creates but wants to give to a user -- like camera photos -- or files that
1121 * the user creates but wants the greeter to see -- like contact avatars).
1123 * LightDM will automatically create these if the user actually logs in, so
1124 * greeters only need to call this method if they want to store something in
1125 * the directory themselves.
1127 * Return value: TRUE if the directory is ready for use.
1130 lightdm_greeter_ensure_shared_data_dir_sync (LightDMGreeter *greeter, const gchar *username)
1132 LightDMGreeterPrivate *priv;
1133 guint8 message[MAX_MESSAGE_LENGTH];
1135 gsize response_length, offset = 0;
1136 guint32 id, return_code = 1;
1138 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1140 priv = GET_PRIVATE (greeter);
1142 g_return_if_fail (priv->connected);
1144 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_ENSURE_SHARED_DIR, string_length (username), &offset);
1145 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
1146 write_message (greeter, message, offset);
1148 response = read_message (greeter, &response_length, TRUE);
1153 id = read_int (response, response_length, &offset);
1154 read_int (response, response_length, &offset);
1155 if (id == SERVER_MESSAGE_SHARED_DIR_RESULT)
1156 return_code = read_int (response, response_length, &offset);
1158 g_warning ("Expected SHARED_DIR_RESULT message, got %d", id);
1162 return return_code == 0;
1166 lightdm_greeter_init (LightDMGreeter *greeter)
1168 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1170 priv->read_buffer = g_malloc (HEADER_SIZE);
1171 priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1175 lightdm_greeter_set_property (GObject *object,
1177 const GValue *value,
1180 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1184 lightdm_greeter_get_property (GObject *object,
1189 LightDMGreeter *self;
1191 self = LIGHTDM_GREETER (object);
1194 case PROP_DEFAULT_SESSION_HINT:
1195 g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
1197 case PROP_HIDE_USERS_HINT:
1198 g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
1200 case PROP_SHOW_MANUAL_LOGIN_HINT:
1201 g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
1203 case PROP_SHOW_REMOTE_LOGIN_HINT:
1204 g_value_set_boolean (value, lightdm_greeter_get_show_remote_login_hint (self));
1206 case PROP_LOCK_HINT:
1207 g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
1209 case PROP_HAS_GUEST_ACCOUNT_HINT:
1210 g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
1212 case PROP_SELECT_USER_HINT:
1213 g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
1215 case PROP_SELECT_GUEST_HINT:
1216 g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
1218 case PROP_AUTOLOGIN_USER_HINT:
1219 g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
1221 case PROP_AUTOLOGIN_GUEST_HINT:
1222 g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
1224 case PROP_AUTOLOGIN_TIMEOUT_HINT:
1225 g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
1227 case PROP_AUTHENTICATION_USER:
1228 g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
1230 case PROP_IN_AUTHENTICATION:
1231 g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
1233 case PROP_IS_AUTHENTICATED:
1234 g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
1237 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1243 lightdm_greeter_finalize (GObject *object)
1245 LightDMGreeter *self = LIGHTDM_GREETER (object);
1246 LightDMGreeterPrivate *priv = GET_PRIVATE (self);
1248 if (priv->to_server_channel)
1249 g_io_channel_unref (priv->to_server_channel);
1250 if (priv->from_server_channel)
1251 g_io_channel_unref (priv->from_server_channel);
1252 g_free (priv->authentication_user);
1253 g_hash_table_unref (priv->hints);
1255 G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
1259 lightdm_greeter_class_init (LightDMGreeterClass *klass)
1261 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1263 g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
1265 object_class->set_property = lightdm_greeter_set_property;
1266 object_class->get_property = lightdm_greeter_get_property;
1267 object_class->finalize = lightdm_greeter_finalize;
1269 g_object_class_install_property (object_class,
1270 PROP_DEFAULT_SESSION_HINT,
1271 g_param_spec_string ("default-session-hint",
1272 "default-session-hint",
1273 "Default session hint",
1275 G_PARAM_READWRITE));
1277 g_object_class_install_property (object_class,
1278 PROP_HIDE_USERS_HINT,
1279 g_param_spec_boolean ("hide-users-hint",
1285 g_object_class_install_property (object_class,
1286 PROP_SHOW_MANUAL_LOGIN_HINT,
1287 g_param_spec_boolean ("show-manual-login-hint",
1288 "show-manual-login-hint",
1289 "Show manual login hint",
1293 g_object_class_install_property (object_class,
1294 PROP_SHOW_REMOTE_LOGIN_HINT,
1295 g_param_spec_boolean ("show-remote-login-hint",
1296 "show-remote-login-hint",
1297 "Show remote login hint",
1301 g_object_class_install_property (object_class,
1303 g_param_spec_boolean ("lock-hint",
1309 g_object_class_install_property (object_class,
1310 PROP_HAS_GUEST_ACCOUNT_HINT,
1311 g_param_spec_boolean ("has-guest-account-hint",
1312 "has-guest-account-hint",
1313 "Has guest account hint",
1317 g_object_class_install_property (object_class,
1318 PROP_SELECT_USER_HINT,
1319 g_param_spec_string ("select-user-hint",
1325 g_object_class_install_property (object_class,
1326 PROP_SELECT_GUEST_HINT,
1327 g_param_spec_boolean ("select-guest-hint",
1328 "select-guest-hint",
1329 "Select guest account hint",
1333 g_object_class_install_property (object_class,
1334 PROP_AUTOLOGIN_USER_HINT,
1335 g_param_spec_string ("autologin-user-hint",
1336 "autologin-user-hint",
1337 "Autologin user hint",
1341 g_object_class_install_property (object_class,
1342 PROP_AUTOLOGIN_GUEST_HINT,
1343 g_param_spec_boolean ("autologin-guest-hint",
1344 "autologin-guest-hint",
1345 "Autologin guest account hint",
1349 g_object_class_install_property (object_class,
1350 PROP_AUTOLOGIN_TIMEOUT_HINT,
1351 g_param_spec_int ("autologin-timeout-hint",
1352 "autologin-timeout-hint",
1353 "Autologin timeout hint",
1357 g_object_class_install_property (object_class,
1358 PROP_AUTHENTICATION_USER,
1359 g_param_spec_string ("authentication-user",
1360 "authentication-user",
1361 "The user being authenticated",
1364 g_object_class_install_property (object_class,
1365 PROP_IN_AUTHENTICATION,
1366 g_param_spec_boolean ("in-authentication",
1367 "in-authentication",
1368 "TRUE if a user is being authenticated",
1371 g_object_class_install_property (object_class,
1372 PROP_IS_AUTHENTICATED,
1373 g_param_spec_boolean ("is-authenticated",
1375 "TRUE if the selected user is authenticated",
1380 * LightDMGreeter::show-prompt:
1381 * @greeter: A #LightDMGreeter
1382 * @text: Prompt text
1383 * @type: Prompt type
1385 * The ::show-prompt signal gets emitted when the greeter should show a
1386 * prompt to the user. The given text should be displayed and an input
1387 * field for the user to provide a response.
1389 * Call lightdm_greeter_respond() with the resultant input or
1390 * lightdm_greeter_cancel_authentication() to abort the authentication.
1392 signals[SHOW_PROMPT] =
1393 g_signal_new ("show-prompt",
1394 G_TYPE_FROM_CLASS (klass),
1396 G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
1399 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1402 * LightDMGreeter::show-message:
1403 * @greeter: A #LightDMGreeter
1404 * @text: Message text
1405 * @type: Message type
1407 * The ::show-message signal gets emitted when the greeter
1408 * should show a message to the user.
1410 signals[SHOW_MESSAGE] =
1411 g_signal_new ("show-message",
1412 G_TYPE_FROM_CLASS (klass),
1414 G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
1417 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1420 * LightDMGreeter::authentication-complete:
1421 * @greeter: A #LightDMGreeter
1423 * The ::authentication-complete signal gets emitted when the greeter
1424 * has completed authentication.
1426 * Call lightdm_greeter_get_is_authenticated() to check if the authentication
1429 signals[AUTHENTICATION_COMPLETE] =
1430 g_signal_new ("authentication-complete",
1431 G_TYPE_FROM_CLASS (klass),
1433 G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
1439 * LightDMGreeter::autologin-timer-expired:
1440 * @greeter: A #LightDMGreeter
1442 * The ::timed-login signal gets emitted when the automatic login timer has expired.
1443 * The application should then call lightdm_greeter_login().
1445 signals[AUTOLOGIN_TIMER_EXPIRED] =
1446 g_signal_new ("autologin-timer-expired",
1447 G_TYPE_FROM_CLASS (klass),
1449 G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),