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;
57 GList *connect_requests;
58 GList *start_session_requests;
59 GList *ensure_shared_data_dir_requests;
62 guint autologin_timeout;
64 gchar *authentication_user;
65 gboolean in_authentication;
66 gboolean is_authenticated;
67 guint32 authenticate_sequence_number;
68 gboolean cancelling_authentication;
69 } LightDMGreeterPrivate;
71 G_DEFINE_TYPE (LightDMGreeter, lightdm_greeter, G_TYPE_OBJECT);
73 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_GREETER, LightDMGreeterPrivate)
76 #define MAX_MESSAGE_LENGTH 1024
78 /* Messages from the greeter to the server */
81 GREETER_MESSAGE_CONNECT = 0,
82 GREETER_MESSAGE_AUTHENTICATE,
83 GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
84 GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
85 GREETER_MESSAGE_START_SESSION,
86 GREETER_MESSAGE_CANCEL_AUTHENTICATION,
87 GREETER_MESSAGE_SET_LANGUAGE,
88 GREETER_MESSAGE_AUTHENTICATE_REMOTE,
89 GREETER_MESSAGE_ENSURE_SHARED_DIR,
92 /* Messages from the server to the greeter */
95 SERVER_MESSAGE_CONNECTED = 0,
96 SERVER_MESSAGE_PROMPT_AUTHENTICATION,
97 SERVER_MESSAGE_END_AUTHENTICATION,
98 SERVER_MESSAGE_SESSION_RESULT,
99 SERVER_MESSAGE_SHARED_DIR_RESULT,
102 /* Request sent to server */
105 GObject parent_instance;
112 GObjectClass parent_class;
114 GType request_get_type (void);
115 #define REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), request_get_type (), Request))
116 G_DEFINE_TYPE (Request, request, G_TYPE_OBJECT);
119 * lightdm_greeter_new:
121 * Create a new greeter.
123 * Return value: the new #LightDMGreeter
126 lightdm_greeter_new ()
128 return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
136 request = g_object_new (request_get_type (), NULL);
142 timed_login_cb (gpointer data)
144 LightDMGreeter *greeter = data;
145 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
147 priv->autologin_timeout = 0;
148 g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
160 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
162 if (*offset + 4 >= buffer_length)
164 buffer[*offset] = value >> 24;
165 buffer[*offset+1] = (value >> 16) & 0xFF;
166 buffer[*offset+2] = (value >> 8) & 0xFF;
167 buffer[*offset+3] = value & 0xFF;
172 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
177 length = strlen (value);
178 write_int (buffer, buffer_length, length, offset);
179 if (*offset + length >= buffer_length)
181 memcpy (buffer + *offset, value, length);
186 read_int (guint8 *message, gsize message_length, gsize *offset)
191 if (message_length - *offset < int_length ())
193 g_warning ("Not enough space for int, need %i, got %zi", int_length (), message_length - *offset);
197 buffer = message + *offset;
198 value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
199 *offset += int_length ();
205 read_string (guint8 *message, gsize message_length, gsize *offset)
210 length = read_int (message, message_length, offset);
211 if (message_length - *offset < length)
213 g_warning ("Not enough space for string, need %u, got %zu", length, message_length - *offset);
214 return g_strdup ("");
217 value = g_malloc (sizeof (gchar) * (length + 1));
218 memcpy (value, message + *offset, length);
219 value[length] = '\0';
226 string_length (const gchar *value)
229 return int_length () + strlen (value);
231 return int_length ();
235 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
237 write_int (buffer, buffer_length, id, offset);
238 write_int (buffer, buffer_length, length, offset);
242 get_message_length (guint8 *message, gsize message_length)
245 return read_int (message, message_length, &offset);
249 write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
251 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
253 GError *error = NULL;
254 guint32 stated_length;
256 /* Double check that we're sending well-formed messages. If we say we're
257 sending more than we do, we end up DOS'ing lightdm as it waits for the
258 rest. If we say we're sending less than we do, we confuse the heck out
259 of lightdm, as it starts reading headers from the middle of our
261 stated_length = HEADER_SIZE + get_message_length (message, message_length);
262 if (stated_length != message_length)
264 g_warning ("Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu", stated_length, message_length);
268 status = g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, &error);
270 g_warning ("Error writing to daemon: %s", error->message);
271 g_clear_error (&error);
272 if (status == G_IO_STATUS_NORMAL)
273 g_debug ("Wrote %zi bytes to daemon", message_length);
274 g_io_channel_flush (priv->to_server_channel, NULL);
278 handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
280 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
282 GString *hint_string;
286 version = read_string (message, message_length, offset);
287 hint_string = g_string_new ("");
288 while (*offset < message_length)
292 name = read_string (message, message_length, offset);
293 value = read_string (message, message_length, offset);
294 g_hash_table_insert (priv->hints, name, value);
295 g_string_append_printf (hint_string, " %s=%s", name, value);
298 priv->connected = TRUE;
299 g_debug ("Connected version=%s%s", version, hint_string->str);
301 g_string_free (hint_string, TRUE);
303 /* Set timeout for default login */
304 timeout = lightdm_greeter_get_autologin_timeout_hint (greeter);
307 g_debug ("Setting autologin timer for %d seconds", timeout);
308 priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
311 request = g_list_nth_data (priv->connect_requests, 0);
314 request->complete = TRUE;
315 priv->connect_requests = g_list_remove (priv->connect_requests, request);
316 g_object_unref (request);
321 handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
323 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
324 guint32 sequence_number, n_messages, i;
327 sequence_number = read_int (message, message_length, offset);
328 if (sequence_number != priv->authenticate_sequence_number)
330 g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
334 if (priv->cancelling_authentication)
336 g_debug ("Ignoring prompt authentication as waiting for it to cancel");
340 /* Update username */
341 username = read_string (message, message_length, offset);
342 if (strcmp (username, "") == 0)
347 g_free (priv->authentication_user);
348 priv->authentication_user = username;
350 g_list_free_full (priv->responses_received, g_free);
351 priv->responses_received = NULL;
352 priv->n_responses_waiting = 0;
354 n_messages = read_int (message, message_length, offset);
355 g_debug ("Prompt user with %d message(s)", n_messages);
357 for (i = 0; i < n_messages; i++)
362 style = read_int (message, message_length, offset);
363 text = read_string (message, message_length, offset);
365 // FIXME: Should stop on prompts?
368 case PAM_PROMPT_ECHO_OFF:
369 priv->n_responses_waiting++;
370 g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_SECRET);
372 case PAM_PROMPT_ECHO_ON:
373 priv->n_responses_waiting++;
374 g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_QUESTION);
377 g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_ERROR);
380 g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_INFO);
389 handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
391 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
392 guint32 sequence_number, return_code;
395 sequence_number = read_int (message, message_length, offset);
397 if (sequence_number != priv->authenticate_sequence_number)
399 g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
403 username = read_string (message, message_length, offset);
404 return_code = read_int (message, message_length, offset);
406 g_debug ("Authentication complete for user %s with return code %d", username, return_code);
408 /* Update username */
409 if (strcmp (username, "") == 0)
414 g_free (priv->authentication_user);
415 priv->authentication_user = username;
417 priv->cancelling_authentication = FALSE;
418 priv->is_authenticated = (return_code == 0);
420 priv->in_authentication = FALSE;
421 g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
425 handle_session_result (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
427 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
430 request = g_list_nth_data (priv->start_session_requests, 0);
433 request->return_code = read_int (message, message_length, offset);
434 request->complete = TRUE;
435 priv->start_session_requests = g_list_remove (priv->start_session_requests, request);
436 g_object_unref (request);
441 handle_shared_dir_result (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
443 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
446 request = g_list_nth_data (priv->ensure_shared_data_dir_requests, 0);
449 request->dir = read_string (message, message_length, offset);
450 /* Blank data dir means invalid user */
451 if (g_strcmp0 (request->dir, "") == 0)
453 g_free (request->dir);
456 request->complete = TRUE;
457 priv->ensure_shared_data_dir_requests = g_list_remove (priv->ensure_shared_data_dir_requests, request);
458 g_object_unref (request);
463 handle_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
468 id = read_int (message, message_length, &offset);
469 read_int (message, message_length, &offset);
472 case SERVER_MESSAGE_CONNECTED:
473 handle_connected (greeter, message, message_length, &offset);
475 case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
476 handle_prompt_authentication (greeter, message, message_length, &offset);
478 case SERVER_MESSAGE_END_AUTHENTICATION:
479 handle_end_authentication (greeter, message, message_length, &offset);
481 case SERVER_MESSAGE_SESSION_RESULT:
482 handle_session_result (greeter, message, message_length, &offset);
484 case SERVER_MESSAGE_SHARED_DIR_RESULT:
485 handle_shared_dir_result (greeter, message, message_length, &offset);
488 g_warning ("Unknown message from server: %d", id);
494 read_message (LightDMGreeter *greeter, gsize *length, gboolean block)
496 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
497 gsize n_to_read, n_read;
499 GError *error = NULL;
501 /* Read the header, or the whole message if we already have that */
502 n_to_read = HEADER_SIZE;
503 if (priv->n_read >= HEADER_SIZE)
504 n_to_read += get_message_length (priv->read_buffer, priv->n_read);
509 status = g_io_channel_read_chars (priv->from_server_channel,
510 (gchar *) priv->read_buffer + priv->n_read,
511 n_to_read - priv->n_read,
515 g_warning ("Error reading from server: %s", error->message);
516 g_clear_error (&error);
517 if (status != G_IO_STATUS_NORMAL)
520 g_debug ("Read %zi bytes from daemon", n_read);
522 priv->n_read += n_read;
523 } while (priv->n_read < n_to_read && block);
525 /* Stop if haven't got all the data we want */
526 if (priv->n_read != n_to_read)
529 /* If have header, rerun for content */
530 if (priv->n_read == HEADER_SIZE)
532 n_to_read = get_message_length (priv->read_buffer, priv->n_read);
535 priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
536 return read_message (greeter, length, block);
540 buffer = priv->read_buffer;
541 *length = priv->n_read;
543 priv->read_buffer = g_malloc (priv->n_read);
550 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
552 LightDMGreeter *greeter = data;
554 gsize message_length;
556 /* Read one message and process it */
557 message = read_message (greeter, &message_length, FALSE);
560 handle_message (greeter, message, message_length);
568 send_connect (LightDMGreeter *greeter)
570 guint8 message[MAX_MESSAGE_LENGTH];
573 g_debug ("Connecting to display manager...");
574 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
575 write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
576 write_message (greeter, message, offset);
580 send_start_session (LightDMGreeter *greeter, const gchar *session)
582 guint8 message[MAX_MESSAGE_LENGTH];
586 g_debug ("Starting session %s", session);
588 g_debug ("Starting default session");
590 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
591 write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
592 write_message (greeter, message, offset);
596 send_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username)
598 guint8 message[MAX_MESSAGE_LENGTH];
601 g_debug ("Ensuring data directory for user %s", username);
603 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_ENSURE_SHARED_DIR, string_length (username), &offset);
604 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
605 write_message (greeter, message, offset);
609 * lightdm_greeter_connect_sync:
610 * @greeter: The greeter to connect
611 * @error: return location for a #GError, or %NULL
613 * Connects the greeter to the display manager. Will block until connected.
615 * Return value: #TRUE if successfully connected
618 lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
620 LightDMGreeterPrivate *priv;
624 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
626 priv = GET_PRIVATE (greeter);
628 fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
631 g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
634 priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
635 g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
637 fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
640 g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
643 priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
644 g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
645 g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
647 /* Read until we are connected */
648 send_connect (greeter);
649 request = request_new ();
650 priv->connect_requests = g_list_append (priv->connect_requests, g_object_ref (request));
654 gsize message_length;
656 message = read_message (greeter, &message_length, TRUE);
659 handle_message (greeter, message, message_length);
661 } while (!request->complete);
663 g_object_unref (request);
665 return request->complete;
669 * lightdm_greeter_get_hint:
670 * @greeter: A #LightDMGreeter
671 * @name: The hint name to query.
675 * Return value: The value for this hint or #NULL if not set.
678 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
680 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
681 return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
685 * lightdm_greeter_get_default_session_hint:
686 * @greeter: A #LightDMGreeter
688 * Get the default session to use.
690 * Return value: The session name
693 lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
695 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
696 return lightdm_greeter_get_hint (greeter, "default-session");
700 * lightdm_greeter_get_hide_users_hint:
701 * @greeter: A #LightDMGreeter
703 * Check if user accounts should be shown. If this is TRUE then the list of
704 * accounts should be taken from #LightDMUserList and displayed in the greeter
705 * for the user to choose from. Note that this list can be empty and it is
706 * recommended you show a method for the user to enter a username manually.
708 * If this option is shown the greeter should only allow these users to be
709 * chosen for login unless the manual login hint is set.
711 * Return value: #TRUE if the available users should not be shown.
714 lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
718 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
719 value = lightdm_greeter_get_hint (greeter, "hide-users");
721 return g_strcmp0 (value, "true") == 0;
725 * lightdm_greeter_get_show_manual_login_hint:
726 * @greeter: A #LightDMGreeter
728 * Check if a manual login option should be shown. If set the GUI
729 * should provide a way for a username to be entered manually.
730 * Without this hint a greeter which is showing a user list can
731 * limit logins to only those users.
733 * Return value: #TRUE if a manual login option should be shown.
736 lightdm_greeter_get_show_manual_login_hint (LightDMGreeter *greeter)
740 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
741 value = lightdm_greeter_get_hint (greeter, "show-manual-login");
743 return g_strcmp0 (value, "true") == 0;
747 * lightdm_greeter_get_show_remote_login_hint:
748 * @greeter: A #LightDMGreeter
750 * Check if a remote login option should be shown. If set the GUI
751 * should provide a way for a user to log into a remote desktop server.
753 * Return value: #TRUE if a remote login option should be shown.
756 lightdm_greeter_get_show_remote_login_hint (LightDMGreeter *greeter)
760 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
761 value = lightdm_greeter_get_hint (greeter, "show-remote-login");
763 return g_strcmp0 (value, "true") == 0;
767 * lightdm_greeter_get_lock_hint:
768 * @greeter: A #LightDMGreeter
770 * Check if the greeter is acting as a lock screen.
772 * Return value: #TRUE if the greeter was triggered by locking the seat.
775 lightdm_greeter_get_lock_hint (LightDMGreeter *greeter)
779 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
780 value = lightdm_greeter_get_hint (greeter, "lock-screen");
782 return g_strcmp0 (value, "true") == 0;
786 * lightdm_greeter_get_has_guest_account_hint:
787 * @greeter: A #LightDMGreeter
789 * Check if guest sessions are supported.
791 * Return value: #TRUE if guest sessions are supported.
794 lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
798 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
799 value = lightdm_greeter_get_hint (greeter, "has-guest-account");
801 return g_strcmp0 (value, "true") == 0;
805 * lightdm_greeter_get_select_user_hint:
806 * @greeter: A #LightDMGreeter
808 * Get the user to select by default.
810 * Return value: A username
813 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
815 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
816 return lightdm_greeter_get_hint (greeter, "select-user");
820 * lightdm_greeter_get_select_guest_hint:
821 * @greeter: A #LightDMGreeter
823 * Check if the guest account should be selected by default.
825 * Return value: #TRUE if the guest account should be selected by default.
828 lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
832 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
833 value = lightdm_greeter_get_hint (greeter, "select-guest");
835 return g_strcmp0 (value, "true") == 0;
839 * lightdm_greeter_get_autologin_user_hint:
840 * @greeter: A #LightDMGreeter
842 * Get the user account to automatically logg into when the timer expires.
844 * Return value: The user account to automatically log into.
847 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
849 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
850 return lightdm_greeter_get_hint (greeter, "autologin-user");
854 * lightdm_greeter_get_autologin_guest_hint:
855 * @greeter: A #LightDMGreeter
857 * Check if the guest account should be automatically logged into when the timer expires.
859 * Return value: #TRUE if the guest account should be automatically logged into.
862 lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
866 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
867 value = lightdm_greeter_get_hint (greeter, "autologin-guest");
869 return g_strcmp0 (value, "true") == 0;
873 * lightdm_greeter_get_autologin_timeout_hint:
874 * @greeter: A #LightDMGreeter
876 * Get the number of seconds to wait before automaitcally logging in.
878 * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
881 lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
886 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
887 value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
889 timeout = atoi (value);
897 * lightdm_greeter_cancel_autologin:
898 * @greeter: A #LightDMGreeter
900 * Cancel the automatic login.
903 lightdm_greeter_cancel_autologin (LightDMGreeter *greeter)
905 LightDMGreeterPrivate *priv;
907 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
909 priv = GET_PRIVATE (greeter);
911 if (priv->autologin_timeout)
912 g_source_remove (priv->autologin_timeout);
913 priv->autologin_timeout = 0;
917 * lightdm_greeter_authenticate:
918 * @greeter: A #LightDMGreeter
919 * @username: (allow-none): A username or #NULL to prompt for a username.
921 * Starts the authentication procedure for a user.
924 lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username)
926 LightDMGreeterPrivate *priv;
927 guint8 message[MAX_MESSAGE_LENGTH];
930 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
932 priv = GET_PRIVATE (greeter);
934 g_return_if_fail (priv->connected);
936 priv->cancelling_authentication = FALSE;
937 priv->authenticate_sequence_number++;
938 priv->in_authentication = TRUE;
939 priv->is_authenticated = FALSE;
940 if (username != priv->authentication_user)
942 g_free (priv->authentication_user);
943 priv->authentication_user = g_strdup (username);
946 g_debug ("Starting authentication for user %s...", username);
947 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset);
948 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
949 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
950 write_message (greeter, message, offset);
954 * lightdm_greeter_authenticate_as_guest:
955 * @greeter: A #LightDMGreeter
957 * Starts the authentication procedure for the guest user.
960 lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter)
962 LightDMGreeterPrivate *priv;
963 guint8 message[MAX_MESSAGE_LENGTH];
966 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
968 priv = GET_PRIVATE (greeter);
970 g_return_if_fail (priv->connected);
972 priv->cancelling_authentication = FALSE;
973 priv->authenticate_sequence_number++;
974 priv->in_authentication = TRUE;
975 priv->is_authenticated = FALSE;
976 g_free (priv->authentication_user);
977 priv->authentication_user = NULL;
979 g_debug ("Starting authentication for guest account...");
980 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset);
981 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
982 write_message (greeter, message, offset);
986 * lightdm_greeter_authenticate_autologin:
987 * @greeter: A #LightDMGreeter
989 * Starts the authentication procedure for the automatic login user.
992 lightdm_greeter_authenticate_autologin (LightDMGreeter *greeter)
996 user = lightdm_greeter_get_autologin_user_hint (greeter);
997 if (lightdm_greeter_get_autologin_guest_hint (greeter))
998 lightdm_greeter_authenticate_as_guest (greeter);
1000 lightdm_greeter_authenticate (greeter, user);
1004 * lightdm_greeter_authenticate_remote:
1005 * @greeter: A #LightDMGreeter
1006 * @session: The name of a remote session
1007 * @username: (allow-none): A username of #NULL to prompt for a username.
1009 * Start authentication for a remote session type.
1012 lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *session, const gchar *username)
1014 LightDMGreeterPrivate *priv;
1015 guint8 message[MAX_MESSAGE_LENGTH];
1018 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1020 priv = GET_PRIVATE (greeter);
1022 g_return_if_fail (priv->connected);
1024 priv->cancelling_authentication = FALSE;
1025 priv->authenticate_sequence_number++;
1026 priv->in_authentication = TRUE;
1027 priv->is_authenticated = FALSE;
1028 g_free (priv->authentication_user);
1029 priv->authentication_user = NULL;
1032 g_debug ("Starting authentication for remote session %s as user %s...", session, username);
1034 g_debug ("Starting authentication for remote session %s...", session);
1035 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_REMOTE, int_length () + string_length (session) + string_length (username), &offset);
1036 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
1037 write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
1038 write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
1039 write_message (greeter, message, offset);
1043 * lightdm_greeter_respond:
1044 * @greeter: A #LightDMGreeter
1045 * @response: Response to a prompt
1047 * Provide response to a prompt. May be one in a series.
1050 lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response)
1052 LightDMGreeterPrivate *priv;
1053 guint8 message[MAX_MESSAGE_LENGTH];
1056 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1057 g_return_if_fail (response != NULL);
1059 priv = GET_PRIVATE (greeter);
1061 g_return_if_fail (priv->connected);
1062 g_return_if_fail (priv->n_responses_waiting > 0);
1064 priv->n_responses_waiting--;
1065 priv->responses_received = g_list_append (priv->responses_received, g_strdup (response));
1067 if (priv->n_responses_waiting == 0)
1072 g_debug ("Providing response to display manager");
1074 msg_length = int_length ();
1075 for (iter = priv->responses_received; iter; iter = iter->next)
1077 msg_length += string_length ((gchar *)iter->data);
1080 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, msg_length, &offset);
1081 write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset);
1082 for (iter = priv->responses_received; iter; iter = iter->next)
1084 write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset);
1086 write_message (greeter, message, offset);
1088 g_list_free_full (priv->responses_received, g_free);
1089 priv->responses_received = NULL;
1094 * lightdm_greeter_cancel_authentication:
1095 * @greeter: A #LightDMGreeter
1097 * Cancel the current user authentication.
1100 lightdm_greeter_cancel_authentication (LightDMGreeter *greeter)
1102 LightDMGreeterPrivate *priv;
1103 guint8 message[MAX_MESSAGE_LENGTH];
1106 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1108 priv = GET_PRIVATE (greeter);
1110 g_return_if_fail (priv->connected);
1112 priv->cancelling_authentication = TRUE;
1113 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
1114 write_message (greeter, message, offset);
1118 * lightdm_greeter_get_in_authentication:
1119 * @greeter: A #LightDMGreeter
1121 * Checks if the greeter is in the process of authenticating.
1123 * Return value: #TRUE if the greeter is authenticating a user.
1126 lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
1128 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1129 return GET_PRIVATE (greeter)->in_authentication;
1133 * lightdm_greeter_get_is_authenticated:
1134 * @greeter: A #LightDMGreeter
1136 * Checks if the greeter has successfully authenticated.
1138 * Return value: #TRUE if the greeter is authenticated for login.
1141 lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
1143 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1144 return GET_PRIVATE (greeter)->is_authenticated;
1148 * lightdm_greeter_get_authentication_user:
1149 * @greeter: A #LightDMGreeter
1151 * Get the user that is being authenticated.
1153 * Return value: The username of the authentication user being authenticated or #NULL if no authentication in progress.
1156 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
1158 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1159 return GET_PRIVATE (greeter)->authentication_user;
1163 * lightdm_greeter_set_language:
1164 * @greeter: A #LightDMGreeter
1165 * @language: The language to use for this user in the form of a locale specification (e.g. "de_DE.UTF-8").
1167 * Set the language for the currently authenticated user.
1170 lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language)
1172 LightDMGreeterPrivate *priv;
1173 guint8 message[MAX_MESSAGE_LENGTH];
1176 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1178 priv = GET_PRIVATE (greeter);
1180 g_return_if_fail (priv->connected);
1182 write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset);
1183 write_string (message, MAX_MESSAGE_LENGTH, language, &offset);
1184 write_message (greeter, message, offset);
1188 * lightdm_greeter_start_session_sync:
1189 * @greeter: A #LightDMGreeter
1190 * @session: (allow-none): The session to log into or #NULL to use the default.
1191 * @error: return location for a #GError, or %NULL
1193 * Start a session for the authenticated user.
1195 * Return value: TRUE if the session was started.
1198 lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
1200 LightDMGreeterPrivate *priv;
1202 guint32 return_code;
1204 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1206 priv = GET_PRIVATE (greeter);
1208 g_return_val_if_fail (priv->connected, FALSE);
1209 g_return_val_if_fail (priv->is_authenticated, FALSE);
1211 /* Read until the session is started */
1212 send_start_session (greeter, session);
1213 request = request_new ();
1214 priv->start_session_requests = g_list_append (priv->start_session_requests, g_object_ref (request));
1218 gsize message_length;
1220 message = read_message (greeter, &message_length, TRUE);
1223 handle_message (greeter, message, message_length);
1225 } while (!request->complete);
1227 return_code = request->return_code;
1228 g_object_unref (request);
1230 return return_code == 0;
1234 * lightdm_greeter_ensure_shared_data_dir_sync:
1235 * @greeter: A #LightDMGreeter
1236 * @username: A username
1238 * Ensure that a shared data dir for the given user is available. Both the
1239 * greeter user and @username will have write access to that folder. The
1240 * intention is that larger pieces of shared data would be stored there (files
1241 * that the greeter creates but wants to give to a user -- like camera
1242 * photos -- or files that the user creates but wants the greeter to
1243 * see -- like contact avatars).
1245 * LightDM will automatically create these if the user actually logs in, so
1246 * greeters only need to call this method if they want to store something in
1247 * the directory themselves.
1249 * Return value: The path to the shared directory, free with g_free
1252 lightdm_greeter_ensure_shared_data_dir_sync (LightDMGreeter *greeter, const gchar *username)
1254 LightDMGreeterPrivate *priv;
1258 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1260 priv = GET_PRIVATE (greeter);
1262 g_return_val_if_fail (priv->connected, NULL);
1264 /* Read until a response */
1265 send_ensure_shared_data_dir (greeter, username);
1266 request = request_new ();
1267 priv->ensure_shared_data_dir_requests = g_list_append (priv->ensure_shared_data_dir_requests, g_object_ref (request));
1271 gsize message_length;
1273 message = read_message (greeter, &message_length, TRUE);
1276 handle_message (greeter, message, message_length);
1278 } while (!request->complete);
1280 data_dir = g_strdup (request->dir);
1281 g_object_unref (request);
1287 lightdm_greeter_init (LightDMGreeter *greeter)
1289 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1291 priv->read_buffer = g_malloc (HEADER_SIZE);
1292 priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1296 lightdm_greeter_set_property (GObject *object,
1298 const GValue *value,
1301 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1305 lightdm_greeter_get_property (GObject *object,
1310 LightDMGreeter *self;
1312 self = LIGHTDM_GREETER (object);
1315 case PROP_DEFAULT_SESSION_HINT:
1316 g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
1318 case PROP_HIDE_USERS_HINT:
1319 g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
1321 case PROP_SHOW_MANUAL_LOGIN_HINT:
1322 g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
1324 case PROP_SHOW_REMOTE_LOGIN_HINT:
1325 g_value_set_boolean (value, lightdm_greeter_get_show_remote_login_hint (self));
1327 case PROP_LOCK_HINT:
1328 g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
1330 case PROP_HAS_GUEST_ACCOUNT_HINT:
1331 g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
1333 case PROP_SELECT_USER_HINT:
1334 g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
1336 case PROP_SELECT_GUEST_HINT:
1337 g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
1339 case PROP_AUTOLOGIN_USER_HINT:
1340 g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
1342 case PROP_AUTOLOGIN_GUEST_HINT:
1343 g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
1345 case PROP_AUTOLOGIN_TIMEOUT_HINT:
1346 g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
1348 case PROP_AUTHENTICATION_USER:
1349 g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
1351 case PROP_IN_AUTHENTICATION:
1352 g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
1354 case PROP_IS_AUTHENTICATED:
1355 g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
1358 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1364 lightdm_greeter_finalize (GObject *object)
1366 LightDMGreeter *self = LIGHTDM_GREETER (object);
1367 LightDMGreeterPrivate *priv = GET_PRIVATE (self);
1369 if (priv->to_server_channel)
1370 g_io_channel_unref (priv->to_server_channel);
1371 if (priv->from_server_channel)
1372 g_io_channel_unref (priv->from_server_channel);
1373 g_free (priv->authentication_user);
1374 g_hash_table_unref (priv->hints);
1376 G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
1380 lightdm_greeter_class_init (LightDMGreeterClass *klass)
1382 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1384 g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
1386 object_class->set_property = lightdm_greeter_set_property;
1387 object_class->get_property = lightdm_greeter_get_property;
1388 object_class->finalize = lightdm_greeter_finalize;
1390 g_object_class_install_property (object_class,
1391 PROP_DEFAULT_SESSION_HINT,
1392 g_param_spec_string ("default-session-hint",
1393 "default-session-hint",
1394 "Default session hint",
1396 G_PARAM_READWRITE));
1398 g_object_class_install_property (object_class,
1399 PROP_HIDE_USERS_HINT,
1400 g_param_spec_boolean ("hide-users-hint",
1406 g_object_class_install_property (object_class,
1407 PROP_SHOW_MANUAL_LOGIN_HINT,
1408 g_param_spec_boolean ("show-manual-login-hint",
1409 "show-manual-login-hint",
1410 "Show manual login hint",
1414 g_object_class_install_property (object_class,
1415 PROP_SHOW_REMOTE_LOGIN_HINT,
1416 g_param_spec_boolean ("show-remote-login-hint",
1417 "show-remote-login-hint",
1418 "Show remote login hint",
1422 g_object_class_install_property (object_class,
1424 g_param_spec_boolean ("lock-hint",
1430 g_object_class_install_property (object_class,
1431 PROP_HAS_GUEST_ACCOUNT_HINT,
1432 g_param_spec_boolean ("has-guest-account-hint",
1433 "has-guest-account-hint",
1434 "Has guest account hint",
1438 g_object_class_install_property (object_class,
1439 PROP_SELECT_USER_HINT,
1440 g_param_spec_string ("select-user-hint",
1446 g_object_class_install_property (object_class,
1447 PROP_SELECT_GUEST_HINT,
1448 g_param_spec_boolean ("select-guest-hint",
1449 "select-guest-hint",
1450 "Select guest account hint",
1454 g_object_class_install_property (object_class,
1455 PROP_AUTOLOGIN_USER_HINT,
1456 g_param_spec_string ("autologin-user-hint",
1457 "autologin-user-hint",
1458 "Autologin user hint",
1462 g_object_class_install_property (object_class,
1463 PROP_AUTOLOGIN_GUEST_HINT,
1464 g_param_spec_boolean ("autologin-guest-hint",
1465 "autologin-guest-hint",
1466 "Autologin guest account hint",
1470 g_object_class_install_property (object_class,
1471 PROP_AUTOLOGIN_TIMEOUT_HINT,
1472 g_param_spec_int ("autologin-timeout-hint",
1473 "autologin-timeout-hint",
1474 "Autologin timeout hint",
1478 g_object_class_install_property (object_class,
1479 PROP_AUTHENTICATION_USER,
1480 g_param_spec_string ("authentication-user",
1481 "authentication-user",
1482 "The user being authenticated",
1485 g_object_class_install_property (object_class,
1486 PROP_IN_AUTHENTICATION,
1487 g_param_spec_boolean ("in-authentication",
1488 "in-authentication",
1489 "TRUE if a user is being authenticated",
1492 g_object_class_install_property (object_class,
1493 PROP_IS_AUTHENTICATED,
1494 g_param_spec_boolean ("is-authenticated",
1496 "TRUE if the selected user is authenticated",
1501 * LightDMGreeter::show-prompt:
1502 * @greeter: A #LightDMGreeter
1503 * @text: Prompt text
1504 * @type: Prompt type
1506 * The ::show-prompt signal gets emitted when the greeter should show a
1507 * prompt to the user. The given text should be displayed and an input
1508 * field for the user to provide a response.
1510 * Call lightdm_greeter_respond() with the resultant input or
1511 * lightdm_greeter_cancel_authentication() to abort the authentication.
1513 signals[SHOW_PROMPT] =
1514 g_signal_new ("show-prompt",
1515 G_TYPE_FROM_CLASS (klass),
1517 G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
1520 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1523 * LightDMGreeter::show-message:
1524 * @greeter: A #LightDMGreeter
1525 * @text: Message text
1526 * @type: Message type
1528 * The ::show-message signal gets emitted when the greeter
1529 * should show a message to the user.
1531 signals[SHOW_MESSAGE] =
1532 g_signal_new ("show-message",
1533 G_TYPE_FROM_CLASS (klass),
1535 G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
1538 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1541 * LightDMGreeter::authentication-complete:
1542 * @greeter: A #LightDMGreeter
1544 * The ::authentication-complete signal gets emitted when the greeter
1545 * has completed authentication.
1547 * Call lightdm_greeter_get_is_authenticated() to check if the authentication
1550 signals[AUTHENTICATION_COMPLETE] =
1551 g_signal_new ("authentication-complete",
1552 G_TYPE_FROM_CLASS (klass),
1554 G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
1560 * LightDMGreeter::autologin-timer-expired:
1561 * @greeter: A #LightDMGreeter
1563 * The ::timed-login signal gets emitted when the automatic login timer has expired.
1564 * The application should then call lightdm_greeter_login().
1566 signals[AUTOLOGIN_TIMER_EXPIRED] =
1567 g_signal_new ("autologin-timer-expired",
1568 G_TYPE_FROM_CLASS (klass),
1570 G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),
1577 request_init (Request *request)
1582 request_finalize (GObject *object)
1584 Request *request = REQUEST (object);
1586 g_free (request->dir);
1588 G_OBJECT_CLASS (request_parent_class)->finalize (object);
1592 request_class_init (RequestClass *klass)
1594 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1595 object_class->finalize = request_finalize;