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 3 of the License, or (at your option) any
8 * later version. See http://www.gnu.org/copyleft/lgpl.html the full text of the
16 #include <security/pam_appl.h>
18 #include "lightdm/greeter.h"
22 PROP_DEFAULT_SESSION_HINT,
24 PROP_SHOW_MANUAL_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;
55 guint autologin_timeout;
57 gchar *authentication_user;
58 gboolean in_authentication;
59 gboolean is_authenticated;
60 guint32 authenticate_sequence_number;
61 gboolean cancelling_authentication;
62 } LightDMGreeterPrivate;
64 G_DEFINE_TYPE (LightDMGreeter, lightdm_greeter, G_TYPE_OBJECT);
66 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_GREETER, LightDMGreeterPrivate)
69 #define MAX_MESSAGE_LENGTH 1024
71 /* Messages from the greeter to the server */
74 GREETER_MESSAGE_CONNECT = 0,
75 GREETER_MESSAGE_AUTHENTICATE,
76 GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
77 GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
78 GREETER_MESSAGE_START_SESSION,
79 GREETER_MESSAGE_CANCEL_AUTHENTICATION,
80 GREETER_MESSAGE_SET_LANGUAGE
83 /* Messages from the server to the greeter */
86 SERVER_MESSAGE_CONNECTED = 0,
87 SERVER_MESSAGE_PROMPT_AUTHENTICATION,
88 SERVER_MESSAGE_END_AUTHENTICATION,
89 SERVER_MESSAGE_SESSION_RESULT
93 * lightdm_greeter_new:
95 * Create a new greeter.
97 * Return value: the new #LightDMGreeter
100 lightdm_greeter_new ()
102 return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
106 timed_login_cb (gpointer data)
108 LightDMGreeter *greeter = data;
109 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
111 priv->autologin_timeout = 0;
112 g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
124 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
126 if (*offset + 4 >= buffer_length)
128 buffer[*offset] = value >> 24;
129 buffer[*offset+1] = (value >> 16) & 0xFF;
130 buffer[*offset+2] = (value >> 8) & 0xFF;
131 buffer[*offset+3] = value & 0xFF;
136 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
141 length = strlen (value);
142 write_int (buffer, buffer_length, length, offset);
143 if (*offset + length >= buffer_length)
145 memcpy (buffer + *offset, value, length);
150 read_int (guint8 *message, gsize message_length, gsize *offset)
155 if (message_length - *offset < int_length ())
157 g_warning ("Not enough space for int, need %i, got %zi", int_length (), message_length - *offset);
161 buffer = message + *offset;
162 value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
163 *offset += int_length ();
169 read_string (guint8 *message, gsize message_length, gsize *offset)
174 length = read_int (message, message_length, offset);
175 if (message_length - *offset < length)
177 g_warning ("Not enough space for string, need %u, got %zu", length, message_length - *offset);
178 return g_strdup ("");
181 value = g_malloc (sizeof (gchar) * (length + 1));
182 memcpy (value, message + *offset, length);
183 value[length] = '\0';
190 string_length (const gchar *value)
193 return int_length () + strlen (value);
195 return int_length ();
199 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
201 write_int (buffer, buffer_length, id, offset);
202 write_int (buffer, buffer_length, length, offset);
206 get_message_length (guint8 *message, gsize message_length)
209 return read_int (message, message_length, &offset);
213 write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
215 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
217 GError *error = NULL;
218 guint32 stated_length;
220 /* Double check that we're sending well-formed messages. If we say we're
221 sending more than we do, we end up DOS'ing lightdm as it waits for the
222 rest. If we say we're sending less than we do, we confuse the heck out
223 of lightdm, as it starts reading headers from the middle of our
225 stated_length = HEADER_SIZE + get_message_length (message, message_length);
226 if (stated_length != message_length)
228 g_warning ("Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu", stated_length, message_length);
232 status = g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, &error);
234 g_warning ("Error writing to daemon: %s", error->message);
235 g_clear_error (&error);
236 if (status == G_IO_STATUS_NORMAL)
237 g_debug ("Wrote %zi bytes to daemon", message_length);
238 g_io_channel_flush (priv->to_server_channel, NULL);
242 handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
244 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
246 GString *hint_string;
249 version = read_string (message, message_length, offset);
250 hint_string = g_string_new ("");
251 while (*offset < message_length)
255 name = read_string (message, message_length, offset);
256 value = read_string (message, message_length, offset);
257 g_hash_table_insert (priv->hints, name, value);
258 g_string_append_printf (hint_string, " %s=%s", name, value);
261 g_debug ("Connected version=%s%s", version, hint_string->str);
263 g_string_free (hint_string, TRUE);
265 /* Set timeout for default login */
266 timeout = lightdm_greeter_get_autologin_timeout_hint (greeter);
269 g_debug ("Setting autologin timer for %d seconds", timeout);
270 priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
275 handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
277 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
278 guint32 sequence_number, n_messages, i;
281 sequence_number = read_int (message, message_length, offset);
282 if (sequence_number != priv->authenticate_sequence_number)
284 g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
288 if (priv->cancelling_authentication)
290 g_debug ("Ignoring prompt authentication as waiting for it to cancel");
294 /* Update username */
295 username = read_string (message, message_length, offset);
296 if (strcmp (username, "") == 0)
301 g_free (priv->authentication_user);
302 priv->authentication_user = username;
304 n_messages = read_int (message, message_length, offset);
305 g_debug ("Prompt user with %d message(s)", n_messages);
307 for (i = 0; i < n_messages; i++)
312 style = read_int (message, message_length, offset);
313 text = read_string (message, message_length, offset);
315 // FIXME: Should stop on prompts?
318 case PAM_PROMPT_ECHO_OFF:
319 g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_SECRET);
321 case PAM_PROMPT_ECHO_ON:
322 g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_QUESTION);
325 g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_ERROR);
328 g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_INFO);
337 handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
339 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
340 guint32 sequence_number, return_code;
343 sequence_number = read_int (message, message_length, offset);
345 if (sequence_number != priv->authenticate_sequence_number)
347 g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
351 username = read_string (message, message_length, offset);
352 return_code = read_int (message, message_length, offset);
354 g_debug ("Authentication complete for user %s with return code %d", username, return_code);
356 /* Update username */
357 if (strcmp (username, "") == 0)
362 g_free (priv->authentication_user);
363 priv->authentication_user = username;
365 priv->cancelling_authentication = FALSE;
366 priv->is_authenticated = (return_code == 0);
368 priv->in_authentication = FALSE;
369 g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
373 read_message (LightDMGreeter *greeter, gsize *length, gboolean block)
375 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
376 gsize n_to_read, n_read;
378 GError *error = NULL;
380 /* Read the header, or the whole message if we already have that */
381 n_to_read = HEADER_SIZE;
382 if (priv->n_read >= HEADER_SIZE)
383 n_to_read += get_message_length (priv->read_buffer, priv->n_read);
388 status = g_io_channel_read_chars (priv->from_server_channel,
389 (gchar *) priv->read_buffer + priv->n_read,
390 n_to_read - priv->n_read,
394 g_warning ("Error reading from server: %s", error->message);
395 g_clear_error (&error);
396 if (status != G_IO_STATUS_NORMAL)
399 g_debug ("Read %zi bytes from daemon", n_read);
401 priv->n_read += n_read;
402 } while (priv->n_read < n_to_read && block);
404 /* Stop if haven't got all the data we want */
405 if (priv->n_read != n_to_read)
408 /* If have header, rerun for content */
409 if (priv->n_read == HEADER_SIZE)
411 n_to_read = get_message_length (priv->read_buffer, priv->n_read);
414 priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
415 return read_message (greeter, length, block);
419 buffer = priv->read_buffer;
420 *length = priv->n_read;
422 priv->read_buffer = g_malloc (priv->n_read);
429 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
431 LightDMGreeter *greeter = data;
433 gsize message_length, offset;
436 message = read_message (greeter, &message_length, FALSE);
441 id = read_int (message, message_length, &offset);
442 read_int (message, message_length, &offset);
445 case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
446 handle_prompt_authentication (greeter, message, message_length, &offset);
448 case SERVER_MESSAGE_END_AUTHENTICATION:
449 handle_end_authentication (greeter, message, message_length, &offset);
452 g_warning ("Unknown message from server: %d", id);
461 * lightdm_greeter_connect_sync:
462 * @greeter: The greeter to connect
463 * @error: return location for a #GError, or %NULL
465 * Connects the greeter to the display manager. Will block until connected.
467 * Return value: #TRUE if successfully connected
470 lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
472 LightDMGreeterPrivate *priv;
474 guint8 message[MAX_MESSAGE_LENGTH];
476 gsize response_length, offset = 0;
479 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
481 priv = GET_PRIVATE (greeter);
483 fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
486 g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
489 priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
490 g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
492 fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
495 g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
498 priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
499 g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
500 g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
502 g_debug ("Connecting to display manager...");
503 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
504 write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
505 write_message (greeter, message, offset);
507 response = read_message (greeter, &response_length, TRUE);
512 id = read_int (response, response_length, &offset);
513 read_int (response, response_length, &offset);
514 if (id == SERVER_MESSAGE_CONNECTED)
515 handle_connected (greeter, response, response_length, &offset);
517 if (id != SERVER_MESSAGE_CONNECTED)
519 g_warning ("Expected CONNECTED message, got %d", id);
523 priv->connected = TRUE;
529 * lightdm_greeter_get_hint:
530 * @greeter: A #LightDMGreeter
531 * @name: The hint name to query.
535 * Return value: The value for this hint or #NULL if not set.
538 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
540 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
541 return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
545 * lightdm_greeter_get_default_session_hint:
546 * @greeter: A #LightDMGreeter
548 * Get the default session to use.
550 * Return value: The session name
553 lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
555 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
556 return lightdm_greeter_get_hint (greeter, "default-session");
560 * lightdm_greeter_get_hide_users_hint:
561 * @greeter: A #LightDMGreeter
563 * Check if user accounts should be shown. If this is TRUE then the list of
564 * accounts should be taken from #LightDMUserList and displayed in the greeter
565 * for the user to choose from. Note that this list can be empty and it is
566 * recommended you show a method for the user to enter a username manually.
568 * If this option is shown the greeter should only allow these users to be
569 * chosen for login unless the manual login hint is set.
571 * Return value: #TRUE if the available users should not be shown.
574 lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
578 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
579 value = lightdm_greeter_get_hint (greeter, "hide-users");
581 return g_strcmp0 (value, "true") == 0;
585 * lightdm_greeter_get_show_manual_login_hint:
586 * @greeter: A #LightDMGreeter
588 * Check if a manual login option should be shown. If set the GUI
589 * should provide a way for a username to be entered manually.
590 * Without this hint a greeter which is showing a user list can
591 * limit logins to only those users.
593 * Return value: #TRUE if a manual login option should be shown.
596 lightdm_greeter_get_show_manual_login_hint (LightDMGreeter *greeter)
600 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
601 value = lightdm_greeter_get_hint (greeter, "show-manual-login");
603 return g_strcmp0 (value, "true") == 0;
607 * lightdm_greeter_get_lock_hint:
608 * @greeter: A #LightDMGreeter
610 * Check if the greeter is acting as a lock screen.
612 * Return value: #TRUE if the greeter was triggered by locking the seat.
615 lightdm_greeter_get_lock_hint (LightDMGreeter *greeter)
619 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
620 value = lightdm_greeter_get_hint (greeter, "lock-screen");
622 return g_strcmp0 (value, "true") == 0;
626 * lightdm_greeter_get_has_guest_account_hint:
627 * @greeter: A #LightDMGreeter
629 * Check if guest sessions are supported.
631 * Return value: #TRUE if guest sessions are supported.
634 lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
638 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
639 value = lightdm_greeter_get_hint (greeter, "has-guest-account");
641 return g_strcmp0 (value, "true") == 0;
645 * lightdm_greeter_get_select_user_hint:
646 * @greeter: A #LightDMGreeter
648 * Get the user to select by default.
650 * Return value: A username
653 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
655 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
656 return lightdm_greeter_get_hint (greeter, "select-user");
660 * lightdm_greeter_get_select_guest_hint:
661 * @greeter: A #LightDMGreeter
663 * Check if the guest account should be selected by default.
665 * Return value: #TRUE if the guest account should be selected by default.
668 lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
672 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
673 value = lightdm_greeter_get_hint (greeter, "select-guest");
675 return g_strcmp0 (value, "true") == 0;
679 * lightdm_greeter_get_autologin_user_hint:
680 * @greeter: A #LightDMGreeter
682 * Get the user account to automatically logg into when the timer expires.
684 * Return value: The user account to automatically log into.
687 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
689 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
690 return lightdm_greeter_get_hint (greeter, "autologin-user");
694 * lightdm_greeter_get_autologin_guest_hint:
695 * @greeter: A #LightDMGreeter
697 * Check if the guest account should be automatically logged into when the timer expires.
699 * Return value: #TRUE if the guest account should be automatically logged into.
702 lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
706 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
707 value = lightdm_greeter_get_hint (greeter, "autologin-guest");
709 return g_strcmp0 (value, "true") == 0;
713 * lightdm_greeter_get_autologin_timeout_hint:
714 * @greeter: A #LightDMGreeter
716 * Get the number of seconds to wait before automaitcally logging in.
718 * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
721 lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
726 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
727 value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
729 timeout = atoi (value);
737 * lightdm_greeter_cancel_autologin:
738 * @greeter: A #LightDMGreeter
740 * Cancel the automatic login.
743 lightdm_greeter_cancel_autologin (LightDMGreeter *greeter)
745 LightDMGreeterPrivate *priv;
747 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
749 priv = GET_PRIVATE (greeter);
751 if (priv->autologin_timeout)
752 g_source_remove (priv->autologin_timeout);
753 priv->autologin_timeout = 0;
757 * lightdm_greeter_authenticate:
758 * @greeter: A #LightDMGreeter
759 * @username: (allow-none): A username or #NULL to prompt for a username.
761 * Starts the authentication procedure for a user.
764 lightdm_greeter_authenticate (LightDMGreeter *greeter, const char *username)
766 LightDMGreeterPrivate *priv;
767 guint8 message[MAX_MESSAGE_LENGTH];
770 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
772 priv = GET_PRIVATE (greeter);
774 g_return_if_fail (priv->connected);
776 priv->cancelling_authentication = FALSE;
777 priv->authenticate_sequence_number++;
778 priv->in_authentication = TRUE;
779 priv->is_authenticated = FALSE;
780 if (username != priv->authentication_user)
782 g_free (priv->authentication_user);
783 priv->authentication_user = g_strdup (username);
786 g_debug ("Starting authentication for user %s...", username);
787 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset);
788 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
789 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
790 write_message (greeter, message, offset);
794 * lightdm_greeter_authenticate_as_guest:
795 * @greeter: A #LightDMGreeter
797 * Starts the authentication procedure for the guest user.
800 lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter)
802 LightDMGreeterPrivate *priv;
803 guint8 message[MAX_MESSAGE_LENGTH];
806 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
808 priv = GET_PRIVATE (greeter);
810 g_return_if_fail (priv->connected);
812 priv->cancelling_authentication = FALSE;
813 priv->authenticate_sequence_number++;
814 priv->in_authentication = TRUE;
815 priv->is_authenticated = FALSE;
816 g_free (priv->authentication_user);
817 priv->authentication_user = NULL;
819 g_debug ("Starting authentication for guest account...");
820 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset);
821 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
822 write_message (greeter, message, offset);
826 * lightdm_greeter_respond:
827 * @greeter: A #LightDMGreeter
828 * @response: Response to a prompt
830 * Provide response to a prompt.
833 lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response)
835 LightDMGreeterPrivate *priv;
836 guint8 message[MAX_MESSAGE_LENGTH];
839 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
840 g_return_if_fail (response != NULL);
842 priv = GET_PRIVATE (greeter);
844 g_return_if_fail (priv->connected);
846 g_debug ("Providing response to display manager");
847 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, int_length () + string_length (response), &offset);
848 // FIXME: Could be multiple responses required
849 write_int (message, MAX_MESSAGE_LENGTH, 1, &offset);
850 write_string (message, MAX_MESSAGE_LENGTH, response, &offset);
851 write_message (greeter, message, offset);
855 * lightdm_greeter_cancel_authentication:
856 * @greeter: A #LightDMGreeter
858 * Cancel the current user authentication.
861 lightdm_greeter_cancel_authentication (LightDMGreeter *greeter)
863 LightDMGreeterPrivate *priv;
864 guint8 message[MAX_MESSAGE_LENGTH];
867 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
869 priv = GET_PRIVATE (greeter);
871 g_return_if_fail (priv->connected);
873 priv->cancelling_authentication = TRUE;
874 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
875 write_message (greeter, message, offset);
879 * lightdm_greeter_get_in_authentication:
880 * @greeter: A #LightDMGreeter
882 * Checks if the greeter is in the process of authenticating.
884 * Return value: #TRUE if the greeter is authenticating a user.
887 lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
889 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
890 return GET_PRIVATE (greeter)->in_authentication;
894 * lightdm_greeter_get_is_authenticated:
895 * @greeter: A #LightDMGreeter
897 * Checks if the greeter has successfully authenticated.
899 * Return value: #TRUE if the greeter is authenticated for login.
902 lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
904 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
905 return GET_PRIVATE (greeter)->is_authenticated;
909 * lightdm_greeter_get_authentication_user:
910 * @greeter: A #LightDMGreeter
912 * Get the user that is being authenticated.
914 * Return value: The username of the authentication user being authenticated or #NULL if no authentication in progress.
917 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
919 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
920 return GET_PRIVATE (greeter)->authentication_user;
924 * lightdm_greeter_set_language:
925 * @greeter: A #LightDMGreeter
926 * @language: The language to use for this user.
928 * Set the language for the currently authenticated user.
931 lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language)
933 LightDMGreeterPrivate *priv;
934 guint8 message[MAX_MESSAGE_LENGTH];
937 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
939 priv = GET_PRIVATE (greeter);
941 g_return_if_fail (priv->connected);
943 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset);
944 write_string (message, MAX_MESSAGE_LENGTH, language, &offset);
945 write_message (greeter, message, offset);
949 * lightdm_greeter_start_session_sync:
950 * @greeter: A #LightDMGreeter
951 * @session: (allow-none): The session to log into or #NULL to use the default.
952 * @error: return location for a #GError, or %NULL
954 * Start a session for the authenticated user.
956 * Return value: TRUE if the session was started.
959 lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
961 LightDMGreeterPrivate *priv;
962 guint8 message[MAX_MESSAGE_LENGTH];
964 gsize response_length, offset = 0;
965 guint32 id, return_code = 1;
967 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
969 priv = GET_PRIVATE (greeter);
971 g_return_val_if_fail (priv->connected, FALSE);
972 g_return_val_if_fail (priv->is_authenticated, FALSE);
975 g_debug ("Starting session %s", session);
977 g_debug ("Starting default session");
979 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
980 write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
981 write_message (greeter, message, offset);
983 response = read_message (greeter, &response_length, TRUE);
988 id = read_int (response, response_length, &offset);
989 read_int (response, response_length, &offset);
990 if (id == SERVER_MESSAGE_SESSION_RESULT)
991 return_code = read_int (response, response_length, &offset);
993 g_warning ("Expected SESSION_RESULT message, got %d", id);
997 return return_code == 0;
1001 lightdm_greeter_init (LightDMGreeter *greeter)
1003 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1005 priv->read_buffer = g_malloc (HEADER_SIZE);
1006 priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1010 lightdm_greeter_set_property (GObject *object,
1012 const GValue *value,
1015 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1019 lightdm_greeter_get_property (GObject *object,
1024 LightDMGreeter *self;
1026 self = LIGHTDM_GREETER (object);
1029 case PROP_DEFAULT_SESSION_HINT:
1030 g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
1032 case PROP_HIDE_USERS_HINT:
1033 g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
1035 case PROP_SHOW_MANUAL_LOGIN_HINT:
1036 g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
1038 case PROP_LOCK_HINT:
1039 g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
1041 case PROP_HAS_GUEST_ACCOUNT_HINT:
1042 g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
1044 case PROP_SELECT_USER_HINT:
1045 g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
1047 case PROP_SELECT_GUEST_HINT:
1048 g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
1050 case PROP_AUTOLOGIN_USER_HINT:
1051 g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
1053 case PROP_AUTOLOGIN_GUEST_HINT:
1054 g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
1056 case PROP_AUTOLOGIN_TIMEOUT_HINT:
1057 g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
1059 case PROP_AUTHENTICATION_USER:
1060 g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
1062 case PROP_IN_AUTHENTICATION:
1063 g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
1065 case PROP_IS_AUTHENTICATED:
1066 g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
1069 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1075 marshal_VOID__STRING_INT (GClosure *closure,
1076 GValue *return_value G_GNUC_UNUSED,
1077 guint n_param_values,
1078 const GValue *param_values,
1079 gpointer invocation_hint G_GNUC_UNUSED,
1080 gpointer marshal_data)
1082 typedef void (*GMarshalFunc_VOID__STRING_INT) (gpointer data1,
1086 register GMarshalFunc_VOID__STRING_INT callback;
1087 register GCClosure *cc = (GCClosure*) closure;
1088 register gpointer data1, data2;
1090 g_return_if_fail (n_param_values == 3);
1092 if (G_CCLOSURE_SWAP_DATA (closure))
1094 data1 = closure->data;
1095 data2 = g_value_peek_pointer (param_values + 0);
1099 data1 = g_value_peek_pointer (param_values + 0);
1100 data2 = closure->data;
1102 callback = (GMarshalFunc_VOID__STRING_INT) (marshal_data ? marshal_data : cc->callback);
1105 (param_values + 1)->data[0].v_pointer,
1106 (param_values + 2)->data[0].v_int,
1111 lightdm_greeter_finalize (GObject *object)
1113 LightDMGreeter *self = LIGHTDM_GREETER (object);
1114 LightDMGreeterPrivate *priv = GET_PRIVATE (self);
1116 if (priv->to_server_channel)
1117 g_io_channel_unref (priv->to_server_channel);
1118 if (priv->from_server_channel)
1119 g_io_channel_unref (priv->from_server_channel);
1120 g_free (priv->authentication_user);
1121 g_hash_table_unref (priv->hints);
1123 G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
1127 lightdm_greeter_class_init (LightDMGreeterClass *klass)
1129 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1131 g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
1133 object_class->set_property = lightdm_greeter_set_property;
1134 object_class->get_property = lightdm_greeter_get_property;
1135 object_class->finalize = lightdm_greeter_finalize;
1137 g_object_class_install_property (object_class,
1138 PROP_DEFAULT_SESSION_HINT,
1139 g_param_spec_string ("default-session-hint",
1140 "default-session-hint",
1141 "Default session hint",
1143 G_PARAM_READWRITE));
1145 g_object_class_install_property (object_class,
1146 PROP_HIDE_USERS_HINT,
1147 g_param_spec_boolean ("hide-users-hint",
1153 g_object_class_install_property (object_class,
1154 PROP_SHOW_MANUAL_LOGIN_HINT,
1155 g_param_spec_boolean ("show-manual-login-hint",
1156 "show-manual-login-hint",
1157 "Show manual login hint",
1161 g_object_class_install_property (object_class,
1163 g_param_spec_boolean ("lock-hint",
1169 g_object_class_install_property (object_class,
1170 PROP_HAS_GUEST_ACCOUNT_HINT,
1171 g_param_spec_boolean ("has-guest-account-hint",
1172 "has-guest-account-hint",
1173 "Has guest account hint",
1177 g_object_class_install_property (object_class,
1178 PROP_SELECT_USER_HINT,
1179 g_param_spec_string ("select-user-hint",
1185 g_object_class_install_property (object_class,
1186 PROP_SELECT_GUEST_HINT,
1187 g_param_spec_boolean ("select-guest-hint",
1188 "select-guest-hint",
1189 "Select guest account hint",
1193 g_object_class_install_property (object_class,
1194 PROP_AUTOLOGIN_USER_HINT,
1195 g_param_spec_string ("autologin-user-hint",
1196 "autologin-user-hint",
1197 "Autologin user hint",
1201 g_object_class_install_property (object_class,
1202 PROP_AUTOLOGIN_GUEST_HINT,
1203 g_param_spec_boolean ("autologin-guest-hint",
1204 "autologin-guest-hint",
1205 "Autologin guest account hint",
1209 g_object_class_install_property (object_class,
1210 PROP_AUTOLOGIN_TIMEOUT_HINT,
1211 g_param_spec_int ("autologin-timeout-hint",
1212 "autologin-timeout-hint",
1213 "Autologin timeout hint",
1217 g_object_class_install_property (object_class,
1218 PROP_AUTHENTICATION_USER,
1219 g_param_spec_string ("authentication-user",
1220 "authentication-user",
1221 "The user being authenticated",
1224 g_object_class_install_property (object_class,
1225 PROP_IN_AUTHENTICATION,
1226 g_param_spec_boolean ("in-authentication",
1227 "in-authentication",
1228 "TRUE if a user is being authenticated",
1231 g_object_class_install_property (object_class,
1232 PROP_IS_AUTHENTICATED,
1233 g_param_spec_boolean ("is-authenticated",
1235 "TRUE if the selected user is authenticated",
1240 * LightDMGreeter::show-prompt:
1241 * @greeter: A #LightDMGreeter
1242 * @text: Prompt text
1243 * @type: Prompt type
1245 * The ::show-prompt signal gets emitted when the greeter should show a
1246 * prompt to the user. The given text should be displayed and an input
1247 * field for the user to provide a response.
1249 * Call lightdm_greeter_respond() with the resultant input or
1250 * lightdm_greeter_cancel_authentication() to abort the authentication.
1252 signals[SHOW_PROMPT] =
1253 g_signal_new ("show-prompt",
1254 G_TYPE_FROM_CLASS (klass),
1256 G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
1258 marshal_VOID__STRING_INT,
1259 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1262 * LightDMGreeter::show-message:
1263 * @greeter: A #LightDMGreeter
1264 * @text: Message text
1265 * @type: Message type
1267 * The ::show-message signal gets emitted when the greeter
1268 * should show a message to the user.
1270 signals[SHOW_MESSAGE] =
1271 g_signal_new ("show-message",
1272 G_TYPE_FROM_CLASS (klass),
1274 G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
1276 marshal_VOID__STRING_INT,
1277 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1280 * LightDMGreeter::authentication-complete:
1281 * @greeter: A #LightDMGreeter
1283 * The ::authentication-complete signal gets emitted when the greeter
1284 * has completed authentication.
1286 * Call lightdm_greeter_get_is_authenticated() to check if the authentication
1289 signals[AUTHENTICATION_COMPLETE] =
1290 g_signal_new ("authentication-complete",
1291 G_TYPE_FROM_CLASS (klass),
1293 G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
1295 g_cclosure_marshal_VOID__VOID,
1299 * LightDMGreeter::autologin-timer-expired:
1300 * @greeter: A #LightDMGreeter
1302 * The ::timed-login signal gets emitted when the automatic login timer has expired.
1303 * The application should then call lightdm_greeter_login().
1305 signals[AUTOLOGIN_TIMER_EXPIRED] =
1306 g_signal_new ("autologin-timer-expired",
1307 G_TYPE_FROM_CLASS (klass),
1309 G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),
1311 g_cclosure_marshal_VOID__VOID,