/* * Copyright (C) 2010 Robert Ancell. * Author: Robert Ancell * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) any * later version. See http://www.gnu.org/copyleft/lgpl.html the full text of the * license. */ #include #include #include #include #include "lightdm/greeter.h" enum { PROP_0, PROP_DEFAULT_SESSION_HINT, PROP_HIDE_USERS_HINT, PROP_HAS_GUEST_ACCOUNT_HINT, PROP_SELECT_USER_HINT, PROP_SELECT_GUEST_HINT, PROP_AUTOLOGIN_USER_HINT, PROP_AUTOLOGIN_GUEST_HINT, PROP_AUTOLOGIN_TIMEOUT_HINT, PROP_AUTHENTICATION_USER, PROP_IN_AUTHENTICATION, PROP_IS_AUTHENTICATED, }; enum { SHOW_PROMPT, SHOW_MESSAGE, AUTHENTICATION_COMPLETE, AUTOLOGIN_TIMER_EXPIRED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { gboolean connected; GIOChannel *to_server_channel, *from_server_channel; guint8 *read_buffer; gsize n_read; GHashTable *hints; guint autologin_timeout; gchar *authentication_user; gboolean in_authentication; gboolean is_authenticated; guint32 authenticate_sequence_number; gboolean cancelling_authentication; } LightDMGreeterPrivate; G_DEFINE_TYPE (LightDMGreeter, lightdm_greeter, G_TYPE_OBJECT); #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_GREETER, LightDMGreeterPrivate) #define HEADER_SIZE 8 #define MAX_MESSAGE_LENGTH 1024 /* Messages from the greeter to the server */ typedef enum { GREETER_MESSAGE_CONNECT = 0, GREETER_MESSAGE_AUTHENTICATE, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, GREETER_MESSAGE_START_SESSION, GREETER_MESSAGE_CANCEL_AUTHENTICATION } GreeterMessage; /* Messages from the server to the greeter */ typedef enum { SERVER_MESSAGE_CONNECTED = 0, SERVER_MESSAGE_PROMPT_AUTHENTICATION, SERVER_MESSAGE_END_AUTHENTICATION, SERVER_MESSAGE_SESSION_RESULT } ServerMessage; /** * lightdm_greeter_new: * * Create a new greeter. * * Return value: the new #LightDMGreeter **/ LightDMGreeter * lightdm_greeter_new () { return g_object_new (LIGHTDM_TYPE_GREETER, NULL); } static gboolean timed_login_cb (gpointer data) { LightDMGreeter *greeter = data; LightDMGreeterPrivate *priv = GET_PRIVATE (greeter); priv->autologin_timeout = 0; g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0); return FALSE; } static guint32 int_length () { return 4; } static void write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length) { LightDMGreeterPrivate *priv = GET_PRIVATE (greeter); GError *error = NULL; if (g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, NULL) != G_IO_STATUS_NORMAL) g_warning ("Error writing to daemon: %s", error->message); else g_debug ("Wrote %zi bytes to daemon", message_length); g_clear_error (&error); g_io_channel_flush (priv->to_server_channel, NULL); } static void write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset) { if (*offset + 4 >= buffer_length) return; buffer[*offset] = value >> 24; buffer[*offset+1] = (value >> 16) & 0xFF; buffer[*offset+2] = (value >> 8) & 0xFF; buffer[*offset+3] = value & 0xFF; *offset += 4; } static void write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset) { gint length = 0; if (value) length = strlen (value); write_int (buffer, buffer_length, length, offset); if (*offset + length >= buffer_length) return; memcpy (buffer + *offset, value, length); *offset += length; } static guint32 read_int (guint8 *message, gsize message_length, gsize *offset) { guint32 value; guint8 *buffer; if (message_length - *offset < int_length ()) { g_warning ("Not enough space for int, need %i, got %zi", int_length (), message_length - *offset); return 0; } buffer = message + *offset; value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; *offset += int_length (); return value; } static gchar * read_string (guint8 *message, gsize message_length, gsize *offset) { guint32 length; gchar *value; length = read_int (message, message_length, offset); if (message_length - *offset < length) { g_warning ("Not enough space for string, need %u, got %zu", length, message_length - *offset); return g_strdup (""); } value = g_malloc (sizeof (gchar) * (length + 1)); memcpy (value, message + *offset, length); value[length] = '\0'; *offset += length; return value; } static guint32 string_length (const gchar *value) { if (value) return int_length () + strlen (value); else return int_length (); } static void write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset) { write_int (buffer, buffer_length, id, offset); write_int (buffer, buffer_length, length, offset); } static guint32 get_message_length (guint8 *message, gsize message_length) { gsize offset = 4; return read_int (message, message_length, &offset); } static void handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset) { LightDMGreeterPrivate *priv = GET_PRIVATE (greeter); gchar *version; GString *hint_string; int timeout; version = read_string (message, message_length, offset); hint_string = g_string_new (""); while (*offset < message_length) { gchar *name, *value; name = read_string (message, message_length, offset); value = read_string (message, message_length, offset); g_hash_table_insert (priv->hints, name, value); g_string_append_printf (hint_string, " %s=%s", name, value); } g_debug ("Connected version=%s%s", version, hint_string->str); g_free (version); g_string_free (hint_string, TRUE); /* Set timeout for default login */ timeout = lightdm_greeter_get_autologin_timeout_hint (greeter); if (timeout) { g_debug ("Setting autologin timer for %d seconds", timeout); priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter); } } static void handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset) { LightDMGreeterPrivate *priv = GET_PRIVATE (greeter); guint32 sequence_number, n_messages, i; gchar *username; sequence_number = read_int (message, message_length, offset); if (sequence_number != priv->authenticate_sequence_number) { g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number); return; } if (priv->cancelling_authentication) { g_debug ("Ignoring prompt authentication as waiting for it to cancel"); return; } /* Update username */ username = read_string (message, message_length, offset); if (strcmp (username, "") == 0) { g_free (username); username = NULL; } g_free (priv->authentication_user); priv->authentication_user = username; n_messages = read_int (message, message_length, offset); g_debug ("Prompt user with %d message(s)", n_messages); for (i = 0; i < n_messages; i++) { int style; gchar *text; style = read_int (message, message_length, offset); text = read_string (message, message_length, offset); // FIXME: Should stop on prompts? switch (style) { case PAM_PROMPT_ECHO_OFF: g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_SECRET); break; case PAM_PROMPT_ECHO_ON: g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_QUESTION); break; case PAM_ERROR_MSG: g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_ERROR); break; case PAM_TEXT_INFO: g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_INFO); break; } g_free (text); } } static void handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset) { LightDMGreeterPrivate *priv = GET_PRIVATE (greeter); guint32 sequence_number, return_code; gchar *username; sequence_number = read_int (message, message_length, offset); if (sequence_number != priv->authenticate_sequence_number) { g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number); return; } username = read_string (message, message_length, offset); return_code = read_int (message, message_length, offset); g_debug ("Authentication complete for user %s with return code %d", username, return_code); /* Update username */ if (strcmp (username, "") == 0) { g_free (username); username = NULL; } g_free (priv->authentication_user); priv->authentication_user = username; priv->cancelling_authentication = FALSE; priv->is_authenticated = (return_code == 0); priv->in_authentication = FALSE; g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0); } static guint8 * read_message (LightDMGreeter *greeter, gsize *length, gboolean block) { LightDMGreeterPrivate *priv = GET_PRIVATE (greeter); gsize n_to_read, n_read; guint8 *buffer; GError *error = NULL; /* Read the header, or the whole message if we already have that */ n_to_read = HEADER_SIZE; if (priv->n_read >= HEADER_SIZE) n_to_read += get_message_length (priv->read_buffer, priv->n_read); do { GIOStatus status; status = g_io_channel_read_chars (priv->from_server_channel, (gchar *) priv->read_buffer + priv->n_read, n_to_read - priv->n_read, &n_read, &error); if (status == G_IO_STATUS_ERROR) g_warning ("Error reading from server: %s", error->message); g_clear_error (&error); if (status != G_IO_STATUS_NORMAL) break; g_debug ("Read %zi bytes from daemon", n_read); priv->n_read += n_read; } while (priv->n_read < n_to_read && block); /* Stop if haven't got all the data we want */ if (priv->n_read != n_to_read) return FALSE; /* If have header, rerun for content */ if (priv->n_read == HEADER_SIZE) { n_to_read = get_message_length (priv->read_buffer, priv->n_read); if (n_to_read > 0) { priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read); return read_message (greeter, length, block); } } buffer = priv->read_buffer; *length = priv->n_read; priv->read_buffer = g_malloc (priv->n_read); priv->n_read = 0; return buffer; } static gboolean from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data) { LightDMGreeter *greeter = data; guint8 *message; gsize message_length, offset; guint32 id; message = read_message (greeter, &message_length, FALSE); if (!message) return TRUE; offset = 0; id = read_int (message, message_length, &offset); read_int (message, message_length, &offset); switch (id) { case SERVER_MESSAGE_PROMPT_AUTHENTICATION: handle_prompt_authentication (greeter, message, message_length, &offset); break; case SERVER_MESSAGE_END_AUTHENTICATION: handle_end_authentication (greeter, message, message_length, &offset); break; default: g_warning ("Unknown message from server: %d", id); break; } g_free (message); return TRUE; } /** * lightdm_greeter_connect_sync: * @greeter: The greeter to connect * @error: return location for a #GError, or %NULL * * Connects the greeter to the display manager. Will block until connected. * * Return value: #TRUE if successfully connected **/ gboolean lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error) { LightDMGreeterPrivate *priv; const gchar *fd; guint8 message[MAX_MESSAGE_LENGTH]; guint8 *response; gsize response_length, offset = 0; guint32 id; g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); priv = GET_PRIVATE (greeter); fd = g_getenv ("LIGHTDM_TO_SERVER_FD"); if (!fd) { g_warning ("No LIGHTDM_TO_SERVER_FD environment variable"); return FALSE; } priv->to_server_channel = g_io_channel_unix_new (atoi (fd)); g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL); fd = g_getenv ("LIGHTDM_FROM_SERVER_FD"); if (!fd) { g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable"); return FALSE; } priv->from_server_channel = g_io_channel_unix_new (atoi (fd)); g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL); g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter); g_debug ("Connecting to display manager..."); write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset); write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset); write_message (greeter, message, offset); response = read_message (greeter, &response_length, TRUE); if (!response) return FALSE; offset = 0; id = read_int (response, response_length, &offset); read_int (response, response_length, &offset); if (id == SERVER_MESSAGE_CONNECTED) handle_connected (greeter, response, response_length, &offset); g_free (response); if (id != SERVER_MESSAGE_CONNECTED) { g_warning ("Expected CONNECTED message, got %d", id); return FALSE; } priv->connected = TRUE; return TRUE; } /** * lightdm_greeter_get_hint: * @greeter: A #LightDMGreeter * @name: The hint name to query. * * Get a hint. * * Return value: The value for this hint or #NULL if not set. **/ const gchar * lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name) { g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL); return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name); } /** * lightdm_greeter_get_default_session_hint: * @greeter: A #LightDMGreeter * * Get the default session to use. * * Return value: The session name **/ const gchar * lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter) { g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL); return lightdm_greeter_get_hint (greeter, "default-session"); } /** * lightdm_greeter_get_hide_users_hint: * @greeter: A #LightDMGreeter * * Check if user accounts should be shown. * * Return value: #TRUE if the available users should not be shown. */ gboolean lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter) { const gchar *value; g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); value = lightdm_greeter_get_hint (greeter, "hide-users"); return g_strcmp0 (value, "true") == 0; } /** * lightdm_greeter_get_has_guest_account_hint: * @greeter: A #LightDMGreeter * * Check if guest sessions are supported. * * Return value: #TRUE if guest sessions are supported. */ gboolean lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter) { const gchar *value; g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); value = lightdm_greeter_get_hint (greeter, "has-guest-account"); return g_strcmp0 (value, "true") == 0; } /** * lightdm_greeter_get_select_user_hint: * @greeter: A #LightDMGreeter * * Get the user to select by default. * * Return value: A username */ const gchar * lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter) { g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL); return lightdm_greeter_get_hint (greeter, "select-user"); } /** * lightdm_greeter_get_select_guest_hint: * @greeter: A #LightDMGreeter * * Check if the guest account should be selected by default. * * Return value: #TRUE if the guest account should be selected by default. */ gboolean lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter) { const gchar *value; g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); value = lightdm_greeter_get_hint (greeter, "select-guest"); return g_strcmp0 (value, "true") == 0; } /** * lightdm_greeter_get_autologin_user_hint: * @greeter: A #LightDMGreeter * * Get the user account to automatically logg into when the timer expires. * * Return value: The user account to automatically log into. */ const gchar * lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter) { g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL); return lightdm_greeter_get_hint (greeter, "autologin-user"); } /** * lightdm_greeter_get_autologin_guest_hint: * @greeter: A #LightDMGreeter * * Check if the guest account should be automatically logged into when the timer expires. * * Return value: #TRUE if the guest account should be automatically logged into. */ gboolean lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter) { const gchar *value; g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); value = lightdm_greeter_get_hint (greeter, "autologin-guest"); return g_strcmp0 (value, "true") == 0; } /** * lightdm_greeter_get_autologin_timeout_hint: * @greeter: A #LightDMGreeter * * Get the number of seconds to wait before automaitcally logging in. * * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout. */ gint lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter) { const gchar *value; gint timeout = 0; g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); value = lightdm_greeter_get_hint (greeter, "autologin-timeout"); if (value) timeout = atoi (value); if (timeout < 0) timeout = 0; return timeout; } /** * lightdm_greeter_cancel_autologin: * @greeter: A #LightDMGreeter * * Cancel the automatic login. */ void lightdm_greeter_cancel_autologin (LightDMGreeter *greeter) { LightDMGreeterPrivate *priv; g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); priv = GET_PRIVATE (greeter); if (priv->autologin_timeout) g_source_remove (priv->autologin_timeout); priv->autologin_timeout = 0; } /** * lightdm_greeter_authenticate: * @greeter: A #LightDMGreeter * @username: (allow-none): A username or #NULL to prompt for a username. * * Starts the authentication procedure for a user. **/ void lightdm_greeter_authenticate (LightDMGreeter *greeter, const char *username) { LightDMGreeterPrivate *priv; guint8 message[MAX_MESSAGE_LENGTH]; gsize offset = 0; g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); priv = GET_PRIVATE (greeter); g_return_if_fail (priv->connected); priv->cancelling_authentication = FALSE; priv->authenticate_sequence_number++; priv->in_authentication = TRUE; priv->is_authenticated = FALSE; if (username != priv->authentication_user) { g_free (priv->authentication_user); priv->authentication_user = g_strdup (username); } g_debug ("Starting authentication for user %s...", username); write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset); write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset); write_string (message, MAX_MESSAGE_LENGTH, username, &offset); write_message (greeter, message, offset); } /** * lightdm_greeter_authenticate_as_guest: * @greeter: A #LightDMGreeter * * Starts the authentication procedure for the guest user. **/ void lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter) { LightDMGreeterPrivate *priv; guint8 message[MAX_MESSAGE_LENGTH]; gsize offset = 0; g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); priv = GET_PRIVATE (greeter); g_return_if_fail (priv->connected); priv->cancelling_authentication = FALSE; priv->authenticate_sequence_number++; priv->in_authentication = TRUE; priv->is_authenticated = FALSE; g_free (priv->authentication_user); priv->authentication_user = NULL; g_debug ("Starting authentication for guest account..."); write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset); write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset); write_message (greeter, message, offset); } /** * lightdm_greeter_respond: * @greeter: A #LightDMGreeter * @response: Response to a prompt * * Provide response to a prompt. **/ void lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response) { LightDMGreeterPrivate *priv; guint8 message[MAX_MESSAGE_LENGTH]; gsize offset = 0; g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); g_return_if_fail (response != NULL); priv = GET_PRIVATE (greeter); g_return_if_fail (priv->connected); g_debug ("Providing response to display manager"); write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, int_length () + string_length (response), &offset); // FIXME: Could be multiple responses required write_int (message, MAX_MESSAGE_LENGTH, 1, &offset); write_string (message, MAX_MESSAGE_LENGTH, response, &offset); write_message (greeter, message, offset); } /** * lightdm_greeter_cancel_authentication: * @greeter: A #LightDMGreeter * * Cancel the current user authentication. **/ void lightdm_greeter_cancel_authentication (LightDMGreeter *greeter) { LightDMGreeterPrivate *priv; guint8 message[MAX_MESSAGE_LENGTH]; gsize offset = 0; g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); priv = GET_PRIVATE (greeter); g_return_if_fail (priv->connected); priv->cancelling_authentication = TRUE; write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset); write_message (greeter, message, offset); } /** * lightdm_greeter_get_in_authentication: * @greeter: A #LightDMGreeter * * Checks if the greeter is in the process of authenticating. * * Return value: #TRUE if the greeter is authenticating a user. **/ gboolean lightdm_greeter_get_in_authentication (LightDMGreeter *greeter) { g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); return GET_PRIVATE (greeter)->in_authentication; } /** * lightdm_greeter_get_is_authenticated: * @greeter: A #LightDMGreeter * * Checks if the greeter has successfully authenticated. * * Return value: #TRUE if the greeter is authenticated for login. **/ gboolean lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter) { g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); return GET_PRIVATE (greeter)->is_authenticated; } /** * lightdm_greeter_get_authentication_user: * @greeter: A #LightDMGreeter * * Get the user that is being authenticated. * * Return value: The username of the authentication user being authenticated or #NULL if no authentication in progress. */ const gchar * lightdm_greeter_get_authentication_user (LightDMGreeter *greeter) { g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL); return GET_PRIVATE (greeter)->authentication_user; } /** * lightdm_greeter_start_session_sync: * @greeter: A #LightDMGreeter * @session: (allow-none): The session to log into or #NULL to use the default. * @error: return location for a #GError, or %NULL * * Start a session for the authenticated user. * * Return value: TRUE if the session was started. **/ gboolean lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error) { LightDMGreeterPrivate *priv; guint8 message[MAX_MESSAGE_LENGTH]; guint8 *response; gsize response_length, offset = 0; guint32 id, return_code = 1; g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE); priv = GET_PRIVATE (greeter); g_return_val_if_fail (priv->connected, FALSE); g_return_val_if_fail (priv->is_authenticated, FALSE); if (session) g_debug ("Starting session %s", session); else g_debug ("Starting default session"); write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset); write_string (message, MAX_MESSAGE_LENGTH, session, &offset); write_message (greeter, message, offset); response = read_message (greeter, &response_length, TRUE); if (!response) return FALSE; offset = 0; id = read_int (response, response_length, &offset); read_int (response, response_length, &offset); if (id == SERVER_MESSAGE_SESSION_RESULT) return_code = read_int (response, response_length, &offset); else g_warning ("Expected SESSION_RESULT message, got %d", id); g_free (response); return return_code == 0; } static void lightdm_greeter_init (LightDMGreeter *greeter) { LightDMGreeterPrivate *priv = GET_PRIVATE (greeter); priv->read_buffer = g_malloc (HEADER_SIZE); priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); } static void lightdm_greeter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } static void lightdm_greeter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { LightDMGreeter *self; self = LIGHTDM_GREETER (object); switch (prop_id) { case PROP_DEFAULT_SESSION_HINT: g_value_set_string (value, lightdm_greeter_get_default_session_hint (self)); break; case PROP_HIDE_USERS_HINT: g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self)); break; case PROP_HAS_GUEST_ACCOUNT_HINT: g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self)); break; case PROP_SELECT_USER_HINT: g_value_set_string (value, lightdm_greeter_get_select_user_hint (self)); break; case PROP_SELECT_GUEST_HINT: g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self)); break; case PROP_AUTOLOGIN_USER_HINT: g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self)); break; case PROP_AUTOLOGIN_GUEST_HINT: g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self)); break; case PROP_AUTOLOGIN_TIMEOUT_HINT: g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self)); break; case PROP_AUTHENTICATION_USER: g_value_set_string (value, lightdm_greeter_get_authentication_user (self)); break; case PROP_IN_AUTHENTICATION: g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self)); break; case PROP_IS_AUTHENTICATED: g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void marshal_VOID__STRING_INT (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef void (*GMarshalFunc_VOID__STRING_INT) (gpointer data1, gpointer arg_1, gint arg_2, gpointer data2); register GMarshalFunc_VOID__STRING_INT callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; g_return_if_fail (n_param_values == 3); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__STRING_INT) (marshal_data ? marshal_data : cc->callback); callback (data1, (param_values + 1)->data[0].v_pointer, (param_values + 2)->data[0].v_int, data2); } static void lightdm_greeter_finalize (GObject *object) { LightDMGreeter *self = LIGHTDM_GREETER (object); LightDMGreeterPrivate *priv = GET_PRIVATE (self); if (priv->to_server_channel) g_io_channel_unref (priv->to_server_channel); if (priv->from_server_channel) g_io_channel_unref (priv->from_server_channel); g_free (priv->authentication_user); g_hash_table_unref (priv->hints); G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object); } static void lightdm_greeter_class_init (LightDMGreeterClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate)); object_class->set_property = lightdm_greeter_set_property; object_class->get_property = lightdm_greeter_get_property; object_class->finalize = lightdm_greeter_finalize; g_object_class_install_property (object_class, PROP_DEFAULT_SESSION_HINT, g_param_spec_string ("default-session-hint", "default-session-hint", "Default session hint", NULL, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_HIDE_USERS_HINT, g_param_spec_boolean ("hide-users-hint", "hide-users-hint", "hide users hint", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_HAS_GUEST_ACCOUNT_HINT, g_param_spec_boolean ("has-guest-account-hint", "has-guest-account-hint", "Has guest account hint", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_SELECT_USER_HINT, g_param_spec_string ("select-user-hint", "select-user-hint", "Select user hint", NULL, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_SELECT_GUEST_HINT, g_param_spec_boolean ("select-guest-hint", "select-guest-hint", "Select guest account hint", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_AUTOLOGIN_USER_HINT, g_param_spec_string ("autologin-user-hint", "autologin-user-hint", "Autologin user hint", NULL, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_AUTOLOGIN_GUEST_HINT, g_param_spec_boolean ("autologin-guest-hint", "autologin-guest-hint", "Autologin guest account hint", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_AUTOLOGIN_TIMEOUT_HINT, g_param_spec_int ("autologin-timeout-hint", "autologin-timeout-hint", "Autologin timeout hint", 0, G_MAXINT, 0, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_AUTHENTICATION_USER, g_param_spec_string ("authentication-user", "authentication-user", "The user being authenticated", NULL, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_IN_AUTHENTICATION, g_param_spec_boolean ("in-authentication", "in-authentication", "TRUE if a user is being authenticated", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_IS_AUTHENTICATED, g_param_spec_boolean ("is-authenticated", "is-authenticated", "TRUE if the selected user is authenticated", FALSE, G_PARAM_READABLE)); /** * LightDMGreeter::show-prompt: * @greeter: A #LightDMGreeter * @text: Prompt text * @type: Prompt type * * The ::show-prompt signal gets emitted when the greeter should show a * prompt to the user. The given text should be displayed and an input * field for the user to provide a response. * * Call lightdm_greeter_respond() with the resultant input or * lightdm_greeter_cancel_authentication() to abort the authentication. **/ signals[SHOW_PROMPT] = g_signal_new ("show-prompt", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt), NULL, NULL, marshal_VOID__STRING_INT, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT); /** * LightDMGreeter::show-message: * @greeter: A #LightDMGreeter * @text: Message text * @type: Message type * * The ::show-message signal gets emitted when the greeter * should show a message to the user. **/ signals[SHOW_MESSAGE] = g_signal_new ("show-message", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (LightDMGreeterClass, show_message), NULL, NULL, marshal_VOID__STRING_INT, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT); /** * LightDMGreeter::authentication-complete: * @greeter: A #LightDMGreeter * * The ::authentication-complete signal gets emitted when the greeter * has completed authentication. * * Call lightdm_greeter_get_is_authenticated() to check if the authentication * was successful. **/ signals[AUTHENTICATION_COMPLETE] = g_signal_new ("authentication-complete", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * LightDMGreeter::autologin-timer-expired: * @greeter: A #LightDMGreeter * * The ::timed-login signal gets emitted when the automatic login timer has expired. * The application should then call lightdm_greeter_login(). **/ signals[AUTOLOGIN_TIMER_EXPIRED] = g_signal_new ("autologin-timer-expired", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); }