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. Both the
1117 * greeter user and @username will have write access to that folder. The
1118 * intention is that larger pieces of shared data would be stored there (files
1119 * that the greeter creates but wants to give to a user -- like camera
1120 * photos -- or files that the user creates but wants the greeter to
1121 * 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: The path to the shared directory, free with g_free
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;
1137 gchar *data_dir = NULL;
1139 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1141 priv = GET_PRIVATE (greeter);
1143 g_return_val_if_fail (priv->connected, NULL);
1145 g_debug ("Ensuring data directory for user %s", username);
1147 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_ENSURE_SHARED_DIR, string_length (username), &offset);
1148 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
1149 write_message (greeter, message, offset);
1151 response = read_message (greeter, &response_length, TRUE);
1156 id = read_int (response, response_length, &offset);
1157 read_int (response, response_length, &offset);
1158 if (id == SERVER_MESSAGE_SHARED_DIR_RESULT)
1159 data_dir = read_string (response, response_length, &offset);
1161 g_warning ("Expected SHARED_DIR_RESULT message, got %d", id);
1163 /* Blank data dir means invalid user */
1164 if (g_strcmp0 (data_dir, "") == 0)
1176 lightdm_greeter_init (LightDMGreeter *greeter)
1178 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1180 priv->read_buffer = g_malloc (HEADER_SIZE);
1181 priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1185 lightdm_greeter_set_property (GObject *object,
1187 const GValue *value,
1190 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1194 lightdm_greeter_get_property (GObject *object,
1199 LightDMGreeter *self;
1201 self = LIGHTDM_GREETER (object);
1204 case PROP_DEFAULT_SESSION_HINT:
1205 g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
1207 case PROP_HIDE_USERS_HINT:
1208 g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
1210 case PROP_SHOW_MANUAL_LOGIN_HINT:
1211 g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
1213 case PROP_SHOW_REMOTE_LOGIN_HINT:
1214 g_value_set_boolean (value, lightdm_greeter_get_show_remote_login_hint (self));
1216 case PROP_LOCK_HINT:
1217 g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
1219 case PROP_HAS_GUEST_ACCOUNT_HINT:
1220 g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
1222 case PROP_SELECT_USER_HINT:
1223 g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
1225 case PROP_SELECT_GUEST_HINT:
1226 g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
1228 case PROP_AUTOLOGIN_USER_HINT:
1229 g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
1231 case PROP_AUTOLOGIN_GUEST_HINT:
1232 g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
1234 case PROP_AUTOLOGIN_TIMEOUT_HINT:
1235 g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
1237 case PROP_AUTHENTICATION_USER:
1238 g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
1240 case PROP_IN_AUTHENTICATION:
1241 g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
1243 case PROP_IS_AUTHENTICATED:
1244 g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
1247 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1253 lightdm_greeter_finalize (GObject *object)
1255 LightDMGreeter *self = LIGHTDM_GREETER (object);
1256 LightDMGreeterPrivate *priv = GET_PRIVATE (self);
1258 if (priv->to_server_channel)
1259 g_io_channel_unref (priv->to_server_channel);
1260 if (priv->from_server_channel)
1261 g_io_channel_unref (priv->from_server_channel);
1262 g_free (priv->authentication_user);
1263 g_hash_table_unref (priv->hints);
1265 G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
1269 lightdm_greeter_class_init (LightDMGreeterClass *klass)
1271 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1273 g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
1275 object_class->set_property = lightdm_greeter_set_property;
1276 object_class->get_property = lightdm_greeter_get_property;
1277 object_class->finalize = lightdm_greeter_finalize;
1279 g_object_class_install_property (object_class,
1280 PROP_DEFAULT_SESSION_HINT,
1281 g_param_spec_string ("default-session-hint",
1282 "default-session-hint",
1283 "Default session hint",
1285 G_PARAM_READWRITE));
1287 g_object_class_install_property (object_class,
1288 PROP_HIDE_USERS_HINT,
1289 g_param_spec_boolean ("hide-users-hint",
1295 g_object_class_install_property (object_class,
1296 PROP_SHOW_MANUAL_LOGIN_HINT,
1297 g_param_spec_boolean ("show-manual-login-hint",
1298 "show-manual-login-hint",
1299 "Show manual login hint",
1303 g_object_class_install_property (object_class,
1304 PROP_SHOW_REMOTE_LOGIN_HINT,
1305 g_param_spec_boolean ("show-remote-login-hint",
1306 "show-remote-login-hint",
1307 "Show remote login hint",
1311 g_object_class_install_property (object_class,
1313 g_param_spec_boolean ("lock-hint",
1319 g_object_class_install_property (object_class,
1320 PROP_HAS_GUEST_ACCOUNT_HINT,
1321 g_param_spec_boolean ("has-guest-account-hint",
1322 "has-guest-account-hint",
1323 "Has guest account hint",
1327 g_object_class_install_property (object_class,
1328 PROP_SELECT_USER_HINT,
1329 g_param_spec_string ("select-user-hint",
1335 g_object_class_install_property (object_class,
1336 PROP_SELECT_GUEST_HINT,
1337 g_param_spec_boolean ("select-guest-hint",
1338 "select-guest-hint",
1339 "Select guest account hint",
1343 g_object_class_install_property (object_class,
1344 PROP_AUTOLOGIN_USER_HINT,
1345 g_param_spec_string ("autologin-user-hint",
1346 "autologin-user-hint",
1347 "Autologin user hint",
1351 g_object_class_install_property (object_class,
1352 PROP_AUTOLOGIN_GUEST_HINT,
1353 g_param_spec_boolean ("autologin-guest-hint",
1354 "autologin-guest-hint",
1355 "Autologin guest account hint",
1359 g_object_class_install_property (object_class,
1360 PROP_AUTOLOGIN_TIMEOUT_HINT,
1361 g_param_spec_int ("autologin-timeout-hint",
1362 "autologin-timeout-hint",
1363 "Autologin timeout hint",
1367 g_object_class_install_property (object_class,
1368 PROP_AUTHENTICATION_USER,
1369 g_param_spec_string ("authentication-user",
1370 "authentication-user",
1371 "The user being authenticated",
1374 g_object_class_install_property (object_class,
1375 PROP_IN_AUTHENTICATION,
1376 g_param_spec_boolean ("in-authentication",
1377 "in-authentication",
1378 "TRUE if a user is being authenticated",
1381 g_object_class_install_property (object_class,
1382 PROP_IS_AUTHENTICATED,
1383 g_param_spec_boolean ("is-authenticated",
1385 "TRUE if the selected user is authenticated",
1390 * LightDMGreeter::show-prompt:
1391 * @greeter: A #LightDMGreeter
1392 * @text: Prompt text
1393 * @type: Prompt type
1395 * The ::show-prompt signal gets emitted when the greeter should show a
1396 * prompt to the user. The given text should be displayed and an input
1397 * field for the user to provide a response.
1399 * Call lightdm_greeter_respond() with the resultant input or
1400 * lightdm_greeter_cancel_authentication() to abort the authentication.
1402 signals[SHOW_PROMPT] =
1403 g_signal_new ("show-prompt",
1404 G_TYPE_FROM_CLASS (klass),
1406 G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
1409 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1412 * LightDMGreeter::show-message:
1413 * @greeter: A #LightDMGreeter
1414 * @text: Message text
1415 * @type: Message type
1417 * The ::show-message signal gets emitted when the greeter
1418 * should show a message to the user.
1420 signals[SHOW_MESSAGE] =
1421 g_signal_new ("show-message",
1422 G_TYPE_FROM_CLASS (klass),
1424 G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
1427 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1430 * LightDMGreeter::authentication-complete:
1431 * @greeter: A #LightDMGreeter
1433 * The ::authentication-complete signal gets emitted when the greeter
1434 * has completed authentication.
1436 * Call lightdm_greeter_get_is_authenticated() to check if the authentication
1439 signals[AUTHENTICATION_COMPLETE] =
1440 g_signal_new ("authentication-complete",
1441 G_TYPE_FROM_CLASS (klass),
1443 G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
1449 * LightDMGreeter::autologin-timer-expired:
1450 * @greeter: A #LightDMGreeter
1452 * The ::timed-login signal gets emitted when the automatic login timer has expired.
1453 * The application should then call lightdm_greeter_login().
1455 signals[AUTOLOGIN_TIMER_EXPIRED] =
1456 g_signal_new ("autologin-timer-expired",
1457 G_TYPE_FROM_CLASS (klass),
1459 G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),