/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2006 Ray Strode * Copyright (C) 2007 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBXKLAVIER #include #include /* for Display */ #endif #include #include #include "gdm-session-direct.h" #include "gdm-session.h" #include "gdm-session-private.h" #include "gdm-session-direct-glue.h" #include "gdm-session-record.h" #include "gdm-session-worker-job.h" #include "gdm-common.h" #define GDM_SESSION_DBUS_PATH "/org/gnome/DisplayManager/Session" #define GDM_SESSION_DBUS_INTERFACE "org.gnome.DisplayManager.Session" #define GDM_SESSION_DBUS_ERROR_CANCEL "org.gnome.DisplayManager.Session.Error.Cancel" #ifndef GDM_SESSION_DEFAULT_PATH #define GDM_SESSION_DEFAULT_PATH "/usr/local/bin:/usr/bin:/bin" #endif typedef struct { GdmSessionDirect *session; GdmSessionWorkerJob *job; GPid worker_pid; char *service_name; DBusConnection *worker_connection; DBusMessage *message_pending_reply; guint32 is_stopping : 1; } GdmSessionConversation; struct _GdmSessionDirectPrivate { /* per open scope */ char *selected_program; char *selected_session; char *saved_session; char *selected_language; char *saved_language; char *selected_user; char *user_x11_authority_file; GHashTable *conversations; GList *pending_connections; GPid session_pid; guint32 is_running : 1; /* object lifetime scope */ char *id; char *display_id; char *display_name; char *display_hostname; char *display_device; char *display_x11_authority_file; gboolean display_is_local; char *fallback_session_name; DBusServer *server; char *server_address; GHashTable *environment; DBusGConnection *connection; }; enum { PROP_0, PROP_DISPLAY_ID, PROP_DISPLAY_NAME, PROP_DISPLAY_HOSTNAME, PROP_DISPLAY_IS_LOCAL, PROP_DISPLAY_DEVICE, PROP_DISPLAY_X11_AUTHORITY_FILE, PROP_USER_X11_AUTHORITY_FILE, }; static void gdm_session_iface_init (GdmSessionIface *iface); G_DEFINE_TYPE_WITH_CODE (GdmSessionDirect, gdm_session_direct, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GDM_TYPE_SESSION, gdm_session_iface_init)) static gboolean send_dbus_message (GdmSessionConversation *conversation, DBusMessage *message) { gboolean is_connected; gboolean sent; g_return_val_if_fail (message != NULL, FALSE); if (conversation->worker_connection == NULL) { g_warning ("There is no valid connection"); return FALSE; } is_connected = dbus_connection_get_is_connected (conversation->worker_connection); if (! is_connected) { g_warning ("Not connected!"); return FALSE; } sent = dbus_connection_send (conversation->worker_connection, message, NULL); return sent; } static void send_dbus_string_signal (GdmSessionConversation *conversation, const char *name, const char *text) { DBusMessage *message; DBusMessageIter iter; g_return_if_fail (conversation != NULL); message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH, GDM_SESSION_DBUS_INTERFACE, name); dbus_message_iter_init_append (message, &iter); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &text); if (! send_dbus_message (conversation, message)) { g_debug ("GdmSessionDirect: Could not send %s signal", name ? name : "(null)"); } dbus_message_unref (message); } static void send_dbus_void_signal (GdmSessionConversation *conversation, const char *name) { DBusMessage *message; g_return_if_fail (conversation != NULL); message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH, GDM_SESSION_DBUS_INTERFACE, name); if (! send_dbus_message (conversation, message)) { g_debug ("GdmSessionDirect: Could not send %s signal", name); } dbus_message_unref (message); } static GdmSessionConversation * find_conversation_by_name (GdmSessionDirect *session, const char *service_name) { GdmSessionConversation *conversation; conversation = g_hash_table_lookup (session->priv->conversations, service_name); if (conversation == NULL) { g_warning ("Tried to look up non-existent conversation %s", service_name); } return conversation; } static void on_authentication_failed (GdmSession *session, const char *service_name, const char *message) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); GdmSessionConversation *conversation; conversation = find_conversation_by_name (impl, service_name); if (conversation != NULL) { gdm_session_record_failed (conversation->worker_pid, impl->priv->selected_user, impl->priv->display_hostname, impl->priv->display_name, impl->priv->display_device); } } static void on_session_started (GdmSession *session, const char *service_name) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); GdmSessionConversation *conversation; conversation = find_conversation_by_name (impl, service_name); if (conversation != NULL) { gdm_session_record_login (conversation->worker_pid, impl->priv->selected_user, impl->priv->display_hostname, impl->priv->display_name, impl->priv->display_device); } } static void on_session_start_failed (GdmSession *session, const char *service_name, const char *message) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); GdmSessionConversation *conversation; conversation = find_conversation_by_name (impl, service_name); if (conversation != NULL) { gdm_session_record_login (conversation->worker_pid, impl->priv->selected_user, impl->priv->display_hostname, impl->priv->display_name, impl->priv->display_device); } } static void on_session_exited (GdmSession *session, int exit_code) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); gdm_session_record_logout (impl->priv->session_pid, impl->priv->selected_user, impl->priv->display_hostname, impl->priv->display_name, impl->priv->display_device); } static DBusHandlerResult gdm_session_direct_handle_service_unavailable (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; g_debug ("GdmSessionDirect: Emitting 'service-unavailable' signal"); reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); _gdm_session_service_unavailable (GDM_SESSION (session), conversation->service_name); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_setup_complete (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; g_debug ("GdmSessionDirect: Emitting 'setup-complete' signal"); reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); _gdm_session_setup_complete (GDM_SESSION (session), conversation->service_name); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_setup_failed (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; const char *text; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); g_debug ("GdmSessionDirect: Emitting 'setup-failed' signal"); _gdm_session_setup_failed (GDM_SESSION (session), conversation->service_name, text); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_reset_complete (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; g_debug ("GdmSessionDirect: Emitting 'reset-complete' signal"); reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); _gdm_session_reset_complete (GDM_SESSION (session)); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_reset_failed (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; const char *text; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); g_debug ("GdmSessionDirect: Emitting 'reset-failed' signal"); _gdm_session_reset_failed (GDM_SESSION (session), text); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_authenticated (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; g_debug ("GdmSessionDirect: Emitting 'authenticated' signal"); reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); _gdm_session_authenticated (GDM_SESSION (session), conversation->service_name); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_authentication_failed (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; const char *text; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); g_debug ("GdmSessionDirect: Emitting 'authentication-failed' signal"); _gdm_session_authentication_failed (GDM_SESSION (session), conversation->service_name, text); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_authorized (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; g_debug ("GdmSessionDirect: Emitting 'authorized' signal"); reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); _gdm_session_authorized (GDM_SESSION (session), conversation->service_name); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_authorization_failed (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; const char *text; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); g_debug ("GdmSessionDirect: Emitting 'authorization-failed' signal"); _gdm_session_authorization_failed (GDM_SESSION (session), conversation->service_name, text); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_accredited (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; g_debug ("GdmSessionDirect: Emitting 'accredited' signal"); reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); _gdm_session_accredited (GDM_SESSION (session), conversation->service_name); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_accreditation_failed (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; const char *text; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); g_debug ("GdmSessionDirect: Emitting 'accreditation-failed' signal"); _gdm_session_accreditation_failed (GDM_SESSION (session), conversation->service_name, text); return DBUS_HANDLER_RESULT_HANDLED; } static const char ** get_system_session_dirs (void) { static const char *search_dirs[] = { "/etc/X11/sessions/", DMCONFDIR "/Sessions/", DATADIR "/xsessions/", DATADIR "/gdm/BuiltInSessions/", NULL }; return search_dirs; } static gboolean is_prog_in_path (const char *prog) { char *f; gboolean ret; f = g_find_program_in_path (prog); ret = (f != NULL); g_free (f); return ret; } static gboolean get_session_command_for_file (const char *file, char **command) { GKeyFile *key_file; GError *error; char *exec; gboolean ret; gboolean res; exec = NULL; ret = FALSE; if (command != NULL) { *command = NULL; } key_file = g_key_file_new (); g_debug ("GdmSessionDirect: looking for session file '%s'", file); error = NULL; res = g_key_file_load_from_dirs (key_file, file, get_system_session_dirs (), NULL, G_KEY_FILE_NONE, &error); if (! res) { g_debug ("GdmSessionDirect: File '%s' not found: %s", file, error->message); g_error_free (error); if (command != NULL) { *command = NULL; } goto out; } error = NULL; res = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, &error); if (error == NULL && res) { g_debug ("GdmSessionDirect: Session %s is marked as hidden", file); goto out; } exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TRY_EXEC, NULL); if (exec != NULL) { res = is_prog_in_path (exec); g_free (exec); exec = NULL; if (! res) { g_debug ("GdmSessionDirect: Command not found: %s", G_KEY_FILE_DESKTOP_KEY_TRY_EXEC); goto out; } } error = NULL; exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, &error); if (error != NULL) { g_debug ("GdmSessionDirect: %s key not found: %s", G_KEY_FILE_DESKTOP_KEY_EXEC, error->message); g_error_free (error); goto out; } if (command != NULL) { *command = g_strdup (exec); } ret = TRUE; out: g_free (exec); return ret; } static gboolean get_session_command_for_name (const char *name, char **command) { gboolean res; char *filename; filename = g_strdup_printf ("%s.desktop", name); res = get_session_command_for_file (filename, command); g_free (filename); /* * The GDM Xsession script honors "custom" as a valid session. If the * session is one of these, no file is needed, then just run the * command as "custom". */ if (!res && strcmp (name, GDM_CUSTOM_SESSION) == 0) { g_debug ("No custom desktop file, but accepting it anyway."); if (command != NULL) { *command = g_strdup (GDM_CUSTOM_SESSION); } res = TRUE; } return res; } static const char * get_default_language_name (GdmSessionDirect *session) { if (session->priv->saved_language != NULL) { return session->priv->saved_language; } return setlocale (LC_MESSAGES, NULL); } static const char * get_fallback_session_name (GdmSessionDirect *session_direct) { const char **search_dirs; int i; char *name; GSequence *sessions; GSequenceIter *session; if (session_direct->priv->fallback_session_name != NULL) { /* verify that the cached version still exists */ if (get_session_command_for_name (session_direct->priv->fallback_session_name, NULL)) { goto out; } } name = g_strdup ("gnome"); if (get_session_command_for_name (name, NULL)) { g_free (session_direct->priv->fallback_session_name); session_direct->priv->fallback_session_name = name; goto out; } g_free (name); sessions = g_sequence_new (g_free); search_dirs = get_system_session_dirs (); for (i = 0; search_dirs[i] != NULL; i++) { GDir *dir; const char *base_name; dir = g_dir_open (search_dirs[i], 0, NULL); if (dir == NULL) { continue; } do { base_name = g_dir_read_name (dir); if (base_name == NULL) { break; } if (!g_str_has_suffix (base_name, ".desktop")) { continue; } if (get_session_command_for_file (base_name, NULL)) { g_sequence_insert_sorted (sessions, g_strdup (base_name), (GCompareDataFunc) g_strcmp0, NULL); } } while (base_name != NULL); g_dir_close (dir); } name = NULL; session = g_sequence_get_begin_iter (sessions); do { if (g_sequence_get (session)) { char *base_name; g_free (name); base_name = g_sequence_get (session); name = g_strndup (base_name, strlen (base_name) - strlen (".desktop")); break; } session = g_sequence_iter_next (session); } while (!g_sequence_iter_is_end (session)); g_free (session_direct->priv->fallback_session_name); session_direct->priv->fallback_session_name = name; g_sequence_free (sessions); out: return session_direct->priv->fallback_session_name; } static const char * get_default_session_name (GdmSessionDirect *session) { if (session->priv->saved_session != NULL) { return session->priv->saved_session; } return get_fallback_session_name (session); } static void gdm_session_direct_defaults_changed (GdmSessionDirect *session) { _gdm_session_default_language_name_changed (GDM_SESSION (session), get_default_language_name (session)); _gdm_session_default_session_name_changed (GDM_SESSION (session), get_default_session_name (session)); } static void gdm_session_direct_select_user (GdmSession *session, const char *text) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); g_debug ("GdmSessionDirect: Setting user: '%s'", text); g_free (impl->priv->selected_user); impl->priv->selected_user = g_strdup (text); g_free (impl->priv->saved_session); impl->priv->saved_session = NULL; g_free (impl->priv->saved_language); impl->priv->saved_language = NULL; } static DBusHandlerResult gdm_session_direct_handle_username_changed (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; const char *text; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); g_debug ("GdmSessionDirect: changing username from '%s' to '%s'", session->priv->selected_user != NULL ? session->priv->selected_user : "", (strlen (text)) ? text : ""); gdm_session_direct_select_user (GDM_SESSION (session), (strlen (text) > 0) ? g_strdup (text) : NULL); _gdm_session_selected_user_changed (GDM_SESSION (session), session->priv->selected_user); gdm_session_direct_defaults_changed (session); return DBUS_HANDLER_RESULT_HANDLED; } static void cancel_pending_query (GdmSessionConversation *conversation) { DBusMessage *reply; if (conversation->message_pending_reply == NULL) { return; } g_debug ("GdmSessionDirect: Cancelling pending query"); reply = dbus_message_new_error (conversation->message_pending_reply, GDM_SESSION_DBUS_ERROR_CANCEL, "Operation cancelled"); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_connection_flush (conversation->worker_connection); dbus_message_unref (reply); dbus_message_unref (conversation->message_pending_reply); conversation->message_pending_reply = NULL; } static void answer_pending_query (GdmSessionConversation *conversation, const char *answer) { DBusMessage *reply; DBusMessageIter iter; reply = dbus_message_new_method_return (conversation->message_pending_reply); dbus_message_iter_init_append (reply, &iter); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &answer); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); dbus_message_unref (conversation->message_pending_reply); conversation->message_pending_reply = NULL; } static void set_pending_query (GdmSessionConversation *conversation, DBusMessage *message) { g_assert (conversation->message_pending_reply == NULL); conversation->message_pending_reply = dbus_message_ref (message); } static DBusHandlerResult gdm_session_direct_handle_info_query (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusError error; const char *text; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } set_pending_query (conversation, message); g_debug ("GdmSessionDirect: Emitting 'info-query' signal"); _gdm_session_info_query (GDM_SESSION (session), conversation->service_name, text); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusError error; const char *text; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } set_pending_query (conversation, message); g_debug ("GdmSessionDirect: Emitting 'secret-info-query' signal"); _gdm_session_secret_info_query (GDM_SESSION (session), conversation->service_name, text); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_info (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; const char *text; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); g_debug ("GdmSessionDirect: Emitting 'info' signal"); _gdm_session_info (GDM_SESSION (session), conversation->service_name, text); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_cancel_pending_query (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; g_debug ("GdmSessionDirect: worker cancelling pending query"); cancel_pending_query (conversation); reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_problem (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; const char *text; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); g_debug ("GdmSessionDirect: Emitting 'problem' signal"); _gdm_session_problem (GDM_SESSION (session), conversation->service_name, text); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_session_opened (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; g_debug ("GdmSessionDirect: Handling SessionOpened"); dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } g_debug ("GdmSessionDirect: Emitting 'session-opened' signal"); _gdm_session_session_opened (GDM_SESSION (session), conversation->service_name); reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_open_failed (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; const char *text; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); g_debug ("GdmSessionDirect: Emitting 'session-open-failed' signal"); _gdm_session_session_open_failed (GDM_SESSION (session), conversation->service_name, text); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_session_started (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; int pid; pid = 0; g_debug ("GdmSessionDirect: Handling SessionStarted"); dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); g_debug ("GdmSessionDirect: Emitting 'session-started' signal with pid '%d'", pid); session->priv->session_pid = pid; session->priv->is_running = TRUE; _gdm_session_session_started (GDM_SESSION (session), conversation->service_name, pid); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_start_failed (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; const char *text; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); g_debug ("GdmSessionDirect: Emitting 'session-start-failed' signal"); _gdm_session_session_start_failed (GDM_SESSION (session), conversation->service_name, text); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_session_exited (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; int code; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_INT32, &code, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); g_debug ("GdmSessionDirect: Emitting 'session-exited' signal with exit code '%d'", code); session->priv->is_running = FALSE; _gdm_session_session_exited (GDM_SESSION (session), code); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_session_died (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; int code; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_INT32, &code, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); g_debug ("GdmSessionDirect: Emitting 'session-died' signal with signal number '%d'", code); session->priv->is_running = FALSE; _gdm_session_session_died (GDM_SESSION (session), code); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_saved_language_name_read (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; const char *language_name; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &language_name, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); if (strcmp (language_name, get_default_language_name (session)) != 0) { g_free (session->priv->saved_language); session->priv->saved_language = g_strdup (language_name); _gdm_session_default_language_name_changed (GDM_SESSION (session), language_name); } return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult gdm_session_direct_handle_saved_session_name_read (GdmSessionDirect *session, GdmSessionConversation *conversation, DBusMessage *message) { DBusMessage *reply; DBusError error; const char *session_name; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &session_name, DBUS_TYPE_INVALID)) { g_warning ("ERROR: %s", error.message); } reply = dbus_message_new_method_return (message); dbus_connection_send (conversation->worker_connection, reply, NULL); dbus_message_unref (reply); if (! get_session_command_for_name (session_name, NULL)) { /* ignore sessions that don't exist */ g_debug ("GdmSessionDirect: not using invalid .dmrc session: %s", session_name); g_free (session->priv->saved_session); session->priv->saved_session = NULL; goto out; } if (strcmp (session_name, get_default_session_name (session)) != 0) { g_free (session->priv->saved_session); session->priv->saved_session = g_strdup (session_name); _gdm_session_default_session_name_changed (GDM_SESSION (session), session_name); } out: return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult session_worker_message (DBusConnection *connection, DBusMessage *message, void *user_data) { GdmSessionConversation *conversation = user_data; GdmSessionDirect *session; session = conversation->session; if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "InfoQuery")) { return gdm_session_direct_handle_info_query (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SecretInfoQuery")) { return gdm_session_direct_handle_secret_info_query (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Info")) { return gdm_session_direct_handle_info (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Problem")) { return gdm_session_direct_handle_problem (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "CancelPendingQuery")) { return gdm_session_direct_handle_cancel_pending_query (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "ServiceUnavailable")) { return gdm_session_direct_handle_service_unavailable (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SetupComplete")) { return gdm_session_direct_handle_setup_complete (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SetupFailed")) { return gdm_session_direct_handle_setup_failed (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "ResetComplete")) { return gdm_session_direct_handle_reset_complete (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "ResetFailed")) { return gdm_session_direct_handle_reset_failed (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Authenticated")) { return gdm_session_direct_handle_authenticated (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "AuthenticationFailed")) { return gdm_session_direct_handle_authentication_failed (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Authorized")) { return gdm_session_direct_handle_authorized (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "AuthorizationFailed")) { return gdm_session_direct_handle_authorization_failed (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Accredited")) { return gdm_session_direct_handle_accredited (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "AccreditationFailed")) { return gdm_session_direct_handle_accreditation_failed (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "UsernameChanged")) { return gdm_session_direct_handle_username_changed (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SessionOpened")) { return gdm_session_direct_handle_session_opened (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "OpenFailed")) { return gdm_session_direct_handle_open_failed (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SessionStarted")) { return gdm_session_direct_handle_session_started (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "StartFailed")) { return gdm_session_direct_handle_start_failed (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SessionExited")) { return gdm_session_direct_handle_session_exited (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SessionDied")) { return gdm_session_direct_handle_session_died (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SavedLanguageNameRead")) { return gdm_session_direct_handle_saved_language_name_read (session, conversation, message); } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SavedSessionNameRead")) { return gdm_session_direct_handle_saved_session_name_read (session, conversation, message); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult do_introspect (DBusConnection *connection, DBusMessage *message) { DBusMessage *reply; GString *xml; char *xml_string; g_debug ("GdmSessionDirect: Do introspect"); /* standard header */ xml = g_string_new ("\n" "\n" " \n" " \n" " \n" " \n" " \n"); /* interface */ xml = g_string_append (xml, " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n"); reply = dbus_message_new_method_return (message); xml = g_string_append (xml, "\n"); xml_string = g_string_free (xml, FALSE); dbus_message_append_args (reply, DBUS_TYPE_STRING, &xml_string, DBUS_TYPE_INVALID); g_free (xml_string); if (reply == NULL) { g_error ("No memory"); } if (! dbus_connection_send (connection, reply, NULL)) { g_error ("No memory"); } dbus_message_unref (reply); return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult session_message_handler (DBusConnection *connection, DBusMessage *message, void *user_data) { const char *dbus_destination = dbus_message_get_destination (message); const char *dbus_path = dbus_message_get_path (message); const char *dbus_interface = dbus_message_get_interface (message); const char *dbus_member = dbus_message_get_member (message); g_debug ("session_message_handler: destination=%s obj_path=%s interface=%s method=%s", dbus_destination ? dbus_destination : "(null)", dbus_path ? dbus_path : "(null)", dbus_interface ? dbus_interface : "(null)", dbus_member ? dbus_member : "(null)"); if (dbus_message_is_method_call (message, "org.freedesktop.DBus", "AddMatch")) { DBusMessage *reply; reply = dbus_message_new_method_return (message); if (reply == NULL) { g_error ("No memory"); } if (! dbus_connection_send (connection, reply, NULL)) { g_error ("No memory"); } dbus_message_unref (reply); return DBUS_HANDLER_RESULT_HANDLED; } else if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") && strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) { g_debug ("GdmSessionDirect: Disconnected"); /*dbus_connection_unref (connection);*/ return DBUS_HANDLER_RESULT_HANDLED; } else if (dbus_message_is_method_call (message, "org.freedesktop.DBus.Introspectable", "Introspect")) { return do_introspect (connection, message); } else { return session_worker_message (connection, message, user_data); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } /* Note: Use abstract sockets like dbus does by default on Linux. Abstract * sockets are only available on Linux. */ static char * generate_address (void) { char *path; #if defined (__linux__) int i; char tmp[9]; for (i = 0; i < 8; i++) { if (g_random_int_range (0, 2) == 0) { tmp[i] = g_random_int_range ('a', 'z' + 1); } else { tmp[i] = g_random_int_range ('A', 'Z' + 1); } } tmp[8] = '\0'; path = g_strdup_printf ("unix:abstract=/tmp/gdm-session-%s", tmp); #else path = g_strdup ("unix:tmpdir=/tmp"); #endif return path; } static void session_unregister_handler (DBusConnection *connection, void *user_data) { g_debug ("session_unregister_handler"); } static GdmSessionConversation * find_conversation_by_pid (GdmSessionDirect *session, GPid pid) { GHashTableIter iter; gpointer key, value; g_hash_table_iter_init (&iter, session->priv->conversations); while (g_hash_table_iter_next (&iter, &key, &value)) { GdmSessionConversation *conversation; conversation = (GdmSessionConversation *) value; if (conversation->worker_pid == pid) { return conversation; } } return NULL; } static dbus_bool_t allow_user_function (DBusConnection *connection, unsigned long uid, void *data) { if (0 == uid) { return TRUE; } g_debug ("GdmSessionDirect: User not allowed"); return FALSE; } static gboolean register_worker (GdmSessionDirect *session, DBusConnection *connection) { GdmSessionConversation *conversation; DBusObjectPathVTable vtable = { &session_unregister_handler, &session_message_handler, NULL, NULL, NULL, NULL }; GList *connection_node; gulong pid; g_debug ("GdmSessionDirect: Authenticating new connection"); connection_node = g_list_find (session->priv->pending_connections, connection); if (connection_node == NULL) { g_debug ("GdmSessionDirect: Ignoring connection that we aren't tracking"); return FALSE; } session->priv->pending_connections = g_list_delete_link (session->priv->pending_connections, connection_node); if (!dbus_connection_get_unix_process_id (connection, &pid)) { g_warning ("GdmSessionDirect: Unable to read pid on new worker connection"); dbus_connection_unref (connection); return FALSE; } conversation = find_conversation_by_pid (session, (GPid) pid); if (conversation == NULL) { g_warning ("GdmSessionDirect: New worker connection is from unknown source"); dbus_connection_unref (connection); return FALSE; } conversation->worker_connection = connection; g_debug ("GdmSessionDirect: worker connection is %p", connection); dbus_connection_register_object_path (connection, GDM_SESSION_DBUS_PATH, &vtable, conversation); g_debug ("GdmSessionDirect: Emitting conversation-started signal"); _gdm_session_conversation_started (GDM_SESSION (session), conversation->service_name); g_debug ("GdmSessionDirect: Conversation started"); return TRUE; } static DBusHandlerResult on_message (DBusConnection *connection, DBusMessage *message, void *user_data) { GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data); g_debug ("GdmSessionDirect: got message"); if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Hello")) { DBusMessage *reply; if (register_worker (session, connection)) { reply = dbus_message_new_method_return (message); } else { reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, ""); } dbus_connection_send (connection, reply, NULL); return DBUS_HANDLER_RESULT_HANDLED; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void handle_connection (DBusServer *server, DBusConnection *new_connection, void *user_data) { GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data); g_debug ("GdmSessionDirect: Handing new connection"); /* add to the list of pending connections. We won't be able to * associate it with a specific worker conversation until we have * authenticated the connection (from the Hello handler). */ session->priv->pending_connections = g_list_prepend (session->priv->pending_connections, dbus_connection_ref (new_connection)); dbus_connection_setup_with_g_main (new_connection, NULL); dbus_connection_set_exit_on_disconnect (new_connection, FALSE); dbus_connection_set_unix_user_function (new_connection, allow_user_function, session, NULL); dbus_connection_add_filter (new_connection, on_message, session, NULL); } static gboolean setup_server (GdmSessionDirect *session) { DBusError error; gboolean ret; char *address; const char *auth_mechanisms[] = {"EXTERNAL", NULL}; ret = FALSE; g_debug ("GdmSessionDirect: Creating D-Bus server for session"); address = generate_address (); dbus_error_init (&error); session->priv->server = dbus_server_listen (address, &error); g_free (address); if (session->priv->server == NULL) { g_warning ("Cannot create D-BUS server for the session: %s", error.message); /* FIXME: should probably fail if we can't create the socket */ goto out; } dbus_server_setup_with_g_main (session->priv->server, NULL); dbus_server_set_auth_mechanisms (session->priv->server, auth_mechanisms); dbus_server_set_new_connection_function (session->priv->server, handle_connection, session, NULL); ret = TRUE; g_free (session->priv->server_address); session->priv->server_address = dbus_server_get_address (session->priv->server); g_debug ("GdmSessionDirect: D-Bus server listening on %s", session->priv->server_address); out: return ret; } static void free_conversation (GdmSessionConversation *conversation) { if (conversation->job != NULL) { g_warning ("Freeing conversation '%s' with active job", conversation->service_name); } g_free (conversation->service_name); g_free (conversation); } static void gdm_session_direct_init (GdmSessionDirect *session) { session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, GDM_TYPE_SESSION_DIRECT, GdmSessionDirectPrivate); g_signal_connect (session, "authentication-failed", G_CALLBACK (on_authentication_failed), NULL); g_signal_connect (session, "session-started", G_CALLBACK (on_session_started), NULL); g_signal_connect (session, "session-start-failed", G_CALLBACK (on_session_start_failed), NULL); g_signal_connect (session, "session-exited", G_CALLBACK (on_session_exited), NULL); session->priv->conversations = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) free_conversation); session->priv->environment = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free); setup_server (session); } static void worker_started (GdmSessionWorkerJob *job, GdmSessionConversation *conversation) { g_debug ("GdmSessionDirect: Worker job started"); } static void worker_exited (GdmSessionWorkerJob *job, int code, GdmSessionConversation *conversation) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (conversation->session); g_debug ("GdmSessionDirect: Worker job exited: %d", code); g_object_ref (conversation->job); if (conversation->session->priv->is_running) { _gdm_session_session_exited (GDM_SESSION (conversation->session), code); } g_hash_table_steal (impl->priv->conversations, conversation->service_name); g_debug ("GdmSessionDirect: Emitting conversation-stopped signal"); _gdm_session_conversation_stopped (GDM_SESSION (conversation->session), conversation->service_name); g_object_unref (conversation->job); if (conversation->is_stopping) { g_object_unref (conversation->job); conversation->job = NULL; } free_conversation (conversation); } static void worker_died (GdmSessionWorkerJob *job, int signum, GdmSessionConversation *conversation) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (conversation->session); g_debug ("GdmSessionDirect: Worker job died: %d", signum); g_object_ref (conversation->job); if (conversation->session->priv->is_running) { _gdm_session_session_died (GDM_SESSION (conversation->session), signum); } g_hash_table_steal (impl->priv->conversations, conversation->service_name); g_debug ("GdmSessionDirect: Emitting conversation-stopped signal"); _gdm_session_conversation_stopped (GDM_SESSION (conversation->session), conversation->service_name); g_object_unref (conversation->job); if (conversation->is_stopping) { g_object_unref (conversation->job); conversation->job = NULL; } free_conversation (conversation); } static GdmSessionConversation * start_conversation (GdmSessionDirect *session, const char *service_name) { GdmSessionConversation *conversation; char *job_name; conversation = g_new0 (GdmSessionConversation, 1); conversation->session = session; conversation->service_name = g_strdup (service_name); conversation->worker_pid = -1; conversation->job = gdm_session_worker_job_new (); gdm_session_worker_job_set_server_address (conversation->job, session->priv->server_address); g_signal_connect (conversation->job, "started", G_CALLBACK (worker_started), conversation); g_signal_connect (conversation->job, "exited", G_CALLBACK (worker_exited), conversation); g_signal_connect (conversation->job, "died", G_CALLBACK (worker_died), conversation); job_name = g_strdup_printf ("gdm-session-worker [pam/%s]", service_name); if (!gdm_session_worker_job_start (conversation->job, job_name)) { g_object_unref (conversation->job); g_free (conversation->service_name); g_free (conversation); g_free (job_name); return NULL; } g_free (job_name); conversation->worker_pid = gdm_session_worker_job_get_pid (conversation->job); return conversation; } static void stop_conversation (GdmSessionConversation *conversation) { GdmSessionDirect *session; session = conversation->session; if (conversation->worker_connection != NULL) { dbus_connection_remove_filter (conversation->worker_connection, on_message, session); dbus_connection_close (conversation->worker_connection); conversation->worker_connection = NULL; } conversation->is_stopping = TRUE; gdm_session_worker_job_stop (conversation->job); } static void stop_conversation_now (GdmSessionConversation *conversation) { GdmSessionDirect *session; session = conversation->session; if (conversation->worker_connection != NULL) { dbus_connection_remove_filter (conversation->worker_connection, on_message, session); dbus_connection_close (conversation->worker_connection); conversation->worker_connection = NULL; } gdm_session_worker_job_stop_now (conversation->job); g_object_unref (conversation->job); conversation->job = NULL; } static void gdm_session_direct_start_conversation (GdmSession *session, const char *service_name) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); GdmSessionConversation *conversation; g_return_if_fail (session != NULL); conversation = g_hash_table_lookup (impl->priv->conversations, service_name); if (conversation != NULL) { if (!conversation->is_stopping) { g_warning ("GdmSessionDirect: conversation %s started more than once", service_name); return; } g_debug ("GdmSessionDirect: stopping old conversation %s", service_name); gdm_session_worker_job_stop_now (conversation->job); g_object_unref (conversation->job); conversation->job = NULL; } g_debug ("GdmSessionDirect: starting conversation %s", service_name); conversation = start_conversation (impl, service_name); g_hash_table_insert (impl->priv->conversations, g_strdup (service_name), conversation); } static void gdm_session_direct_stop_conversation (GdmSession *session, const char *service_name) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); GdmSessionConversation *conversation; g_return_if_fail (session != NULL); g_debug ("GdmSessionDirect: stopping conversation %s", service_name); conversation = find_conversation_by_name (impl, service_name); if (conversation != NULL) { stop_conversation (conversation); } } static void send_setup (GdmSessionDirect *session, const char *service_name) { DBusMessage *message; DBusMessageIter iter; const char *display_name; const char *display_device; const char *display_hostname; const char *display_x11_authority_file; GdmSessionConversation *conversation; g_assert (service_name != NULL); if (session->priv->display_name != NULL) { display_name = session->priv->display_name; } else { display_name = ""; } if (session->priv->display_hostname != NULL) { display_hostname = session->priv->display_hostname; } else { display_hostname = ""; } if (session->priv->display_device != NULL) { display_device = session->priv->display_device; } else { display_device = ""; } if (session->priv->display_x11_authority_file != NULL) { display_x11_authority_file = session->priv->display_x11_authority_file; } else { display_x11_authority_file = ""; } g_debug ("GdmSessionDirect: Beginning setup"); message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH, GDM_SESSION_DBUS_INTERFACE, "Setup"); dbus_message_iter_init_append (message, &iter); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &service_name); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_name); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_device); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_hostname); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file); conversation = find_conversation_by_name (session, service_name); if (conversation != NULL && ! send_dbus_message (conversation, message)) { g_debug ("GdmSessionDirect: Could not send %s signal", "Setup"); } dbus_message_unref (message); } static void send_setup_for_user (GdmSessionDirect *session, const char *service_name) { DBusMessage *message; DBusMessageIter iter; const char *display_name; const char *display_device; const char *display_hostname; const char *display_x11_authority_file; const char *selected_user; GdmSessionConversation *conversation; g_assert (service_name != NULL); if (session->priv->display_name != NULL) { display_name = session->priv->display_name; } else { display_name = ""; } if (session->priv->display_hostname != NULL) { display_hostname = session->priv->display_hostname; } else { display_hostname = ""; } if (session->priv->display_device != NULL) { display_device = session->priv->display_device; } else { display_device = ""; } if (session->priv->display_x11_authority_file != NULL) { display_x11_authority_file = session->priv->display_x11_authority_file; } else { display_x11_authority_file = ""; } if (session->priv->selected_user != NULL) { selected_user = session->priv->selected_user; } else { selected_user = ""; } g_debug ("GdmSessionDirect: Beginning setup for user %s", session->priv->selected_user); message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH, GDM_SESSION_DBUS_INTERFACE, "SetupForUser"); dbus_message_iter_init_append (message, &iter); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &service_name); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_name); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_device); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_hostname); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &selected_user); conversation = find_conversation_by_name (session, service_name); if (conversation != NULL && ! send_dbus_message (conversation, message)) { g_debug ("GdmSessionDirect: Could not send %s signal", "SetupForUser"); } dbus_message_unref (message); } static void send_setup_for_program (GdmSessionDirect *session, const char *service_name, const char *log_file) { DBusMessage *message; DBusMessageIter iter; const char *display_name; const char *display_device; const char *display_hostname; const char *display_x11_authority_file; GdmSessionConversation *conversation; g_assert (service_name != NULL); if (session->priv->display_name != NULL) { display_name = session->priv->display_name; } else { display_name = ""; } if (session->priv->display_hostname != NULL) { display_hostname = session->priv->display_hostname; } else { display_hostname = ""; } if (session->priv->display_device != NULL) { display_device = session->priv->display_device; } else { display_device = ""; } if (session->priv->display_x11_authority_file != NULL) { display_x11_authority_file = session->priv->display_x11_authority_file; } else { display_x11_authority_file = ""; } g_debug ("GdmSessionDirect: Beginning setup for session for program with log '%s'", log_file); message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH, GDM_SESSION_DBUS_INTERFACE, "SetupForProgram"); dbus_message_iter_init_append (message, &iter); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &service_name); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_name); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_device); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_hostname); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &log_file); conversation = find_conversation_by_name (session, service_name); if (conversation != NULL && ! send_dbus_message (conversation, message)) { g_debug ("GdmSessionDirect: Could not send %s signal", "SetupForProgram"); } dbus_message_unref (message); } static void gdm_session_direct_setup (GdmSession *session, const char *service_name) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); g_return_if_fail (session != NULL); send_setup (impl, service_name); gdm_session_direct_defaults_changed (impl); } static void gdm_session_direct_setup_for_user (GdmSession *session, const char *service_name, const char *username) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); g_return_if_fail (session != NULL); g_return_if_fail (username != NULL); gdm_session_direct_select_user (session, username); send_setup_for_user (impl, service_name); gdm_session_direct_defaults_changed (impl); } static void gdm_session_direct_setup_for_program (GdmSession *session, const char *service_name, const char *log_file) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); g_return_if_fail (session != NULL); send_setup_for_program (impl, service_name, log_file); } static void gdm_session_direct_authenticate (GdmSession *session, const char *service_name) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); GdmSessionConversation *conversation; g_return_if_fail (session != NULL); conversation = find_conversation_by_name (impl, service_name); if (conversation != NULL) { send_dbus_void_signal (conversation, "Authenticate"); } } static void gdm_session_direct_authorize (GdmSession *session, const char *service_name) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); GdmSessionConversation *conversation; g_return_if_fail (session != NULL); conversation = find_conversation_by_name (impl, service_name); if (conversation != NULL) { send_dbus_void_signal (conversation, "Authorize"); } } static void gdm_session_direct_accredit (GdmSession *session, const char *service_name, int cred_flag) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); GdmSessionConversation *conversation; g_return_if_fail (session != NULL); conversation = find_conversation_by_name (impl, service_name); if (conversation == NULL) { return; } switch (cred_flag) { case GDM_SESSION_CRED_ESTABLISH: send_dbus_void_signal (conversation, "EstablishCredentials"); break; case GDM_SESSION_CRED_REFRESH: send_dbus_void_signal (conversation, "RefreshCredentials"); break; default: g_assert_not_reached (); } } static void send_environment_variable (const char *key, const char *value, GdmSessionConversation *conversation) { DBusMessage *message; DBusMessageIter iter; message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH, GDM_SESSION_DBUS_INTERFACE, "SetEnvironmentVariable"); dbus_message_iter_init_append (message, &iter); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value); if (! send_dbus_message (conversation, message)) { g_debug ("GdmSessionDirect: Could not send %s signal", "SetEnvironmentVariable"); } dbus_message_unref (message); } static void send_environment (GdmSessionDirect *session, GdmSessionConversation *conversation) { g_hash_table_foreach (session->priv->environment, (GHFunc) send_environment_variable, conversation); } static const char * get_language_name (GdmSessionDirect *session) { if (session->priv->selected_language != NULL) { return session->priv->selected_language; } return get_default_language_name (session); } static const char * get_session_name (GdmSessionDirect *session) { /* FIXME: test the session names before we use them? */ if (session->priv->selected_session != NULL) { return session->priv->selected_session; } return get_default_session_name (session); } static char * get_session_command (GdmSessionDirect *session) { gboolean res; char *command; const char *session_name; session_name = get_session_name (session); command = NULL; res = get_session_command_for_name (session_name, &command); if (! res) { g_critical ("Cannot find a command for specified session: %s", session_name); exit (1); } return command; } static void gdm_session_direct_set_environment_variable (GdmSession *session, const char *key, const char *value) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); g_return_if_fail (key != NULL); g_return_if_fail (value != NULL); g_hash_table_replace (impl->priv->environment, g_strdup (key), g_strdup (value)); } static void setup_session_environment (GdmSessionDirect *session_direct) { GdmSession *session = GDM_SESSION (session_direct); const char *locale; gdm_session_direct_set_environment_variable (session, "GDMSESSION", get_session_name (session_direct)); gdm_session_direct_set_environment_variable (session, "DESKTOP_SESSION", get_session_name (session_direct)); locale = get_language_name (session_direct); if (locale != NULL && locale[0] != '\0') { gdm_session_direct_set_environment_variable (session, "LANG", locale); gdm_session_direct_set_environment_variable (session, "GDM_LANG", locale); } gdm_session_direct_set_environment_variable (session, "DISPLAY", session_direct->priv->display_name); if (session_direct->priv->user_x11_authority_file != NULL) { gdm_session_direct_set_environment_variable (session, "XAUTHORITY", session_direct->priv->user_x11_authority_file); } if (g_getenv ("WINDOWPATH") != NULL) { gdm_session_direct_set_environment_variable (session, "WINDOWPATH", g_getenv ("WINDOWPATH")); } /* FIXME: We do this here and in the session worker. We should consolidate * somehow. */ gdm_session_direct_set_environment_variable (session, "PATH", strcmp (BINDIR, "/usr/bin") == 0? GDM_SESSION_DEFAULT_PATH : BINDIR ":" GDM_SESSION_DEFAULT_PATH); } static void gdm_session_direct_open_session (GdmSession *session, const char *service_name) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); GdmSessionConversation *conversation; g_return_if_fail (session != NULL); conversation = find_conversation_by_name (impl, service_name); send_dbus_string_signal (conversation, "OpenSession", service_name); } static void stop_all_other_conversations (GdmSessionDirect *session, GdmSessionConversation *conversation_to_keep, gboolean now) { GHashTableIter iter; gpointer key, value; if (session->priv->conversations == NULL) { return; } if (conversation_to_keep == NULL) { g_debug ("GdmSessionDirect: Stopping all conversations"); } else { g_debug ("GdmSessionDirect: Stopping all conversations " "except for %s", conversation_to_keep->service_name); } g_hash_table_iter_init (&iter, session->priv->conversations); while (g_hash_table_iter_next (&iter, &key, &value)) { GdmSessionConversation *conversation; conversation = (GdmSessionConversation *) value; if (conversation == conversation_to_keep) { if (now) { g_hash_table_iter_steal (&iter); g_free (key); } } else { if (now) { stop_conversation_now (conversation); } else { stop_conversation (conversation); } } } if (now) { g_hash_table_remove_all (session->priv->conversations); if (conversation_to_keep != NULL) { g_hash_table_insert (session->priv->conversations, g_strdup (conversation_to_keep->service_name), conversation_to_keep); } } } static void gdm_session_direct_start_session (GdmSession *session, const char *service_name) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); GdmSessionConversation *conversation; char *command; char *program; g_return_if_fail (session != NULL); g_return_if_fail (impl->priv->is_running == FALSE); conversation = find_conversation_by_name (impl, service_name); if (conversation == NULL) { g_warning ("GdmSessionDirect: Tried to start session of " "nonexistent conversation %s", service_name); return; } stop_all_other_conversations (impl, conversation, FALSE); if (impl->priv->selected_program == NULL) { command = get_session_command (impl); if (gdm_session_direct_bypasses_xsession (impl)) { program = g_strdup (command); } else { program = g_strdup_printf (GDMCONFDIR "/Xsession \"%s\"", command); } g_free (command); } else { program = g_strdup (impl->priv->selected_program); } setup_session_environment (impl); send_environment (impl, conversation); send_dbus_string_signal (conversation, "StartProgram", program); g_free (program); } static void stop_all_conversations (GdmSessionDirect *session) { stop_all_other_conversations (session, NULL, TRUE); } static void gdm_session_direct_close (GdmSession *session) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); g_return_if_fail (session != NULL); g_debug ("GdmSessionDirect: Closing session"); if (impl->priv->is_running) { gdm_session_record_logout (impl->priv->session_pid, impl->priv->selected_user, impl->priv->display_hostname, impl->priv->display_name, impl->priv->display_device); } stop_all_conversations (impl); g_list_foreach (impl->priv->pending_connections, (GFunc) dbus_connection_unref, NULL); g_list_free (impl->priv->pending_connections); impl->priv->pending_connections = NULL; g_free (impl->priv->selected_user); impl->priv->selected_user = NULL; g_free (impl->priv->selected_session); impl->priv->selected_session = NULL; g_free (impl->priv->saved_session); impl->priv->saved_session = NULL; g_free (impl->priv->selected_language); impl->priv->selected_language = NULL; g_free (impl->priv->saved_language); impl->priv->saved_language = NULL; g_free (impl->priv->user_x11_authority_file); impl->priv->user_x11_authority_file = NULL; g_hash_table_remove_all (impl->priv->environment); impl->priv->session_pid = -1; impl->priv->is_running = FALSE; } static void gdm_session_direct_answer_query (GdmSession *session, const char *service_name, const char *text) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); GdmSessionConversation *conversation; g_return_if_fail (session != NULL); conversation = find_conversation_by_name (impl, service_name); answer_pending_query (conversation, text); } static void gdm_session_direct_cancel (GdmSession *session) { g_return_if_fail (session != NULL); stop_all_conversations (GDM_SESSION_DIRECT (session)); } char * gdm_session_direct_get_username (GdmSessionDirect *session) { g_return_val_if_fail (session != NULL, NULL); return g_strdup (session->priv->selected_user); } char * gdm_session_direct_get_display_device (GdmSessionDirect *session) { g_return_val_if_fail (session != NULL, NULL); return g_strdup (session->priv->display_device); } gboolean gdm_session_direct_bypasses_xsession (GdmSessionDirect *session_direct) { GError *error; GKeyFile *key_file; gboolean res; gboolean bypasses_xsession = FALSE; char *filename; g_return_val_if_fail (session_direct != NULL, FALSE); g_return_val_if_fail (GDM_IS_SESSION_DIRECT (session_direct), FALSE); filename = g_strdup_printf ("%s.desktop", get_session_name (session_direct)); key_file = g_key_file_new (); error = NULL; res = g_key_file_load_from_dirs (key_file, filename, get_system_session_dirs (), NULL, G_KEY_FILE_NONE, &error); if (! res) { g_debug ("GdmSessionDirect: File '%s' not found: %s", filename, error->message); goto out; } error = NULL; res = g_key_file_has_key (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-BypassXsession", NULL); if (!res) { goto out; } else { bypasses_xsession = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-BypassXsession", &error); if (error) { bypasses_xsession = FALSE; g_error_free (error); goto out; } if (bypasses_xsession) { g_debug ("GdmSessionDirect: Session %s bypasses Xsession wrapper script", filename); } } out: g_free (filename); return bypasses_xsession; } static void gdm_session_direct_select_program (GdmSession *session, const char *text) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); g_free (impl->priv->selected_program); impl->priv->selected_program = g_strdup (text); } static void gdm_session_direct_select_session_type (GdmSession *session, const char *text) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); GHashTableIter iter; gpointer key, value; g_hash_table_iter_init (&iter, impl->priv->conversations); while (g_hash_table_iter_next (&iter, &key, &value)) { GdmSessionConversation *conversation; conversation = (GdmSessionConversation *) value; send_dbus_string_signal (conversation, "SetSessionType", text); } } static void gdm_session_direct_select_session (GdmSession *session, const char *text) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); GHashTableIter iter; gpointer key, value; g_free (impl->priv->selected_session); if (strcmp (text, "__previous") == 0) { impl->priv->selected_session = NULL; } else { impl->priv->selected_session = g_strdup (text); } g_hash_table_iter_init (&iter, impl->priv->conversations); while (g_hash_table_iter_next (&iter, &key, &value)) { GdmSessionConversation *conversation; conversation = (GdmSessionConversation *) value; send_dbus_string_signal (conversation, "SetSessionName", get_session_name (impl)); } } static void gdm_session_direct_select_language (GdmSession *session, const char *text) { GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); GHashTableIter iter; gpointer key, value; g_free (impl->priv->selected_language); if (strcmp (text, "__previous") == 0) { impl->priv->selected_language = NULL; } else { impl->priv->selected_language = g_strdup (text); } g_hash_table_iter_init (&iter, impl->priv->conversations); while (g_hash_table_iter_next (&iter, &key, &value)) { GdmSessionConversation *conversation; conversation = (GdmSessionConversation *) value; send_dbus_string_signal (conversation, "SetLanguageName", get_language_name (impl)); } } static void _gdm_session_direct_set_display_id (GdmSessionDirect *session, const char *id) { g_free (session->priv->display_id); session->priv->display_id = g_strdup (id); } /* At some point we may want to read these right from * the slave but for now I don't want the dependency */ static void _gdm_session_direct_set_display_name (GdmSessionDirect *session, const char *name) { g_free (session->priv->display_name); session->priv->display_name = g_strdup (name); } static void _gdm_session_direct_set_display_hostname (GdmSessionDirect *session, const char *name) { g_free (session->priv->display_hostname); session->priv->display_hostname = g_strdup (name); } static void _gdm_session_direct_set_display_device (GdmSessionDirect *session, const char *name) { g_debug ("GdmSessionDirect: Setting display device: %s", name); g_free (session->priv->display_device); session->priv->display_device = g_strdup (name); } static void _gdm_session_direct_set_user_x11_authority_file (GdmSessionDirect *session, const char *name) { g_free (session->priv->user_x11_authority_file); session->priv->user_x11_authority_file = g_strdup (name); } static void _gdm_session_direct_set_display_x11_authority_file (GdmSessionDirect *session, const char *name) { g_free (session->priv->display_x11_authority_file); session->priv->display_x11_authority_file = g_strdup (name); } static void _gdm_session_direct_set_display_is_local (GdmSessionDirect *session, gboolean is) { session->priv->display_is_local = is; } static void gdm_session_direct_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GdmSessionDirect *self; self = GDM_SESSION_DIRECT (object); switch (prop_id) { case PROP_DISPLAY_ID: _gdm_session_direct_set_display_id (self, g_value_get_string (value)); break; case PROP_DISPLAY_NAME: _gdm_session_direct_set_display_name (self, g_value_get_string (value)); break; case PROP_DISPLAY_HOSTNAME: _gdm_session_direct_set_display_hostname (self, g_value_get_string (value)); break; case PROP_DISPLAY_DEVICE: _gdm_session_direct_set_display_device (self, g_value_get_string (value)); break; case PROP_USER_X11_AUTHORITY_FILE: _gdm_session_direct_set_user_x11_authority_file (self, g_value_get_string (value)); break; case PROP_DISPLAY_X11_AUTHORITY_FILE: _gdm_session_direct_set_display_x11_authority_file (self, g_value_get_string (value)); break; case PROP_DISPLAY_IS_LOCAL: _gdm_session_direct_set_display_is_local (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gdm_session_direct_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GdmSessionDirect *self; self = GDM_SESSION_DIRECT (object); switch (prop_id) { case PROP_DISPLAY_ID: g_value_set_string (value, self->priv->display_id); break; case PROP_DISPLAY_NAME: g_value_set_string (value, self->priv->display_name); break; case PROP_DISPLAY_HOSTNAME: g_value_set_string (value, self->priv->display_hostname); break; case PROP_DISPLAY_DEVICE: g_value_set_string (value, self->priv->display_device); break; case PROP_USER_X11_AUTHORITY_FILE: g_value_set_string (value, self->priv->user_x11_authority_file); break; case PROP_DISPLAY_X11_AUTHORITY_FILE: g_value_set_string (value, self->priv->display_x11_authority_file); break; case PROP_DISPLAY_IS_LOCAL: g_value_set_boolean (value, self->priv->display_is_local); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gdm_session_direct_dispose (GObject *object) { GdmSessionDirect *session; session = GDM_SESSION_DIRECT (object); g_debug ("GdmSessionDirect: Disposing session"); gdm_session_direct_close (GDM_SESSION (session)); g_free (session->priv->display_id); session->priv->display_id = NULL; g_free (session->priv->display_name); session->priv->display_name = NULL; g_free (session->priv->display_hostname); session->priv->display_hostname = NULL; g_free (session->priv->display_device); session->priv->display_device = NULL; g_free (session->priv->display_x11_authority_file); session->priv->display_x11_authority_file = NULL; g_free (session->priv->server_address); session->priv->server_address = NULL; if (session->priv->server != NULL) { dbus_server_disconnect (session->priv->server); dbus_server_unref (session->priv->server); session->priv->server = NULL; } if (session->priv->environment != NULL) { g_hash_table_destroy (session->priv->environment); session->priv->environment = NULL; } G_OBJECT_CLASS (gdm_session_direct_parent_class)->dispose (object); } static void gdm_session_direct_finalize (GObject *object) { GdmSessionDirect *session; GObjectClass *parent_class; session = GDM_SESSION_DIRECT (object); g_free (session->priv->id); g_free (session->priv->selected_user); g_free (session->priv->selected_session); g_free (session->priv->saved_session); g_free (session->priv->selected_language); g_free (session->priv->saved_language); g_free (session->priv->fallback_session_name); parent_class = G_OBJECT_CLASS (gdm_session_direct_parent_class); if (parent_class->finalize != NULL) parent_class->finalize (object); } static gboolean register_session (GdmSessionDirect *session) { GError *error; error = NULL; session->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); if (session->priv->connection == NULL) { if (error != NULL) { g_critical ("error getting system bus: %s", error->message); g_error_free (error); } exit (1); } dbus_g_connection_register_g_object (session->priv->connection, session->priv->id, G_OBJECT (session)); return TRUE; } static GObject * gdm_session_direct_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GdmSessionDirect *session; gboolean res; const char *id; session = GDM_SESSION_DIRECT (G_OBJECT_CLASS (gdm_session_direct_parent_class)->constructor (type, n_construct_properties, construct_properties)); if (session->priv->display_id != NULL) { /* Always match the session id with the master */ id = NULL; if (g_str_has_prefix (session->priv->display_id, "/org/gnome/DisplayManager/Display")) { id = session->priv->display_id + strlen ("/org/gnome/DisplayManager/Display"); } g_assert (id != NULL); session->priv->id = g_strdup_printf ("/org/gnome/DisplayManager/Session%s", id); g_debug ("GdmSessionDirect: Registering %s", session->priv->id); res = register_session (session); if (! res) { g_warning ("Unable to register session with system bus"); } } return G_OBJECT (session); } static void gdm_session_iface_init (GdmSessionIface *iface) { iface->start_conversation = gdm_session_direct_start_conversation; iface->stop_conversation = gdm_session_direct_stop_conversation; iface->setup = gdm_session_direct_setup; iface->setup_for_user = gdm_session_direct_setup_for_user; iface->setup_for_program = gdm_session_direct_setup_for_program; iface->set_environment_variable = gdm_session_direct_set_environment_variable; iface->authenticate = gdm_session_direct_authenticate; iface->authorize = gdm_session_direct_authorize; iface->accredit = gdm_session_direct_accredit; iface->open_session = gdm_session_direct_open_session; iface->close = gdm_session_direct_close; iface->cancel = gdm_session_direct_cancel; iface->start_session = gdm_session_direct_start_session; iface->answer_query = gdm_session_direct_answer_query; iface->select_program = gdm_session_direct_select_program; iface->select_session_type = gdm_session_direct_select_session_type; iface->select_session = gdm_session_direct_select_session; iface->select_language = gdm_session_direct_select_language; iface->select_user = gdm_session_direct_select_user; } static void gdm_session_direct_class_init (GdmSessionDirectClass *session_class) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (session_class); object_class->get_property = gdm_session_direct_get_property; object_class->set_property = gdm_session_direct_set_property; object_class->constructor = gdm_session_direct_constructor; object_class->dispose = gdm_session_direct_dispose; object_class->finalize = gdm_session_direct_finalize; g_type_class_add_private (session_class, sizeof (GdmSessionDirectPrivate)); g_object_class_install_property (object_class, PROP_DISPLAY_ID, g_param_spec_string ("display-id", "display id", "display id", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_DISPLAY_NAME, g_param_spec_string ("display-name", "display name", "display name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_DISPLAY_HOSTNAME, g_param_spec_string ("display-hostname", "display hostname", "display hostname", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_DISPLAY_IS_LOCAL, g_param_spec_boolean ("display-is-local", "display is local", "display is local", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_DISPLAY_X11_AUTHORITY_FILE, g_param_spec_string ("display-x11-authority-file", "display x11 authority file", "display x11 authority file", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); /* not construct only */ g_object_class_install_property (object_class, PROP_USER_X11_AUTHORITY_FILE, g_param_spec_string ("user-x11-authority-file", "", "", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_DISPLAY_DEVICE, g_param_spec_string ("display-device", "display device", "display device", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); dbus_g_object_type_install_info (GDM_TYPE_SESSION_DIRECT, &dbus_glib_gdm_session_direct_object_info); } GdmSessionDirect * gdm_session_direct_new (const char *display_id, const char *display_name, const char *display_hostname, const char *display_device, const char *display_x11_authority_file, gboolean display_is_local) { GdmSessionDirect *session; session = g_object_new (GDM_TYPE_SESSION_DIRECT, "display-id", display_id, "display-name", display_name, "display-hostname", display_hostname, "display-device", display_device, "display-x11-authority-file", display_x11_authority_file, "display-is-local", display_is_local, NULL); return session; } gboolean gdm_session_direct_restart (GdmSessionDirect *session, GError **error) { gboolean ret; ret = TRUE; g_debug ("GdmSessionDirect: Request to restart session"); return ret; } gboolean gdm_session_direct_stop (GdmSessionDirect *session, GError **error) { gboolean ret; ret = TRUE; g_debug ("GdmSessionDirect: Request to stop session"); return ret; } gboolean gdm_session_direct_detach (GdmSessionDirect *session, GError **error) { gboolean ret; ret = TRUE; g_debug ("GdmSessionDirect: Request to detach session"); return ret; }