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.
16 #include <gio/gunixsocketaddress.h>
17 #include <security/pam_appl.h>
19 #include "lightdm/greeter.h"
21 G_DEFINE_QUARK (lightdm_greeter_error, lightdm_greeter_error)
25 PROP_DEFAULT_SESSION_HINT,
27 PROP_SHOW_MANUAL_LOGIN_HINT,
28 PROP_SHOW_REMOTE_LOGIN_HINT,
30 PROP_HAS_GUEST_ACCOUNT_HINT,
31 PROP_SELECT_USER_HINT,
32 PROP_SELECT_GUEST_HINT,
33 PROP_AUTOLOGIN_USER_HINT,
34 PROP_AUTOLOGIN_GUEST_HINT,
35 PROP_AUTOLOGIN_TIMEOUT_HINT,
36 PROP_AUTHENTICATION_USER,
37 PROP_IN_AUTHENTICATION,
38 PROP_IS_AUTHENTICATED,
44 AUTHENTICATION_COMPLETE,
45 AUTOLOGIN_TIMER_EXPIRED,
50 static guint signals[LAST_SIGNAL] = { 0 };
54 /* TRUE if the daemon can reuse this greeter */
57 /* Socket connection to daemon */
60 /* Channel to write to daemon */
61 GIOChannel *to_server_channel;
63 /* Channel to read from daemon */
64 GIOChannel *from_server_channel;
65 guint from_server_watch;
67 /* Data read from the daemon */
71 gsize n_responses_waiting;
72 GList *responses_received;
74 /* TRUE if have got a connect response */
77 /* Pending connect requests */
78 GList *connect_requests;
80 /* Pending start session requests */
81 GList *start_session_requests;
83 /* Pending ensure shared data dir requests */
84 GList *ensure_shared_data_dir_requests;
86 /* Hints provided by the daemon */
89 /* Timeout source to notify greeter to autologin */
90 guint autologin_timeout;
92 gchar *authentication_user;
93 gboolean in_authentication;
94 gboolean is_authenticated;
95 guint32 authenticate_sequence_number;
96 gboolean cancelling_authentication;
97 } LightDMGreeterPrivate;
99 G_DEFINE_TYPE (LightDMGreeter, lightdm_greeter, G_TYPE_OBJECT);
101 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_GREETER, LightDMGreeterPrivate)
103 #define HEADER_SIZE 8
104 #define MAX_MESSAGE_LENGTH 1024
106 /* Messages from the greeter to the server */
109 GREETER_MESSAGE_CONNECT = 0,
110 GREETER_MESSAGE_AUTHENTICATE,
111 GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
112 GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
113 GREETER_MESSAGE_START_SESSION,
114 GREETER_MESSAGE_CANCEL_AUTHENTICATION,
115 GREETER_MESSAGE_SET_LANGUAGE,
116 GREETER_MESSAGE_AUTHENTICATE_REMOTE,
117 GREETER_MESSAGE_ENSURE_SHARED_DIR,
120 /* Messages from the server to the greeter */
123 SERVER_MESSAGE_CONNECTED = 0,
124 SERVER_MESSAGE_PROMPT_AUTHENTICATION,
125 SERVER_MESSAGE_END_AUTHENTICATION,
126 SERVER_MESSAGE_SESSION_RESULT,
127 SERVER_MESSAGE_SHARED_DIR_RESULT,
129 SERVER_MESSAGE_RESET,
132 /* Request sent to server */
135 GObject parent_instance;
136 LightDMGreeter *greeter;
137 GCancellable *cancellable;
138 GAsyncReadyCallback callback;
147 GObjectClass parent_class;
149 GType request_get_type (void);
150 static void request_iface_init (GAsyncResultIface *iface);
151 #define REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), request_get_type (), Request))
152 G_DEFINE_TYPE_WITH_CODE (Request, request, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, request_iface_init));
154 static gboolean from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data);
157 lightdm_greeter_error_get_type (void)
159 static GType enum_type = 0;
161 if (G_UNLIKELY(enum_type == 0)) {
162 static const GEnumValue values[] = {
163 { LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR, "LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR", "communication-error" },
164 { LIGHTDM_GREETER_ERROR_CONNECTION_FAILED, "LIGHTDM_GREETER_ERROR_CONNECTION_FAILED", "connection-failed" },
165 { LIGHTDM_GREETER_ERROR_SESSION_FAILED, "LIGHTDM_GREETER_ERROR_SESSION_FAILED", "session-failed" },
166 { LIGHTDM_GREETER_ERROR_NO_AUTOLOGIN, "LIGHTDM_GREETER_ERROR_NO_AUTOLOGIN", "no-autologin" },
167 { LIGHTDM_GREETER_ERROR_INVALID_USER, "LIGHTDM_GREETER_ERROR_INVALID_USER", "invalid-user" },
170 enum_type = g_enum_register_static (g_intern_static_string ("LightDMGreeterError"), values);
177 lightdm_prompt_type_get_type (void)
179 static GType enum_type = 0;
181 if (G_UNLIKELY(enum_type == 0)) {
182 static const GEnumValue values[] = {
183 { LIGHTDM_PROMPT_TYPE_QUESTION, "LIGHTDM_PROMPT_TYPE_QUESTION", "question" },
184 { LIGHTDM_PROMPT_TYPE_SECRET, "LIGHTDM_PROMPT_TYPE_SECRET", "secret" },
187 enum_type = g_enum_register_static (g_intern_static_string ("LightDMPromptType"), values);
194 lightdm_message_type_get_type (void)
196 static GType enum_type = 0;
198 if (G_UNLIKELY(enum_type == 0)) {
199 static const GEnumValue values[] = {
200 { LIGHTDM_MESSAGE_TYPE_INFO, "LIGHTDM_MESSAGE_TYPE_INFO", "info" },
201 { LIGHTDM_MESSAGE_TYPE_ERROR, "LIGHTDM_MESSAGE_TYPE_ERROR", "error" },
204 enum_type = g_enum_register_static (g_intern_static_string ("LightDMMessageType"), values);
212 * lightdm_greeter_new:
214 * Create a new greeter.
216 * Return value: the new #LightDMGreeter
219 lightdm_greeter_new (void)
221 return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
225 * lightdm_greeter_set_resettable:
226 * @greeter: A #LightDMGreeter
227 * @resettable: Whether the greeter wants to be reset instead of killed after the user logs in
229 * Set whether the greeter will be reset instead of killed after the user logs in.
230 * This must be called before lightdm_greeter_connect is called.
233 lightdm_greeter_set_resettable (LightDMGreeter *greeter, gboolean resettable)
235 LightDMGreeterPrivate *priv;
237 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
239 priv = GET_PRIVATE (greeter);
241 g_return_if_fail (!priv->connected);
242 priv->resettable = resettable;
246 request_new (LightDMGreeter *greeter, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
250 request = g_object_new (request_get_type (), NULL);
251 request->greeter = g_object_ref (greeter);
253 request->cancellable = g_object_ref (cancellable);
254 request->callback = callback;
255 request->user_data = user_data;
261 request_callback_cb (gpointer data)
263 Request *request = data;
264 if (request->callback)
265 request->callback (G_OBJECT (request->greeter), G_ASYNC_RESULT (request), request->user_data);
266 g_object_unref (request);
267 return G_SOURCE_REMOVE;
271 request_complete (Request *request)
273 request->complete = TRUE;
275 if (!request->callback)
278 if (request->cancellable && g_cancellable_is_cancelled (request->cancellable))
281 g_idle_add (request_callback_cb, g_object_ref (request));
285 timed_login_cb (gpointer data)
287 LightDMGreeter *greeter = data;
288 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
290 priv->autologin_timeout = 0;
291 g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
303 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset, GError **error)
305 if (*offset + 4 >= buffer_length)
307 g_set_error_literal (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
308 "Not enough buffer space to write integer");
311 buffer[*offset] = value >> 24;
312 buffer[*offset+1] = (value >> 16) & 0xFF;
313 buffer[*offset+2] = (value >> 8) & 0xFF;
314 buffer[*offset+3] = value & 0xFF;
321 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset, GError **error)
326 length = strlen (value);
327 if (!write_int (buffer, buffer_length, length, offset, error))
329 if (*offset + length >= buffer_length)
331 g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
332 "Not enough buffer space to write string of length %d octets", length);
336 memcpy (buffer + *offset, value, length);
343 read_int (guint8 *message, gsize message_length, gsize *offset)
348 if (message_length - *offset < int_length ())
350 g_warning ("Not enough space for int, need %i, got %zi", int_length (), message_length - *offset);
354 buffer = message + *offset;
355 value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
356 *offset += int_length ();
362 read_string (guint8 *message, gsize message_length, gsize *offset)
367 length = read_int (message, message_length, offset);
368 if (message_length - *offset < length)
370 g_warning ("Not enough space for string, need %u, got %zu", length, message_length - *offset);
371 return g_strdup ("");
374 value = g_malloc (sizeof (gchar) * (length + 1));
375 memcpy (value, message + *offset, length);
376 value[length] = '\0';
383 string_length (const gchar *value)
386 return int_length () + strlen (value);
388 return int_length ();
392 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset, GError **error)
394 return write_int (buffer, buffer_length, id, offset, error) &&
395 write_int (buffer, buffer_length, length, offset, error);
399 get_message_length (guint8 *message, gsize message_length)
402 return read_int (message, message_length, &offset);
406 connect_to_daemon (LightDMGreeter *greeter, GError **error)
408 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
409 const gchar *to_server_fd, *from_server_fd, *pipe_path;
411 if (priv->to_server_channel || priv->from_server_channel)
414 /* Use private connection if one exists */
415 to_server_fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
416 from_server_fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
417 pipe_path = g_getenv ("LIGHTDM_GREETER_PIPE");
418 if (to_server_fd && from_server_fd)
420 priv->to_server_channel = g_io_channel_unix_new (atoi (to_server_fd));
421 priv->from_server_channel = g_io_channel_unix_new (atoi (from_server_fd));
425 GSocketAddress *address;
428 priv->socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, error);
432 address = g_unix_socket_address_new (pipe_path);
433 result = g_socket_connect (priv->socket, address, NULL, error);
434 g_object_unref (address);
438 priv->from_server_channel = g_io_channel_unix_new (g_socket_get_fd (priv->socket));
439 priv->to_server_channel = g_io_channel_ref (priv->from_server_channel);
443 g_set_error_literal (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_CONNECTION_FAILED,
444 "Unable to determine socket to daemon");
448 priv->from_server_watch = g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
450 if (!g_io_channel_set_encoding (priv->to_server_channel, NULL, error) ||
451 !g_io_channel_set_encoding (priv->from_server_channel, NULL, error))
458 send_message (LightDMGreeter *greeter, guint8 *message, gsize message_length, GError **error)
460 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
463 guint32 stated_length;
464 GError *flush_error = NULL;
466 if (!connect_to_daemon (greeter, error))
469 /* Double check that we're sending well-formed messages. If we say we're
470 sending more than we do, we end up DOS'ing lightdm as it waits for the
471 rest. If we say we're sending less than we do, we confuse the heck out
472 of lightdm, as it starts reading headers from the middle of our
474 stated_length = HEADER_SIZE + get_message_length (message, message_length);
475 if (stated_length != message_length)
477 g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
478 "Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu",
479 stated_length, message_length);
483 data = (gchar *) message;
484 data_length = message_length;
485 while (data_length > 0)
489 GError *write_error = NULL;
491 status = g_io_channel_write_chars (priv->to_server_channel, data, data_length, &n_written, &write_error);
493 g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
494 "Failed to write to daemon: %s",
495 write_error->message);
496 g_clear_error (&write_error);
497 if (status == G_IO_STATUS_AGAIN)
499 if (status != G_IO_STATUS_NORMAL)
501 data_length -= n_written;
505 g_debug ("Wrote %zi bytes to daemon", message_length);
506 if (!g_io_channel_flush (priv->to_server_channel, &flush_error))
508 g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
509 "Failed to write to daemon: %s",
510 flush_error->message);
511 g_clear_error (&flush_error);
519 handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
521 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
523 GString *hint_string;
527 version = read_string (message, message_length, offset);
528 hint_string = g_string_new ("");
529 while (*offset < message_length)
533 name = read_string (message, message_length, offset);
534 value = read_string (message, message_length, offset);
535 g_hash_table_insert (priv->hints, name, value);
536 g_string_append_printf (hint_string, " %s=%s", name, value);
539 priv->connected = TRUE;
540 g_debug ("Connected version=%s%s", version, hint_string->str);
542 g_string_free (hint_string, TRUE);
544 /* Set timeout for default login */
545 timeout = lightdm_greeter_get_autologin_timeout_hint (greeter);
548 g_debug ("Setting autologin timer for %d seconds", timeout);
549 priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
552 /* Notify asynchronous caller */
553 request = g_list_nth_data (priv->connect_requests, 0);
556 request->result = TRUE;
557 request_complete (request);
558 priv->connect_requests = g_list_remove (priv->connect_requests, request);
559 g_object_unref (request);
564 handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
566 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
567 guint32 sequence_number, n_messages, i;
570 sequence_number = read_int (message, message_length, offset);
571 if (sequence_number != priv->authenticate_sequence_number)
573 g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
577 if (priv->cancelling_authentication)
579 g_debug ("Ignoring prompt authentication as waiting for it to cancel");
583 /* Update username */
584 username = read_string (message, message_length, offset);
585 if (strcmp (username, "") == 0)
590 g_free (priv->authentication_user);
591 priv->authentication_user = username;
593 g_list_free_full (priv->responses_received, g_free);
594 priv->responses_received = NULL;
595 priv->n_responses_waiting = 0;
597 n_messages = read_int (message, message_length, offset);
598 g_debug ("Prompt user with %d message(s)", n_messages);
600 for (i = 0; i < n_messages; i++)
605 style = read_int (message, message_length, offset);
606 text = read_string (message, message_length, offset);
608 // FIXME: Should stop on prompts?
611 case PAM_PROMPT_ECHO_OFF:
612 priv->n_responses_waiting++;
613 g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_SECRET);
615 case PAM_PROMPT_ECHO_ON:
616 priv->n_responses_waiting++;
617 g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_QUESTION);
620 g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_ERROR);
623 g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_INFO);
632 handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
634 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
635 guint32 sequence_number, return_code;
638 sequence_number = read_int (message, message_length, offset);
640 if (sequence_number != priv->authenticate_sequence_number)
642 g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
646 username = read_string (message, message_length, offset);
647 return_code = read_int (message, message_length, offset);
649 g_debug ("Authentication complete for user %s with return code %d", username, return_code);
651 /* Update username */
652 if (strcmp (username, "") == 0)
657 g_free (priv->authentication_user);
658 priv->authentication_user = username;
660 priv->cancelling_authentication = FALSE;
661 priv->is_authenticated = (return_code == 0);
663 priv->in_authentication = FALSE;
664 g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
668 handle_idle (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
670 g_signal_emit (G_OBJECT (greeter), signals[IDLE], 0);
674 handle_reset (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
676 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
677 GString *hint_string;
679 g_hash_table_remove_all (priv->hints);
681 hint_string = g_string_new ("");
682 while (*offset < message_length)
686 name = read_string (message, message_length, offset);
687 value = read_string (message, message_length, offset);
688 g_hash_table_insert (priv->hints, name, value);
689 g_string_append_printf (hint_string, " %s=%s", name, value);
692 g_debug ("Reset%s", hint_string->str);
693 g_string_free (hint_string, TRUE);
695 g_signal_emit (G_OBJECT (greeter), signals[RESET], 0);
699 handle_session_result (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
701 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
704 /* Notify asynchronous caller */
705 request = g_list_nth_data (priv->start_session_requests, 0);
710 return_code = read_int (message, message_length, offset);
711 if (return_code == 0)
712 request->result = TRUE;
714 request->error = g_error_new (LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_SESSION_FAILED,
715 "Session returned error code %d", return_code);
716 request_complete (request);
717 priv->start_session_requests = g_list_remove (priv->start_session_requests, request);
718 g_object_unref (request);
723 handle_shared_dir_result (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
725 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
728 /* Notify asynchronous caller */
729 request = g_list_nth_data (priv->ensure_shared_data_dir_requests, 0);
732 request->dir = read_string (message, message_length, offset);
733 /* Blank data dir means invalid user */
734 if (g_strcmp0 (request->dir, "") == 0)
736 g_free (request->dir);
738 request->error = g_error_new (LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_INVALID_USER,
741 request_complete (request);
742 priv->ensure_shared_data_dir_requests = g_list_remove (priv->ensure_shared_data_dir_requests, request);
743 g_object_unref (request);
748 handle_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
753 id = read_int (message, message_length, &offset);
754 read_int (message, message_length, &offset);
757 case SERVER_MESSAGE_CONNECTED:
758 handle_connected (greeter, message, message_length, &offset);
760 case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
761 handle_prompt_authentication (greeter, message, message_length, &offset);
763 case SERVER_MESSAGE_END_AUTHENTICATION:
764 handle_end_authentication (greeter, message, message_length, &offset);
766 case SERVER_MESSAGE_SESSION_RESULT:
767 handle_session_result (greeter, message, message_length, &offset);
769 case SERVER_MESSAGE_SHARED_DIR_RESULT:
770 handle_shared_dir_result (greeter, message, message_length, &offset);
772 case SERVER_MESSAGE_IDLE:
773 handle_idle (greeter, message, message_length, &offset);
775 case SERVER_MESSAGE_RESET:
776 handle_reset (greeter, message, message_length, &offset);
779 g_warning ("Unknown message from server: %d", id);
785 recv_message (LightDMGreeter *greeter, gboolean block, guint8 **message, gsize *length, GError **error)
787 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
788 gsize n_to_read, n_read;
790 if (!connect_to_daemon (greeter, error))
793 /* Read the header, or the whole message if we already have that */
794 n_to_read = HEADER_SIZE;
795 if (priv->n_read >= HEADER_SIZE)
796 n_to_read += get_message_length (priv->read_buffer, priv->n_read);
801 GError *read_error = NULL;
803 status = g_io_channel_read_chars (priv->from_server_channel,
804 (gchar *) priv->read_buffer + priv->n_read,
805 n_to_read - priv->n_read,
808 if (status == G_IO_STATUS_AGAIN)
813 else if (status != G_IO_STATUS_NORMAL)
815 g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
816 "Failed to read from daemon: %s",
817 read_error->message);
818 g_clear_error (&read_error);
822 g_debug ("Read %zi bytes from daemon", n_read);
824 priv->n_read += n_read;
825 } while (priv->n_read < n_to_read && block);
827 /* Stop if haven't got all the data we want */
828 if (priv->n_read != n_to_read)
837 /* If have header, rerun for content */
838 if (priv->n_read == HEADER_SIZE)
840 n_to_read = get_message_length (priv->read_buffer, priv->n_read);
843 priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
844 return recv_message (greeter, block, message, length, error);
849 *message = priv->read_buffer;
851 g_free (priv->read_buffer);
853 *length = priv->n_read;
855 priv->read_buffer = g_malloc (priv->n_read);
862 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
864 LightDMGreeter *greeter = data;
866 gsize message_length;
867 GError *error = NULL;
869 /* Read one message and process it */
870 if (!recv_message (greeter, FALSE, &message, &message_length, &error))
872 // FIXME: Should push this up to the client somehow
873 g_warning ("Failed to read from daemon: %s\n", error->message);
874 g_clear_error (&error);
875 return G_SOURCE_REMOVE;
880 handle_message (greeter, message, message_length);
884 return G_SOURCE_CONTINUE;
888 send_connect (LightDMGreeter *greeter, gboolean resettable, GError **error)
890 guint8 message[MAX_MESSAGE_LENGTH];
893 g_debug ("Connecting to display manager...");
894 return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION) + int_length (), &offset, error) &&
895 write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset, error) &&
896 write_int (message, MAX_MESSAGE_LENGTH, resettable ? 1 : 0, &offset, error) &&
897 send_message (greeter, message, offset, error);
901 send_start_session (LightDMGreeter *greeter, const gchar *session, GError **error)
903 guint8 message[MAX_MESSAGE_LENGTH];
907 g_debug ("Starting session %s", session);
909 g_debug ("Starting default session");
911 return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset, error) &&
912 write_string (message, MAX_MESSAGE_LENGTH, session, &offset, error) &&
913 send_message (greeter, message, offset, error);
917 send_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username, GError **error)
919 guint8 message[MAX_MESSAGE_LENGTH];
922 g_debug ("Ensuring data directory for user %s", username);
924 return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_ENSURE_SHARED_DIR, string_length (username), &offset, error) &&
925 write_string (message, MAX_MESSAGE_LENGTH, username, &offset, error) &&
926 send_message (greeter, message, offset, error);
930 * lightdm_greeter_connect_to_daemon:
931 * @greeter: The greeter to connect
932 * @cancellable: (allow-none): A #GCancellable or %NULL.
933 * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
934 * @user_data: (allow-none): data to pass to the @callback or %NULL.
936 * Asynchronously connects the greeter to the display manager.
938 * When the operation is finished, @callback will be invoked. You can then call lightdm_greeter_connect_to_daemon_finish() to get the result of the operation.
940 * See lightdm_greeter_connect_to_daemon_sync() for the synchronous version.
943 lightdm_greeter_connect_to_daemon (LightDMGreeter *greeter, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
945 LightDMGreeterPrivate *priv;
947 GError *error = NULL;
949 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
951 priv = GET_PRIVATE (greeter);
953 request = request_new (greeter, cancellable, callback, user_data);
954 if (send_connect (greeter, priv->resettable, &error))
955 priv->connect_requests = g_list_append (priv->connect_requests, request);
958 request->error = error;
959 request_complete (request);
960 g_object_unref (request);
965 * lightdm_greeter_connect_to_daemon_finish:
966 * @greeter: The greeter the the request was done with
967 * @result: A #GAsyncResult.
968 * @error: return location for a #GError, or %NULL
970 * Finishes an operation started with lightdm_greeter_connect_to_daemon().
972 * Return value: #TRUE if successfully connected
975 lightdm_greeter_connect_to_daemon_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error)
977 Request *request = REQUEST (result);
979 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
982 g_propagate_error (error, request->error);
983 return request->result;
987 * lightdm_greeter_connect_to_daemon_sync:
988 * @greeter: The greeter to connect
989 * @error: return location for a #GError, or %NULL
991 * Connects the greeter to the display manager. Will block until connected.
993 * Return value: #TRUE if successfully connected
996 lightdm_greeter_connect_to_daemon_sync (LightDMGreeter *greeter, GError **error)
998 LightDMGreeterPrivate *priv;
1001 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1003 priv = GET_PRIVATE (greeter);
1005 /* Read until we are connected */
1006 if (!send_connect (greeter, priv->resettable, error))
1008 request = request_new (greeter, NULL, NULL, NULL);
1009 priv->connect_requests = g_list_append (priv->connect_requests, g_object_ref (request));
1013 gsize message_length;
1015 if (!recv_message (greeter, TRUE, &message, &message_length, error))
1017 handle_message (greeter, message, message_length);
1019 } while (!request->complete);
1021 return lightdm_greeter_connect_to_daemon_finish (greeter, G_ASYNC_RESULT (request), error);
1025 * lightdm_greeter_connect_sync:
1026 * @greeter: The greeter to connect
1027 * @error: return location for a #GError, or %NULL
1029 * Connects the greeter to the display manager. Will block until connected.
1031 * Return value: #TRUE if successfully connected
1033 * Deprecated: 1.11.1: Use lightdm_greeter_connect_to_daemon_sync() instead
1036 lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
1038 return lightdm_greeter_connect_to_daemon_sync (greeter, error);
1042 * lightdm_greeter_get_hint:
1043 * @greeter: A #LightDMGreeter
1044 * @name: The hint name to query.
1048 * Return value: (nullable): The value for this hint or #NULL if not set.
1051 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
1053 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1054 return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
1058 * lightdm_greeter_get_default_session_hint:
1059 * @greeter: A #LightDMGreeter
1061 * Get the default session to use.
1063 * Return value: The session name
1066 lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
1068 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1069 return lightdm_greeter_get_hint (greeter, "default-session");
1073 * lightdm_greeter_get_hide_users_hint:
1074 * @greeter: A #LightDMGreeter
1076 * Check if user accounts should be shown. If this is TRUE then the list of
1077 * accounts should be taken from #LightDMUserList and displayed in the greeter
1078 * for the user to choose from. Note that this list can be empty and it is
1079 * recommended you show a method for the user to enter a username manually.
1081 * If this option is shown the greeter should only allow these users to be
1082 * chosen for login unless the manual login hint is set.
1084 * Return value: #TRUE if the available users should not be shown.
1087 lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
1091 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1092 value = lightdm_greeter_get_hint (greeter, "hide-users");
1094 return g_strcmp0 (value, "true") == 0;
1098 * lightdm_greeter_get_show_manual_login_hint:
1099 * @greeter: A #LightDMGreeter
1101 * Check if a manual login option should be shown. If set the GUI
1102 * should provide a way for a username to be entered manually.
1103 * Without this hint a greeter which is showing a user list can
1104 * limit logins to only those users.
1106 * Return value: #TRUE if a manual login option should be shown.
1109 lightdm_greeter_get_show_manual_login_hint (LightDMGreeter *greeter)
1113 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1114 value = lightdm_greeter_get_hint (greeter, "show-manual-login");
1116 return g_strcmp0 (value, "true") == 0;
1120 * lightdm_greeter_get_show_remote_login_hint:
1121 * @greeter: A #LightDMGreeter
1123 * Check if a remote login option should be shown. If set the GUI
1124 * should provide a way for a user to log into a remote desktop server.
1126 * Return value: #TRUE if a remote login option should be shown.
1129 lightdm_greeter_get_show_remote_login_hint (LightDMGreeter *greeter)
1133 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1134 value = lightdm_greeter_get_hint (greeter, "show-remote-login");
1136 return g_strcmp0 (value, "true") == 0;
1140 * lightdm_greeter_get_lock_hint:
1141 * @greeter: A #LightDMGreeter
1143 * Check if the greeter is acting as a lock screen.
1145 * Return value: #TRUE if the greeter was triggered by locking the seat.
1148 lightdm_greeter_get_lock_hint (LightDMGreeter *greeter)
1152 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1153 value = lightdm_greeter_get_hint (greeter, "lock-screen");
1155 return g_strcmp0 (value, "true") == 0;
1159 * lightdm_greeter_get_has_guest_account_hint:
1160 * @greeter: A #LightDMGreeter
1162 * Check if guest sessions are supported.
1164 * Return value: #TRUE if guest sessions are supported.
1167 lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
1171 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1172 value = lightdm_greeter_get_hint (greeter, "has-guest-account");
1174 return g_strcmp0 (value, "true") == 0;
1178 * lightdm_greeter_get_select_user_hint:
1179 * @greeter: A #LightDMGreeter
1181 * Get the user to select by default.
1183 * Return value: (nullable): A username or %NULL if no particular user should be selected.
1186 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
1188 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1189 return lightdm_greeter_get_hint (greeter, "select-user");
1193 * lightdm_greeter_get_select_guest_hint:
1194 * @greeter: A #LightDMGreeter
1196 * Check if the guest account should be selected by default.
1198 * Return value: #TRUE if the guest account should be selected by default.
1201 lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
1205 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1206 value = lightdm_greeter_get_hint (greeter, "select-guest");
1208 return g_strcmp0 (value, "true") == 0;
1212 * lightdm_greeter_get_autologin_user_hint:
1213 * @greeter: A #LightDMGreeter
1215 * Get the user account to automatically log into when the timer expires.
1217 * Return value: (nullable): The user account to automatically log into or %NULL if none configured.
1220 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
1222 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1223 return lightdm_greeter_get_hint (greeter, "autologin-user");
1227 * lightdm_greeter_get_autologin_guest_hint:
1228 * @greeter: A #LightDMGreeter
1230 * Check if the guest account should be automatically logged into when the timer expires.
1232 * Return value: #TRUE if the guest account should be automatically logged into.
1235 lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
1239 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1240 value = lightdm_greeter_get_hint (greeter, "autologin-guest");
1242 return g_strcmp0 (value, "true") == 0;
1246 * lightdm_greeter_get_autologin_timeout_hint:
1247 * @greeter: A #LightDMGreeter
1249 * Get the number of seconds to wait before automaitcally logging in.
1251 * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
1254 lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
1259 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1260 value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
1262 timeout = atoi (value);
1270 * lightdm_greeter_cancel_autologin:
1271 * @greeter: A #LightDMGreeter
1273 * Cancel the automatic login.
1276 lightdm_greeter_cancel_autologin (LightDMGreeter *greeter)
1278 LightDMGreeterPrivate *priv;
1280 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1282 priv = GET_PRIVATE (greeter);
1284 if (priv->autologin_timeout)
1285 g_source_remove (priv->autologin_timeout);
1286 priv->autologin_timeout = 0;
1290 * lightdm_greeter_authenticate:
1291 * @greeter: A #LightDMGreeter
1292 * @username: (allow-none): A username or #NULL to prompt for a username.
1293 * @error: return location for a #GError, or %NULL
1295 * Starts the authentication procedure for a user.
1297 * Return value: #TRUE if authentication request sent.
1300 lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username, GError **error)
1302 LightDMGreeterPrivate *priv;
1303 guint8 message[MAX_MESSAGE_LENGTH];
1306 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1308 priv = GET_PRIVATE (greeter);
1310 g_return_val_if_fail (priv->connected, FALSE);
1312 priv->cancelling_authentication = FALSE;
1313 priv->authenticate_sequence_number++;
1314 priv->in_authentication = TRUE;
1315 priv->is_authenticated = FALSE;
1316 if (username != priv->authentication_user)
1318 g_free (priv->authentication_user);
1319 priv->authentication_user = g_strdup (username);
1322 g_debug ("Starting authentication for user %s...", username);
1323 return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset, error) &&
1324 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset, error) &&
1325 write_string (message, MAX_MESSAGE_LENGTH, username, &offset, error) &&
1326 send_message (greeter, message, offset, error);
1330 * lightdm_greeter_authenticate_as_guest:
1331 * @greeter: A #LightDMGreeter
1332 * @error: return location for a #GError, or %NULL
1334 * Starts the authentication procedure for the guest user.
1336 * Return value: #TRUE if authentication request sent.
1339 lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter, GError **error)
1341 LightDMGreeterPrivate *priv;
1342 guint8 message[MAX_MESSAGE_LENGTH];
1345 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1347 priv = GET_PRIVATE (greeter);
1349 g_return_val_if_fail (priv->connected, FALSE);
1351 priv->cancelling_authentication = FALSE;
1352 priv->authenticate_sequence_number++;
1353 priv->in_authentication = TRUE;
1354 priv->is_authenticated = FALSE;
1355 g_free (priv->authentication_user);
1356 priv->authentication_user = NULL;
1358 g_debug ("Starting authentication for guest account...");
1359 return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset, error) &&
1360 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset, error) &&
1361 send_message (greeter, message, offset, error);
1365 * lightdm_greeter_authenticate_autologin:
1366 * @greeter: A #LightDMGreeter
1367 * @error: return location for a #GError, or %NULL
1369 * Starts the authentication procedure for the automatic login user.
1371 * Return value: #TRUE if authentication request sent.
1374 lightdm_greeter_authenticate_autologin (LightDMGreeter *greeter, GError **error)
1378 user = lightdm_greeter_get_autologin_user_hint (greeter);
1379 if (lightdm_greeter_get_autologin_guest_hint (greeter))
1380 return lightdm_greeter_authenticate_as_guest (greeter, error);
1382 return lightdm_greeter_authenticate (greeter, user, error);
1385 g_set_error_literal (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_NO_AUTOLOGIN,
1386 "Can't authenticate autologin; autologin not configured");
1392 * lightdm_greeter_authenticate_remote:
1393 * @greeter: A #LightDMGreeter
1394 * @session: The name of a remote session
1395 * @username: (allow-none): A username of #NULL to prompt for a username.
1396 * @error: return location for a #GError, or %NULL
1398 * Start authentication for a remote session type.
1400 * Return value: #TRUE if authentication request sent.
1403 lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *session, const gchar *username, GError **error)
1405 LightDMGreeterPrivate *priv;
1406 guint8 message[MAX_MESSAGE_LENGTH];
1409 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1411 priv = GET_PRIVATE (greeter);
1413 g_return_val_if_fail (priv->connected, FALSE);
1415 priv->cancelling_authentication = FALSE;
1416 priv->authenticate_sequence_number++;
1417 priv->in_authentication = TRUE;
1418 priv->is_authenticated = FALSE;
1419 g_free (priv->authentication_user);
1420 priv->authentication_user = NULL;
1423 g_debug ("Starting authentication for remote session %s as user %s...", session, username);
1425 g_debug ("Starting authentication for remote session %s...", session);
1427 return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_REMOTE, int_length () + string_length (session) + string_length (username), &offset, error) &&
1428 write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset, error) &&
1429 write_string (message, MAX_MESSAGE_LENGTH, session, &offset, error) &&
1430 write_string (message, MAX_MESSAGE_LENGTH, username, &offset, error) &&
1431 send_message (greeter, message, offset, error);
1435 * lightdm_greeter_respond:
1436 * @greeter: A #LightDMGreeter
1437 * @response: Response to a prompt
1438 * @error: return location for a #GError, or %NULL
1440 * Provide response to a prompt. May be one in a series.
1442 * Return value: #TRUE if response sent.
1445 lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response, GError **error)
1447 LightDMGreeterPrivate *priv;
1448 guint8 message[MAX_MESSAGE_LENGTH];
1451 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1452 g_return_val_if_fail (response != NULL, FALSE);
1454 priv = GET_PRIVATE (greeter);
1456 g_return_val_if_fail (priv->connected, FALSE);
1457 g_return_val_if_fail (priv->n_responses_waiting > 0, FALSE);
1459 priv->n_responses_waiting--;
1460 priv->responses_received = g_list_append (priv->responses_received, g_strdup (response));
1462 if (priv->n_responses_waiting == 0)
1467 g_debug ("Providing response to display manager");
1469 msg_length = int_length ();
1470 for (iter = priv->responses_received; iter; iter = iter->next)
1471 msg_length += string_length ((gchar *)iter->data);
1473 if (!write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, msg_length, &offset, error) ||
1474 !write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset, error))
1476 for (iter = priv->responses_received; iter; iter = iter->next)
1478 if (!write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset, error))
1481 if (!send_message (greeter, message, offset, error))
1484 g_list_free_full (priv->responses_received, g_free);
1485 priv->responses_received = NULL;
1492 * lightdm_greeter_cancel_authentication:
1493 * @greeter: A #LightDMGreeter
1494 * @error: return location for a #GError, or %NULL
1496 * Cancel the current user authentication.
1498 * Return value: #TRUE if cancel request sent.
1501 lightdm_greeter_cancel_authentication (LightDMGreeter *greeter, GError **error)
1503 LightDMGreeterPrivate *priv;
1504 guint8 message[MAX_MESSAGE_LENGTH];
1507 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1509 priv = GET_PRIVATE (greeter);
1511 g_return_val_if_fail (priv->connected, FALSE);
1513 priv->cancelling_authentication = TRUE;
1514 return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset, error) &&
1515 send_message (greeter, message, offset, error);
1519 * lightdm_greeter_get_in_authentication:
1520 * @greeter: A #LightDMGreeter
1522 * Checks if the greeter is in the process of authenticating.
1524 * Return value: #TRUE if the greeter is authenticating a user.
1527 lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
1529 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1530 return GET_PRIVATE (greeter)->in_authentication;
1534 * lightdm_greeter_get_is_authenticated:
1535 * @greeter: A #LightDMGreeter
1537 * Checks if the greeter has successfully authenticated.
1539 * Return value: #TRUE if the greeter is authenticated for login.
1542 lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
1544 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1545 return GET_PRIVATE (greeter)->is_authenticated;
1549 * lightdm_greeter_get_authentication_user:
1550 * @greeter: A #LightDMGreeter
1552 * Get the user that is being authenticated.
1554 * Return value: (nullable): The username of the authentication user being authenticated or #NULL if no authentication in progress.
1557 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
1559 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1560 return GET_PRIVATE (greeter)->authentication_user;
1564 * lightdm_greeter_set_language:
1565 * @greeter: A #LightDMGreeter
1566 * @language: The language to use for this user in the form of a locale specification (e.g. "de_DE.UTF-8").
1567 * @error: return location for a #GError, or %NULL
1569 * Set the language for the currently authenticated user.
1571 * Return value: #TRUE if set language request sent.
1574 lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language, GError **error)
1576 LightDMGreeterPrivate *priv;
1577 guint8 message[MAX_MESSAGE_LENGTH];
1580 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1582 priv = GET_PRIVATE (greeter);
1584 g_return_val_if_fail (priv->connected, FALSE);
1586 return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset, error) &&
1587 write_string (message, MAX_MESSAGE_LENGTH, language, &offset, error) &&
1588 send_message (greeter, message, offset, error);
1592 * lightdm_greeter_start_session:
1593 * @greeter: A #LightDMGreeter
1594 * @session: (allow-none): The session to log into or #NULL to use the default.
1595 * @cancellable: (allow-none): A #GCancellable or %NULL.
1596 * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
1597 * @user_data: (allow-none): data to pass to the @callback or %NULL.
1599 * Asynchronously start a session for the authenticated user.
1601 * When the operation is finished, @callback will be invoked. You can then call lightdm_greeter_start_session_finish() to get the result of the operation.
1603 * See lightdm_greeter_start_session_sync() for the synchronous version.
1606 lightdm_greeter_start_session (LightDMGreeter *greeter, const gchar *session, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
1608 LightDMGreeterPrivate *priv;
1610 GError *error = NULL;
1612 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1614 priv = GET_PRIVATE (greeter);
1616 request = request_new (greeter, cancellable, callback, user_data);
1617 priv->start_session_requests = g_list_append (priv->start_session_requests, request);
1618 if (!send_start_session (greeter, session, &error))
1620 request->error = error;
1621 request_complete (request);
1626 * lightdm_greeter_start_session_finish:
1627 * @greeter: A #LightDMGreeter
1628 * @result: A #GAsyncResult.
1629 * @error: return location for a #GError, or %NULL
1631 * Start a session for the authenticated user.
1633 * Return value: TRUE if the session was started.
1636 lightdm_greeter_start_session_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error)
1638 Request *request = REQUEST (result);
1640 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1643 g_propagate_error (error, request->error);
1644 return request->result;
1648 * lightdm_greeter_start_session_sync:
1649 * @greeter: A #LightDMGreeter
1650 * @session: (allow-none): The session to log into or #NULL to use the default.
1651 * @error: return location for a #GError, or %NULL
1653 * Start a session for the authenticated user.
1655 * Return value: TRUE if the session was started.
1658 lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
1660 LightDMGreeterPrivate *priv;
1663 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1665 priv = GET_PRIVATE (greeter);
1667 g_return_val_if_fail (priv->connected, FALSE);
1668 g_return_val_if_fail (priv->is_authenticated, FALSE);
1670 /* Read until the session is started */
1671 if (!send_start_session (greeter, session, error))
1673 request = request_new (greeter, NULL, NULL, NULL);
1674 priv->start_session_requests = g_list_append (priv->start_session_requests, g_object_ref (request));
1678 gsize message_length;
1680 if (!recv_message (greeter, TRUE, &message, &message_length, error))
1682 handle_message (greeter, message, message_length);
1684 } while (!request->complete);
1686 return lightdm_greeter_start_session_finish (greeter, G_ASYNC_RESULT (request), error);
1690 * lightdm_greeter_ensure_shared_data_dir:
1691 * @greeter: A #LightDMGreeter
1692 * @username: A username
1693 * @cancellable: (allow-none): A #GCancellable or %NULL.
1694 * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
1695 * @user_data: (allow-none): data to pass to the @callback or %NULL.
1697 * Ensure that a shared data dir for the given user is available. Both the
1698 * greeter user and @username will have write access to that folder. The
1699 * intention is that larger pieces of shared data would be stored there (files
1700 * that the greeter creates but wants to give to a user -- like camera
1701 * photos -- or files that the user creates but wants the greeter to
1702 * see -- like contact avatars).
1704 * LightDM will automatically create these if the user actually logs in, so
1705 * greeters only need to call this method if they want to store something in
1706 * the directory themselves.
1709 lightdm_greeter_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
1711 LightDMGreeterPrivate *priv;
1713 GError *error = NULL;
1715 g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1717 priv = GET_PRIVATE (greeter);
1719 request = request_new (greeter, cancellable, callback, user_data);
1720 priv->ensure_shared_data_dir_requests = g_list_append (priv->ensure_shared_data_dir_requests, request);
1721 if (!send_ensure_shared_data_dir (greeter, username, &error))
1723 request->error = error;
1724 request_complete (request);
1729 * lightdm_greeter_ensure_shared_data_dir_finish:
1730 * @result: A #GAsyncResult.
1731 * @greeter: A #LightDMGreeter
1732 * @error: return location for a #GError, or %NULL
1734 * Function to call from lightdm_greeter_ensure_shared_data_dir callback.
1736 * Return value: The path to the shared directory, free with g_free.
1739 lightdm_greeter_ensure_shared_data_dir_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error)
1741 Request *request = REQUEST (result);
1743 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1746 g_propagate_error (error, request->error);
1747 return g_strdup (request->dir);
1751 * lightdm_greeter_ensure_shared_data_dir_sync:
1752 * @greeter: A #LightDMGreeter
1753 * @username: A username
1754 * @error: return location for a #GError, or %NULL
1756 * Ensure that a shared data dir for the given user is available. Both the
1757 * greeter user and @username will have write access to that folder. The
1758 * intention is that larger pieces of shared data would be stored there (files
1759 * that the greeter creates but wants to give to a user -- like camera
1760 * photos -- or files that the user creates but wants the greeter to
1761 * see -- like contact avatars).
1763 * LightDM will automatically create these if the user actually logs in, so
1764 * greeters only need to call this method if they want to store something in
1765 * the directory themselves.
1767 * Return value: The path to the shared directory, free with g_free.
1770 lightdm_greeter_ensure_shared_data_dir_sync (LightDMGreeter *greeter, const gchar *username, GError **error)
1772 LightDMGreeterPrivate *priv;
1775 g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1777 priv = GET_PRIVATE (greeter);
1779 g_return_val_if_fail (priv->connected, NULL);
1781 /* Read until a response */
1782 if (!send_ensure_shared_data_dir (greeter, username, error))
1784 request = request_new (greeter, NULL, NULL, NULL);
1785 priv->ensure_shared_data_dir_requests = g_list_append (priv->ensure_shared_data_dir_requests, g_object_ref (request));
1789 gsize message_length;
1791 if (!recv_message (greeter, TRUE, &message, &message_length, error))
1793 handle_message (greeter, message, message_length);
1795 } while (!request->complete);
1797 return lightdm_greeter_ensure_shared_data_dir_finish (greeter, G_ASYNC_RESULT (request), error);
1801 lightdm_greeter_init (LightDMGreeter *greeter)
1803 LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1805 priv->read_buffer = g_malloc (HEADER_SIZE);
1806 priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1810 lightdm_greeter_set_property (GObject *object,
1812 const GValue *value,
1815 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1819 lightdm_greeter_get_property (GObject *object,
1824 LightDMGreeter *self;
1826 self = LIGHTDM_GREETER (object);
1829 case PROP_DEFAULT_SESSION_HINT:
1830 g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
1832 case PROP_HIDE_USERS_HINT:
1833 g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
1835 case PROP_SHOW_MANUAL_LOGIN_HINT:
1836 g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
1838 case PROP_SHOW_REMOTE_LOGIN_HINT:
1839 g_value_set_boolean (value, lightdm_greeter_get_show_remote_login_hint (self));
1841 case PROP_LOCK_HINT:
1842 g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
1844 case PROP_HAS_GUEST_ACCOUNT_HINT:
1845 g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
1847 case PROP_SELECT_USER_HINT:
1848 g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
1850 case PROP_SELECT_GUEST_HINT:
1851 g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
1853 case PROP_AUTOLOGIN_USER_HINT:
1854 g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
1856 case PROP_AUTOLOGIN_GUEST_HINT:
1857 g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
1859 case PROP_AUTOLOGIN_TIMEOUT_HINT:
1860 g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
1862 case PROP_AUTHENTICATION_USER:
1863 g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
1865 case PROP_IN_AUTHENTICATION:
1866 g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
1868 case PROP_IS_AUTHENTICATED:
1869 g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
1872 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1878 lightdm_greeter_finalize (GObject *object)
1880 LightDMGreeter *self = LIGHTDM_GREETER (object);
1881 LightDMGreeterPrivate *priv = GET_PRIVATE (self);
1883 g_clear_object (&priv->socket);
1884 if (priv->to_server_channel)
1885 g_io_channel_unref (priv->to_server_channel);
1886 if (priv->from_server_channel)
1887 g_io_channel_unref (priv->from_server_channel);
1888 if (priv->from_server_watch)
1889 g_source_remove (priv->from_server_watch);
1890 priv->from_server_watch = 0;
1891 g_clear_pointer (&priv->read_buffer, g_free);
1892 g_list_free_full (priv->responses_received, g_free);
1893 priv->responses_received = NULL;
1894 g_list_free_full (priv->connect_requests, g_object_unref);
1895 priv->connect_requests = NULL;
1896 g_list_free_full (priv->start_session_requests, g_object_unref);
1897 priv->start_session_requests = NULL;
1898 g_list_free_full (priv->ensure_shared_data_dir_requests, g_object_unref);
1899 priv->ensure_shared_data_dir_requests = NULL;
1900 g_clear_pointer (&priv->authentication_user, g_free);
1901 g_hash_table_unref (priv->hints);
1904 G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
1908 lightdm_greeter_class_init (LightDMGreeterClass *klass)
1910 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1912 g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
1914 object_class->set_property = lightdm_greeter_set_property;
1915 object_class->get_property = lightdm_greeter_get_property;
1916 object_class->finalize = lightdm_greeter_finalize;
1918 g_object_class_install_property (object_class,
1919 PROP_DEFAULT_SESSION_HINT,
1920 g_param_spec_string ("default-session-hint",
1921 "default-session-hint",
1922 "Default session hint",
1926 g_object_class_install_property (object_class,
1927 PROP_HIDE_USERS_HINT,
1928 g_param_spec_boolean ("hide-users-hint",
1934 g_object_class_install_property (object_class,
1935 PROP_SHOW_MANUAL_LOGIN_HINT,
1936 g_param_spec_boolean ("show-manual-login-hint",
1937 "show-manual-login-hint",
1938 "Show manual login hint",
1942 g_object_class_install_property (object_class,
1943 PROP_SHOW_REMOTE_LOGIN_HINT,
1944 g_param_spec_boolean ("show-remote-login-hint",
1945 "show-remote-login-hint",
1946 "Show remote login hint",
1950 g_object_class_install_property (object_class,
1952 g_param_spec_boolean ("lock-hint",
1958 g_object_class_install_property (object_class,
1959 PROP_HAS_GUEST_ACCOUNT_HINT,
1960 g_param_spec_boolean ("has-guest-account-hint",
1961 "has-guest-account-hint",
1962 "Has guest account hint",
1966 g_object_class_install_property (object_class,
1967 PROP_SELECT_USER_HINT,
1968 g_param_spec_string ("select-user-hint",
1974 g_object_class_install_property (object_class,
1975 PROP_SELECT_GUEST_HINT,
1976 g_param_spec_boolean ("select-guest-hint",
1977 "select-guest-hint",
1978 "Select guest account hint",
1982 g_object_class_install_property (object_class,
1983 PROP_AUTOLOGIN_USER_HINT,
1984 g_param_spec_string ("autologin-user-hint",
1985 "autologin-user-hint",
1986 "Autologin user hint",
1990 g_object_class_install_property (object_class,
1991 PROP_AUTOLOGIN_GUEST_HINT,
1992 g_param_spec_boolean ("autologin-guest-hint",
1993 "autologin-guest-hint",
1994 "Autologin guest account hint",
1998 g_object_class_install_property (object_class,
1999 PROP_AUTOLOGIN_TIMEOUT_HINT,
2000 g_param_spec_int ("autologin-timeout-hint",
2001 "autologin-timeout-hint",
2002 "Autologin timeout hint",
2006 g_object_class_install_property (object_class,
2007 PROP_AUTHENTICATION_USER,
2008 g_param_spec_string ("authentication-user",
2009 "authentication-user",
2010 "The user being authenticated",
2013 g_object_class_install_property (object_class,
2014 PROP_IN_AUTHENTICATION,
2015 g_param_spec_boolean ("in-authentication",
2016 "in-authentication",
2017 "TRUE if a user is being authenticated",
2020 g_object_class_install_property (object_class,
2021 PROP_IS_AUTHENTICATED,
2022 g_param_spec_boolean ("is-authenticated",
2024 "TRUE if the selected user is authenticated",
2029 * LightDMGreeter::show-prompt:
2030 * @greeter: A #LightDMGreeter
2031 * @text: Prompt text
2032 * @type: Prompt type
2034 * The ::show-prompt signal gets emitted when the greeter should show a
2035 * prompt to the user. The given text should be displayed and an input
2036 * field for the user to provide a response.
2038 * Call lightdm_greeter_respond() with the resultant input or
2039 * lightdm_greeter_cancel_authentication() to abort the authentication.
2041 signals[SHOW_PROMPT] =
2042 g_signal_new (LIGHTDM_GREETER_SIGNAL_SHOW_PROMPT,
2043 G_TYPE_FROM_CLASS (klass),
2045 G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
2048 G_TYPE_NONE, 2, G_TYPE_STRING, lightdm_prompt_type_get_type ());
2051 * LightDMGreeter::show-message:
2052 * @greeter: A #LightDMGreeter
2053 * @text: Message text
2054 * @type: Message type
2056 * The ::show-message signal gets emitted when the greeter
2057 * should show a message to the user.
2059 signals[SHOW_MESSAGE] =
2060 g_signal_new (LIGHTDM_GREETER_SIGNAL_SHOW_MESSAGE,
2061 G_TYPE_FROM_CLASS (klass),
2063 G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
2066 G_TYPE_NONE, 2, G_TYPE_STRING, lightdm_message_type_get_type ());
2069 * LightDMGreeter::authentication-complete:
2070 * @greeter: A #LightDMGreeter
2072 * The ::authentication-complete signal gets emitted when the greeter
2073 * has completed authentication.
2075 * Call lightdm_greeter_get_is_authenticated() to check if the authentication
2078 signals[AUTHENTICATION_COMPLETE] =
2079 g_signal_new (LIGHTDM_GREETER_SIGNAL_AUTHENTICATION_COMPLETE,
2080 G_TYPE_FROM_CLASS (klass),
2082 G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
2088 * LightDMGreeter::autologin-timer-expired:
2089 * @greeter: A #LightDMGreeter
2091 * The ::timed-login signal gets emitted when the automatic login timer has expired.
2092 * The application should then call lightdm_greeter_login().
2094 signals[AUTOLOGIN_TIMER_EXPIRED] =
2095 g_signal_new (LIGHTDM_GREETER_SIGNAL_AUTOLOGIN_TIMER_EXPIRED,
2096 G_TYPE_FROM_CLASS (klass),
2098 G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),
2104 * LightDMGreeter::idle:
2105 * @greeter: A #LightDMGreeter
2107 * The ::idle signal gets emitted when the user has logged in and the
2108 * greeter is no longer needed.
2110 * This signal only matters if the greeter has marked itself as
2111 * resettable using lightdm_greeter_set_resettable().
2114 g_signal_new (LIGHTDM_GREETER_SIGNAL_IDLE,
2115 G_TYPE_FROM_CLASS (klass),
2117 G_STRUCT_OFFSET (LightDMGreeterClass, idle),
2123 * LightDMGreeter::reset:
2124 * @greeter: A #LightDMGreeter
2126 * The ::reset signal gets emitted when the user is returning to a greeter
2127 * that was previously marked idle.
2129 * This signal only matters if the greeter has marked itself as
2130 * resettable using lightdm_greeter_set_resettable().
2133 g_signal_new (LIGHTDM_GREETER_SIGNAL_RESET,
2134 G_TYPE_FROM_CLASS (klass),
2136 G_STRUCT_OFFSET (LightDMGreeterClass, reset),
2143 request_init (Request *request)
2148 request_finalize (GObject *object)
2150 Request *request = REQUEST (object);
2152 g_clear_object (&request->cancellable);
2153 g_free (request->dir);
2155 G_OBJECT_CLASS (request_parent_class)->finalize (object);
2159 request_class_init (RequestClass *klass)
2161 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2162 object_class->finalize = request_finalize;
2166 request_get_user_data (GAsyncResult *result)
2168 return REQUEST (result)->user_data;
2172 request_get_source_object (GAsyncResult *result)
2174 return g_object_ref (REQUEST (result)->greeter);
2178 request_iface_init (GAsyncResultIface *iface)
2180 iface->get_user_data = request_get_user_data;
2181 iface->get_source_object = request_get_source_object;