/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * 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 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef WITH_SYSTEMD #include #endif #include "gdm-common.h" #include "gdm-dbus-util.h" #include "gdm-manager.h" #include "gdm-manager-glue.h" #include "gdm-display-store.h" #include "gdm-display-factory.h" #include "gdm-local-display-factory.h" #include "gdm-session.h" #include "gdm-xdmcp-display-factory.h" #define GDM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_MANAGER, GdmManagerPrivate)) #define GDM_DBUS_PATH "/org/gnome/DisplayManager" #define GDM_MANAGER_PATH GDM_DBUS_PATH "/Manager" #define GDM_MANAGER_DISPLAYS_PATH GDM_DBUS_PATH "/Displays" #define CK_NAME "org.freedesktop.ConsoleKit" #define CK_PATH "/org/freedesktop/ConsoleKit" #define CK_INTERFACE "org.freedesktop.ConsoleKit" #define CK_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager" #define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager" #define CK_SEAT_INTERFACE "org.freedesktop.ConsoleKit.Seat" #define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session" struct GdmManagerPrivate { GdmDisplayStore *display_store; GdmLocalDisplayFactory *local_factory; #ifdef HAVE_LIBXDMCP GdmXdmcpDisplayFactory *xdmcp_factory; #endif GList *user_sessions; GHashTable *transient_sessions; GHashTable *open_reauthentication_requests; gboolean xdmcp_enabled; GCancellable *cancellable; gboolean started; gboolean wait_for_go; gboolean show_local_greeter; GDBusProxy *bus_proxy; GDBusConnection *connection; GDBusObjectManagerServer *object_manager; }; enum { PROP_0, PROP_XDMCP_ENABLED, PROP_SHOW_LOCAL_GREETER }; enum { DISPLAY_ADDED, DISPLAY_REMOVED, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0, }; static void gdm_manager_class_init (GdmManagerClass *klass); static void gdm_manager_init (GdmManager *manager); static void gdm_manager_dispose (GObject *object); static void create_seed_session_for_display (GdmManager *manager, GdmDisplay *display, uid_t allowed_user); static void touch_ran_once_marker_file (GdmManager *manager); static gpointer manager_object = NULL; static void manager_interface_init (GdmDBusManagerIface *interface); G_DEFINE_TYPE_WITH_CODE (GdmManager, gdm_manager, GDM_DBUS_TYPE_MANAGER_SKELETON, G_IMPLEMENT_INTERFACE (GDM_DBUS_TYPE_MANAGER, manager_interface_init)); #ifdef WITH_SYSTEMD static char * get_session_id_for_pid_systemd (pid_t pid, GError **error) { char *session, *gsession; int ret; session = NULL; ret = sd_pid_get_session (pid, &session); if (ret < 0) { g_set_error (error, GDM_DISPLAY_ERROR, GDM_DISPLAY_ERROR_GETTING_SESSION_INFO, "Error getting session id from systemd: %s", g_strerror (-ret)); return NULL; } if (session != NULL) { gsession = g_strdup (session); free (session); return gsession; } else { return NULL; } } #endif #ifdef WITH_CONSOLE_KIT static char * get_session_id_for_pid_consolekit (GDBusConnection *connection, pid_t pid, GError **error) { GVariant *reply; char *retval; reply = g_dbus_connection_call_sync (connection, "org.freedesktop.ConsoleKit", "/org/freedesktop/ConsoleKit/Manager", "org.freedesktop.ConsoleKit.Manager", "GetSessionForUnixProcess", g_variant_new ("(u)", pid), G_VARIANT_TYPE ("(o)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (reply == NULL) { return NULL; } g_variant_get (reply, "(o)", &retval); g_variant_unref (reply); return retval; } #endif static char * get_session_id_for_pid (GDBusConnection *connection, pid_t pid, GError **error) { #ifdef WITH_SYSTEMD if (LOGIND_RUNNING()) { return get_session_id_for_pid_systemd (pid, error); } #endif #ifdef WITH_CONSOLE_KIT return get_session_id_for_pid_consolekit (connection, pid, error); #endif return NULL; } #ifdef WITH_SYSTEMD static gboolean get_uid_for_systemd_session_id (const char *session_id, uid_t *uid, GError **error) { int ret; ret = sd_session_get_uid (session_id, uid); if (ret < 0) { g_set_error (error, GDM_DISPLAY_ERROR, GDM_DISPLAY_ERROR_GETTING_SESSION_INFO, "Error getting uid for session id %s from systemd: %s", session_id, g_strerror (-ret)); return FALSE; } return TRUE; } #endif #ifdef WITH_CONSOLE_KIT static gboolean get_uid_for_consolekit_session_id (GDBusConnection *connection, const char *session_id, uid_t *out_uid, GError **error) { GVariant *reply; guint32 uid; reply = g_dbus_connection_call_sync (connection, "org.freedesktop.ConsoleKit", session_id, "org.freedesktop.ConsoleKit.Session", "GetUnixUser", NULL, G_VARIANT_TYPE ("(u)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (reply == NULL) { return FALSE; } g_variant_get (reply, "(u)", &uid); g_variant_unref (reply); *out_uid = (uid_t) uid; return TRUE; } #endif static gboolean get_uid_for_session_id (GDBusConnection *connection, const char *session_id, uid_t *uid, GError **error) { #ifdef WITH_SYSTEMD if (LOGIND_RUNNING()) { return get_uid_for_systemd_session_id (session_id, uid, error); } #endif #ifdef WITH_CONSOLE_KIT return get_uid_for_consolekit_session_id (connection, session_id, uid, error); #endif return FALSE; } static gboolean lookup_by_session_id (const char *id, GdmDisplay *display, gpointer user_data) { const char *looking_for = user_data; const char *current; current = gdm_display_get_session_id (display); return g_strcmp0 (current, looking_for) == 0; } #ifdef WITH_CONSOLE_KIT static gboolean is_consolekit_login_session (GdmManager *self, GDBusConnection *connection, const char *session_id, GError **error) { GVariant *reply; char *session_type = NULL; reply = g_dbus_connection_call_sync (connection, "org.freedesktop.ConsoleKit", session_id, "org.freedesktop.ConsoleKit.Session", "GetSessionType", NULL, G_VARIANT_TYPE ("(s)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (reply == NULL) { return FALSE; } g_variant_get (reply, "(s)", &session_type); g_variant_unref (reply); if (g_strcmp0 (session_type, "LoginWindow") != 0) { g_free (session_type); return FALSE; } g_free (session_type); return TRUE; } #endif #ifdef WITH_SYSTEMD static gboolean is_systemd_login_session (GdmManager *self, const char *session_id, GError **error) { char *session_class = NULL; int ret; ret = sd_session_get_class (session_id, &session_class); if (ret < 0) { g_set_error (error, GDM_DISPLAY_ERROR, GDM_DISPLAY_ERROR_GETTING_SESSION_INFO, "Error getting class for session id %s from systemd: %s", session_id, g_strerror (-ret)); return FALSE; } if (g_strcmp0 (session_class, "greeter") != 0) { g_free (session_class); return FALSE; } g_free (session_class); return TRUE; } #endif static gboolean is_login_session (GdmManager *self, GDBusConnection *connection, const char *session_id, GError **error) { #ifdef WITH_SYSTEMD if (LOGIND_RUNNING()) { return is_systemd_login_session (self, session_id, error); } #endif #ifdef WITH_CONSOLE_KIT return is_consolekit_login_session (self, connection, session_id, error); #endif return FALSE; } #ifdef WITH_SYSTEMD static gboolean activate_session_id_for_systemd (GdmManager *manager, const char *seat_id, const char *session_id) { GError *error = NULL; GVariant *reply; reply = g_dbus_connection_call_sync (manager->priv->connection, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "ActivateSessionOnSeat", g_variant_new ("(ss)", session_id, seat_id), NULL, /* expected reply */ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (reply == NULL) { g_debug ("GdmManager: logind 'ActivateSessionOnSeat' %s raised:\n %s\n\n", g_dbus_error_get_remote_error (error), error->message); g_error_free (error); return FALSE; } g_variant_unref (reply); return TRUE; } #endif #ifdef WITH_CONSOLE_KIT static gboolean activate_session_id_for_ck (GdmManager *manager, const char *seat_id, const char *session_id) { GError *error = NULL; GVariant *reply; reply = g_dbus_connection_call_sync (manager->priv->connection, CK_NAME, seat_id, "org.freedesktop.ConsoleKit.Seat", "ActivateSession", g_variant_new ("(o)", session_id), NULL, /* expected reply */ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (reply == NULL) { g_debug ("GdmManager: ConsoleKit %s raised:\n %s\n\n", g_dbus_error_get_remote_error (error), error->message); g_error_free (error); /* It is very likely that the "error" just reported is * that the session is already active. Unfortunately, * ConsoleKit doesn't use proper error codes and it * translates the error message, so we have no real way * to detect this case... */ return TRUE; } g_variant_unref (reply); return TRUE; } #endif static gboolean activate_session_id (GdmManager *manager, const char *seat_id, const char *session_id) { #ifdef WITH_SYSTEMD if (LOGIND_RUNNING()) { return activate_session_id_for_systemd (manager, seat_id, session_id); } #endif #ifdef WITH_CONSOLE_KIT return activate_session_id_for_ck (manager, seat_id, session_id); #else return FALSE; #endif } #ifdef WITH_SYSTEMD static gboolean session_unlock_for_systemd (GdmManager *manager, const char *ssid) { GError *error = NULL; GVariant *reply; reply = g_dbus_connection_call_sync (manager->priv->connection, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "UnlockSession", g_variant_new ("(s)", ssid), NULL, /* expected reply */ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (reply == NULL) { g_debug ("GdmManager: logind 'UnlockSession' %s raised:\n %s\n\n", g_dbus_error_get_remote_error (error), error->message); g_error_free (error); return FALSE; } g_variant_unref (reply); return TRUE; } #endif #ifdef WITH_CONSOLE_KIT static gboolean session_unlock_for_ck (GdmManager *manager, const char *ssid) { GError *error = NULL; GVariant *reply; reply = g_dbus_connection_call_sync (manager->priv->connection, CK_NAME, ssid, CK_SESSION_INTERFACE, "Unlock", NULL, /* parameters */ NULL, /* expected reply */ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (reply == NULL) { g_debug ("GdmManager: ConsoleKit %s raised:\n %s\n\n", g_dbus_error_get_remote_error (error), error->message); g_error_free (error); return FALSE; } g_variant_unref (reply); return TRUE; } #endif static gboolean session_unlock (GdmManager *manager, const char *ssid) { g_debug ("Unlocking session %s", ssid); #ifdef WITH_SYSTEMD if (LOGIND_RUNNING()) { return session_unlock_for_systemd (manager, ssid); } #endif #ifdef WITH_CONSOLE_KIT return session_unlock_for_ck (manager, ssid); #else return TRUE; #endif } static GdmSession * find_session_for_user_on_seat (GdmManager *manager, const char *username, const char *seat_id, GdmSession *dont_count_session) { GList *node; for (node = manager->priv->user_sessions; node != NULL; node = node->next) { GdmSession *candidate_session = node->data; const char *candidate_username, *candidate_seat_id; if (candidate_session == dont_count_session) continue; if (!gdm_session_is_running (candidate_session)) continue; candidate_username = gdm_session_get_username (candidate_session); candidate_seat_id = gdm_session_get_display_seat_id (candidate_session); if (g_strcmp0 (candidate_username, username) == 0 && g_strcmp0 (candidate_seat_id, seat_id) == 0) { return candidate_session; } } return NULL; } #ifdef WITH_CONSOLE_KIT static gboolean is_consolekit_remote_session (GdmManager *self, GDBusConnection *connection, const char *session_id, GError **error) { GVariant *reply; gboolean is_remote; reply = g_dbus_connection_call_sync (connection, "org.freedesktop.ConsoleKit", session_id, "org.freedesktop.ConsoleKit.Session", "IsLocal", NULL, G_VARIANT_TYPE ("(b)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (reply == NULL) { return FALSE; } g_variant_get (reply, "(b)", &is_remote); g_variant_unref (reply); return is_remote; } #endif #ifdef WITH_SYSTEMD static gboolean is_systemd_remote_session (GdmManager *self, const char *session_id, GError **error) { char *seat; int ret; gboolean is_remote; /* FIXME: The next release of logind is going to have explicit api for * checking remoteness. */ seat = NULL; ret = sd_session_get_seat (session_id, &seat); if (ret < 0 && ret != -ENOENT) { g_debug ("GdmManager: Error while retrieving seat for session %s: %s", session_id, strerror (-ret)); } if (seat != NULL) { is_remote = FALSE; free (seat); } else { is_remote = TRUE; } return is_remote; } #endif static gboolean is_remote_session (GdmManager *self, GDBusConnection *connection, const char *session_id, GError **error) { #ifdef WITH_SYSTEMD if (LOGIND_RUNNING()) { return is_systemd_remote_session (self, session_id, error); } #endif #ifdef WITH_CONSOLE_KIT return is_consolekit_remote_session (self, connection, session_id, error); #endif return FALSE; } #ifdef WITH_SYSTEMD static char * get_seat_id_for_systemd_session_id (const char *session_id, GError **error) { int ret; char *seat, *out_seat; seat = NULL; ret = sd_session_get_seat (session_id, &seat); if (ret == -ENOENT) { out_seat = NULL; } else if (ret < 0) { g_set_error (error, GDM_DISPLAY_ERROR, GDM_DISPLAY_ERROR_GETTING_SESSION_INFO, "Error getting uid for session id %s from systemd: %s", session_id, g_strerror (-ret)); out_seat = NULL; } else { out_seat = g_strdup (seat); free (seat); } return out_seat; } #endif #ifdef WITH_CONSOLE_KIT static char * get_seat_id_for_consolekit_session_id (GDBusConnection *connection, const char *session_id, GError **error) { GVariant *reply; char *retval; reply = g_dbus_connection_call_sync (connection, "org.freedesktop.ConsoleKit", session_id, "org.freedesktop.ConsoleKit.Session", "GetSeatId", NULL, G_VARIANT_TYPE ("(o)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (reply == NULL) { return NULL; } g_variant_get (reply, "(o)", &retval); g_variant_unref (reply); return retval; } #endif static char * get_seat_id_for_session_id (GDBusConnection *connection, const char *session_id, GError **error) { #ifdef WITH_SYSTEMD if (LOGIND_RUNNING()) { return get_seat_id_for_systemd_session_id (session_id, error); } #endif #ifdef WITH_CONSOLE_KIT return get_seat_id_for_consolekit_session_id (connection, session_id, error); #endif return NULL; } static void get_display_and_details_for_bus_sender (GdmManager *self, GDBusConnection *connection, const char *sender, GdmDisplay **out_display, char **out_seat_id, char **out_session_id, GPid *out_pid, uid_t *out_uid, gboolean *out_is_login_screen, gboolean *out_is_remote) { GdmDisplay *display = NULL; char *session_id = NULL; GError *error = NULL; int ret; GPid pid; uid_t caller_uid, session_uid; ret = gdm_dbus_get_pid_for_name (sender, &pid, &error); if (!ret) { g_debug ("GdmManager: Error while retrieving pid for sender: %s", error->message); g_error_free (error); goto out; } if (out_pid != NULL) { *out_pid = pid; } ret = gdm_dbus_get_uid_for_name (sender, &caller_uid, &error); if (!ret) { g_debug ("GdmManager: Error while retrieving uid for sender: %s", error->message); g_error_free (error); goto out; } session_id = get_session_id_for_pid (connection, pid, &error); if (session_id == NULL) { g_debug ("GdmManager: Error while retrieving session id for sender: %s", error->message); g_error_free (error); goto out; } if (out_session_id != NULL) { *out_session_id = g_strdup (session_id); } if (out_is_login_screen != NULL) { *out_is_login_screen = is_login_session (self, connection, session_id, &error); if (error != NULL) { g_debug ("GdmManager: Error while checking if sender is login screen: %s", error->message); g_error_free (error); goto out; } } if (!get_uid_for_session_id (connection, session_id, &session_uid, &error)) { g_debug ("GdmManager: Error while retrieving uid for session: %s", error->message); g_error_free (error); goto out; } if (out_uid != NULL) { *out_uid = caller_uid; } if (caller_uid != session_uid) { g_debug ("GdmManager: uid for sender and uid for session don't match"); goto out; } if (out_seat_id != NULL) { *out_seat_id = get_seat_id_for_session_id (connection, session_id, &error); if (error != NULL) { g_debug ("GdmManager: Error while retrieving seat id for session: %s", error->message); g_clear_error (&error); } } if (out_is_remote != NULL) { *out_is_remote = is_remote_session (self, connection, session_id, &error); if (error != NULL) { g_debug ("GdmManager: Error while retrieving remoteness for session: %s", error->message); g_clear_error (&error); } } display = gdm_display_store_find (self->priv->display_store, lookup_by_session_id, (gpointer) session_id); if (out_display != NULL) { *out_display = display; } out: g_free (session_id); } static gboolean switch_to_compatible_user_session (GdmManager *manager, GdmSession *session, gboolean fail_if_already_switched) { gboolean res; gboolean ret; const char *username; const char *seat_id; const char *ssid_to_activate; GdmSession *existing_session; ret = FALSE; username = gdm_session_get_username (session); seat_id = gdm_session_get_display_seat_id (session); if (!fail_if_already_switched) { session = NULL; } existing_session = find_session_for_user_on_seat (manager, username, seat_id, session); if (existing_session != NULL) { ssid_to_activate = gdm_session_get_session_id (existing_session); res = activate_session_id (manager, seat_id, ssid_to_activate); if (! res) { g_debug ("GdmManager: unable to activate session: %s", ssid_to_activate); goto out; } res = session_unlock (manager, ssid_to_activate); if (!res) { /* this isn't fatal */ g_debug ("GdmManager: unable to unlock session: %s", ssid_to_activate); } } else { goto out; } ret = TRUE; out: return ret; } static GdmDisplay * get_display_for_user_session (GdmSession *session) { return g_object_get_data (G_OBJECT (session), "gdm-display"); } static GdmSession * get_seed_session_for_display (GdmDisplay *display) { if (display == NULL) { return NULL; } return g_object_get_data (G_OBJECT (display), "gdm-seed-session"); } static gboolean gdm_manager_handle_open_session (GdmDBusManager *manager, GDBusMethodInvocation *invocation) { GdmManager *self = GDM_MANAGER (manager); const char *sender; GError *error = NULL; GDBusConnection *connection; GdmDisplay *display = NULL; GdmSession *session; const char *address; GPid pid = 0; uid_t uid = (uid_t) -1; uid_t allowed_user; g_debug ("GdmManager: trying to open new session"); sender = g_dbus_method_invocation_get_sender (invocation); connection = g_dbus_method_invocation_get_connection (invocation); get_display_and_details_for_bus_sender (self, connection, sender, &display, NULL, NULL, &pid, &uid, NULL, NULL); if (display == NULL) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED, _("No session available")); return TRUE; } session = get_seed_session_for_display (display); if (gdm_session_is_running (session)) { error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED, _("Can only be called before user is logged in")); return FALSE; } allowed_user = gdm_session_get_allowed_user (session); if (uid != allowed_user) { error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED, _("Caller not GDM")); return FALSE; } address = gdm_session_get_server_address (session); if (address == NULL) { g_dbus_method_invocation_return_gerror (invocation, error); g_error_free (error); return TRUE; } gdm_dbus_manager_complete_open_session (GDM_DBUS_MANAGER (manager), invocation, address); return TRUE; } static void close_transient_session (GdmManager *self, GdmSession *session) { GPid pid; pid = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (session), "caller-pid")); gdm_session_close (session); g_hash_table_remove (self->priv->transient_sessions, GUINT_TO_POINTER (pid)); } static void on_reauthentication_client_connected (GdmSession *session, GCredentials *credentials, GPid pid_of_client, GdmManager *self) { g_debug ("GdmManager: client connected to reauthentication server"); } static void on_reauthentication_client_disconnected (GdmSession *session, GCredentials *credentials, GPid pid_of_client, GdmManager *self) { g_debug ("GdmManger: client disconnected from reauthentication server"); close_transient_session (self, session); } static void on_reauthentication_client_rejected (GdmSession *session, GCredentials *credentials, GPid pid_of_client, GdmManager *self) { GPid pid; g_debug ("GdmManger: client with pid %ld rejected from reauthentication server", (long) pid_of_client); if (gdm_session_client_is_connected (session)) { /* we already have a client connected, ignore this rejected one */ return; } pid = (GPid) GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (session), "caller-pid")); if (pid != pid_of_client) { const char *session_id; char *client_session_id; /* rejected client isn't the process that started the * transient reauthentication session. If it's not even from the * same audit session, ignore it since it doesn't "own" the * reauthentication session */ client_session_id = get_session_id_for_pid (self->priv->connection, pid_of_client, NULL); session_id = g_object_get_data (G_OBJECT (session), "caller-session-id"); if (g_strcmp0 (session_id, client_session_id) != 0) { return; } } /* client was rejected, so clean up its session object */ close_transient_session (self, session); } static void on_reauthentication_cancelled (GdmSession *session, GdmManager *self) { g_debug ("GdmManager: client cancelled reauthentication request"); close_transient_session (self, session); } static void on_reauthentication_conversation_started (GdmSession *session, const char *service_name, GdmManager *self) { g_debug ("GdmManager: reauthentication service '%s' started", service_name); } static void on_reauthentication_conversation_stopped (GdmSession *session, const char *service_name, GdmManager *self) { g_debug ("GdmManager: reauthentication service '%s' stopped", service_name); } static void on_reauthentication_verification_complete (GdmSession *session, const char *service_name, GdmManager *self) { const char *session_id; session_id = g_object_get_data (G_OBJECT (session), "caller-session-id"); g_debug ("GdmManager: reauthenticated user in unmanaged session '%s' with service '%s'", session_id, service_name); session_unlock (self, session_id); close_transient_session (self, session); } static char * open_temporary_reauthentication_channel (GdmManager *self, char *seat_id, char *session_id, GPid pid, uid_t uid, gboolean is_remote) { GdmSession *session; char **environment; const char *display, *auth_file; const char *address; /* Note we're just using a minimal environment here rather than the * session's environment because the caller is unprivileged and the * associated worker will be privileged */ environment = g_get_environ (); display = ""; auth_file = "/dev/null"; session = gdm_session_new (GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE, uid, display, NULL, NULL, seat_id, auth_file, is_remote == FALSE, (const char * const *) environment); g_strfreev (environment); g_object_set_data_full (G_OBJECT (session), "caller-session-id", g_strdup (session_id), (GDestroyNotify) g_free); g_object_set_data (G_OBJECT (session), "caller-pid", GUINT_TO_POINTER (pid)); g_hash_table_insert (self->priv->transient_sessions, GINT_TO_POINTER (pid), session); g_signal_connect (session, "client-connected", G_CALLBACK (on_reauthentication_client_connected), self); g_signal_connect (session, "client-disconnected", G_CALLBACK (on_reauthentication_client_disconnected), self); g_signal_connect (session, "client-rejected", G_CALLBACK (on_reauthentication_client_rejected), self); g_signal_connect (session, "cancelled", G_CALLBACK (on_reauthentication_cancelled), self); g_signal_connect (session, "conversation-started", G_CALLBACK (on_reauthentication_conversation_started), self); g_signal_connect (session, "conversation-stopped", G_CALLBACK (on_reauthentication_conversation_stopped), self); g_signal_connect (session, "verification-complete", G_CALLBACK (on_reauthentication_verification_complete), self); address = gdm_session_get_server_address (session); return g_strdup (address); } static gboolean gdm_manager_handle_open_reauthentication_channel (GdmDBusManager *manager, GDBusMethodInvocation *invocation, const char *username) { GdmManager *self = GDM_MANAGER (manager); const char *sender; GdmDisplay *display = NULL; GdmSession *session; GDBusConnection *connection; char *seat_id = NULL; char *session_id = NULL; GPid pid = 0; uid_t uid = (uid_t) -1; gboolean is_login_screen = FALSE; gboolean is_remote = FALSE; g_debug ("GdmManager: trying to open reauthentication channel for user %s", username); sender = g_dbus_method_invocation_get_sender (invocation); connection = g_dbus_method_invocation_get_connection (invocation); get_display_and_details_for_bus_sender (self, connection, sender, &display, &seat_id, &session_id, &pid, &uid, &is_login_screen, &is_remote); if (is_login_screen) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED, "Login screen not allow to open reauthentication channel"); return TRUE; } if (session_id == NULL || pid == 0 || uid == (uid_t) -1) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED, _("No session available")); return TRUE; } session = get_seed_session_for_display (display); if (session != NULL && gdm_session_is_running (session)) { gdm_session_start_reauthentication (session, pid, uid); g_hash_table_insert (self->priv->open_reauthentication_requests, GINT_TO_POINTER (pid), invocation); } else { char *address; address = open_temporary_reauthentication_channel (self, seat_id, session_id, pid, uid, is_remote); gdm_dbus_manager_complete_open_reauthentication_channel (GDM_DBUS_MANAGER (manager), invocation, address); g_free (address); } return TRUE; } static void manager_interface_init (GdmDBusManagerIface *interface) { interface->handle_open_session = gdm_manager_handle_open_session; interface->handle_open_reauthentication_channel = gdm_manager_handle_open_reauthentication_channel; } static void set_up_greeter_session (GdmManager *manager, GdmDisplay *display) { char *allowed_user; struct passwd *passwd_entry; gdm_display_set_up_greeter_session (display, &allowed_user); if (!gdm_get_pwent_for_name (allowed_user, &passwd_entry)) { g_warning ("GdmManager: couldn't look up username %s", allowed_user); gdm_display_unmanage (display); gdm_display_finish (display); return; } create_seed_session_for_display (manager, display, passwd_entry->pw_uid); g_free (allowed_user); gdm_display_start_greeter_session (display); touch_ran_once_marker_file (manager); } static void on_display_status_changed (GdmDisplay *display, GParamSpec *arg1, GdmManager *manager) { int status; status = gdm_display_get_status (display); switch (status) { case GDM_DISPLAY_MANAGED: set_up_greeter_session (manager, display); break; case GDM_DISPLAY_FAILED: case GDM_DISPLAY_UNMANAGED: case GDM_DISPLAY_FINISHED: break; default: break; } } static void on_display_removed (GdmDisplayStore *display_store, const char *id, GdmManager *manager) { GdmDisplay *display; display = gdm_display_store_lookup (display_store, id); if (display != NULL) { g_dbus_object_manager_server_unexport (manager->priv->object_manager, id); g_signal_handlers_disconnect_by_func (display, G_CALLBACK (on_display_status_changed), manager); g_signal_emit (manager, signals[DISPLAY_REMOVED], 0, id); } } typedef struct { GdmManager *manager; GdmSession *session; char *service_name; guint idle_id; } StartUserSessionOperation; static void destroy_start_user_session_operation (StartUserSessionOperation *operation) { g_object_set_data (G_OBJECT (operation->session), "start-user-session-operation", NULL); g_object_unref (operation->session); g_free (operation->service_name); g_slice_free (StartUserSessionOperation, operation); } static void start_user_session (GdmManager *manager, StartUserSessionOperation *operation) { GdmDisplay *display; display = get_display_for_user_session (operation->session); if (display != NULL) { char *auth_file; const char *username; auth_file = NULL; username = gdm_session_get_username (operation->session); gdm_display_add_user_authorization (display, username, &auth_file, NULL); g_assert (auth_file != NULL); g_object_set (operation->session, "user-x11-authority-file", auth_file, NULL); g_free (auth_file); } gdm_session_start_session (operation->session, operation->service_name); destroy_start_user_session_operation (operation); } static gboolean on_start_user_session (StartUserSessionOperation *operation) { gboolean migrated; gboolean fail_if_already_switched = TRUE; GdmDisplay *display; g_debug ("GdmManager: start or jump to session"); /* If there's already a session running, jump to it. * If the only session running is the one we just opened, * start a session on it. */ migrated = switch_to_compatible_user_session (operation->manager, operation->session, fail_if_already_switched); g_debug ("GdmManager: migrated: %d", migrated); if (migrated) { /* We don't stop the manager here because when Xorg exits it switches to the VT it was started from. That interferes with fast user switching. */ gdm_session_reset (operation->session); destroy_start_user_session_operation (operation); goto out; } display = get_display_for_user_session (operation->session); if (gdm_session_get_display_mode (operation->session) == GDM_SESSION_DISPLAY_MODE_REUSE_VT) { /* In this case, the greeter's display is morphing into * the user session display. Kill the greeter on this session * and let the seed session follow the same display. */ gdm_display_stop_greeter_session (display); } else { uid_t allowed_uid; g_debug ("GdmManager: session has its display server, reusing our server for another login screen"); /* The seed session is going to follow the session worker * into the new display. Untie it from this display and * create a new seed session for us. */ allowed_uid = gdm_session_get_allowed_user (operation->session); g_object_set_data (G_OBJECT (display), "gdm-seed-session", NULL); g_object_set_data (G_OBJECT (operation->session), "gdm-display", NULL); create_seed_session_for_display (operation->manager, display, allowed_uid); } start_user_session (operation->manager, operation); out: return G_SOURCE_REMOVE; } static void queue_start_user_session (GdmManager *manager, GdmSession *session, const char *service_name) { StartUserSessionOperation *operation; operation = g_slice_new0 (StartUserSessionOperation); operation->manager = manager; operation->session = g_object_ref (session); operation->service_name = g_strdup (service_name); operation->idle_id = g_idle_add ((GSourceFunc) on_start_user_session, operation); g_object_set_data (G_OBJECT (session), "start-user-session-operation", operation); } static void start_user_session_if_ready (GdmManager *manager, GdmSession *session, const char *service_name) { gboolean start_when_ready; start_when_ready = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (session), "start-when-ready")); if (start_when_ready) { g_object_set_data (G_OBJECT (session), "waiting-to-start", GINT_TO_POINTER (FALSE)); queue_start_user_session (manager, session, service_name); } else { g_object_set_data (G_OBJECT (session), "waiting-to-start", GINT_TO_POINTER (TRUE)); } } static void on_session_opened (GdmSession *session, const char *service_name, const char *session_id, GdmManager *manager) { manager->priv->user_sessions = g_list_append (manager->priv->user_sessions, g_object_ref (session)); if (g_strcmp0 (service_name, "gdm-autologin") == 0 && !gdm_session_client_is_connected (session)) { /* If we're auto logging in then don't wait for the go-ahead from a greeter, * (since there is no greeter) */ g_object_set_data (G_OBJECT (session), "start-when-ready", GINT_TO_POINTER (TRUE)); } start_user_session_if_ready (manager, session, service_name); } static void on_session_started (GdmSession *session, const char *service_name, GPid pid, GdmManager *manager) { GdmDisplay *display; g_debug ("GdmManager: session started %d", pid); display = get_display_for_user_session (session); if (display != NULL) { GdmSlave *slave; const char *session_id; slave = gdm_display_get_slave (display); session_id = gdm_session_get_session_id (session); g_object_set (GDM_SLAVE (slave), "session-id", session_id, NULL); } } static void remove_user_session (GdmManager *manager, GdmSession *session) { GList *node; GdmDisplay *display; display = get_display_for_user_session (session); if (display != NULL) { gdm_display_unmanage (display); gdm_display_finish (display); } node = g_list_find (manager->priv->user_sessions, session); if (node != NULL) { manager->priv->user_sessions = g_list_delete_link (manager->priv->user_sessions, node); gdm_session_close (session); g_object_unref (session); } } static void on_user_session_exited (GdmSession *session, int code, GdmManager *manager) { g_debug ("GdmManager: session exited with status %d", code); remove_user_session (manager, session); } static void on_user_session_died (GdmSession *session, int signal_number, GdmManager *manager) { g_debug ("GdmManager: session died with signal %s", strsignal (signal_number)); remove_user_session (manager, session); } static char * query_ck_for_display_device (GdmManager *manager, GdmDisplay *display) { char *out; char *command; char *display_name = NULL; int status; gboolean res; GError *error; g_object_get (G_OBJECT (display), "x11-display-name", &display_name, NULL); error = NULL; command = g_strdup_printf (CONSOLEKIT_DIR "/ck-get-x11-display-device --display %s", display_name); g_free (display_name); g_debug ("GdmManager: Running helper %s", command); out = NULL; res = g_spawn_command_line_sync (command, &out, NULL, &status, &error); if (! res) { g_warning ("GdmManager: Could not run helper %s: %s", command, error->message); g_error_free (error); } else { out = g_strstrip (out); g_debug ("GdmManager: Got tty: '%s'", out); } g_free (command); return out; } static char * get_display_device (GdmManager *manager, GdmDisplay *display) { #ifdef WITH_SYSTEMD if (LOGIND_RUNNING()) { /* systemd finds the display device out on its own based on the display */ return NULL; } #endif return query_ck_for_display_device (manager, display); } static void on_session_reauthenticated (GdmSession *session, const char *service_name, GdmManager *manager) { gboolean fail_if_already_switched = FALSE; /* There should already be a session running, so jump to its * VT. In the event we're already on the right VT, (i.e. user * used an unlock screen instead of a user switched login screen), * then silently succeed and unlock the session. */ switch_to_compatible_user_session (manager, session, fail_if_already_switched); } static void on_session_client_ready_for_session_to_start (GdmSession *session, const char *service_name, gboolean client_is_ready, GdmManager *manager) { gboolean waiting_to_start_user_session; if (client_is_ready) { g_debug ("GdmManager: Will start session when ready"); } else { g_debug ("GdmManager: Will start session when ready and told"); } waiting_to_start_user_session = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (session), "waiting-to-start")); g_object_set_data (G_OBJECT (session), "start-when-ready", GINT_TO_POINTER (client_is_ready)); if (client_is_ready && waiting_to_start_user_session) { start_user_session_if_ready (manager, session, service_name); } } static void on_session_client_connected (GdmSession *session, GCredentials *credentials, GPid pid_of_client, GdmManager *manager) { GdmDisplay *display; char *username; int delay; gboolean enabled, display_is_local; g_debug ("GdmManager: client connected"); display = get_display_for_user_session (session); if (display == NULL) { return; } g_object_get (display, "is-local", &display_is_local, NULL); enabled = FALSE; gdm_display_get_timed_login_details (display, &enabled, &username, &delay, NULL); if (! enabled) { return; } if (delay > 0) { gdm_session_set_timed_login_details (session, username, delay); } g_free (username); } static void on_session_client_disconnected (GdmSession *session, GCredentials *credentials, GPid pid_of_client, GdmManager *manager) { GdmDisplay *display; gboolean display_is_local; g_debug ("GdmManager: client disconnected"); display = get_display_for_user_session (session); if (display == NULL) { return; } g_object_get (G_OBJECT (display), "is-local", &display_is_local, NULL); if ( ! display_is_local && gdm_session_is_running (session)) { gdm_display_unmanage (display); gdm_display_finish (display); } } typedef struct { GdmManager *manager; GdmSession *session; guint idle_id; } ResetSessionOperation; static void destroy_reset_session_operation (ResetSessionOperation *operation) { g_object_set_data (G_OBJECT (operation->session), "reset-session-operation", NULL); g_object_unref (operation->session); g_slice_free (ResetSessionOperation, operation); } static gboolean on_reset_session (ResetSessionOperation *operation) { gdm_session_reset (operation->session); destroy_reset_session_operation (operation); return G_SOURCE_REMOVE; } static void queue_session_reset (GdmManager *manager, GdmSession *session) { ResetSessionOperation *operation; operation = g_object_get_data (G_OBJECT (session), "reset-session-operation"); if (operation != NULL) { return; } operation = g_slice_new0 (ResetSessionOperation); operation->manager = manager; operation->session = g_object_ref (session); operation->idle_id = g_idle_add ((GSourceFunc) on_reset_session, operation); g_object_set_data (G_OBJECT (session), "reset-session-operation", operation); } static void on_session_cancelled (GdmSession *session, GdmManager *manager) { g_debug ("GdmManager: Session was cancelled"); queue_session_reset (manager, session); } static void on_session_conversation_started (GdmSession *session, const char *service_name, GdmManager *manager) { GdmDisplay *display; gboolean enabled; char *username; int delay; g_debug ("GdmManager: session conversation started for service %s", service_name); if (g_strcmp0 (service_name, "gdm-autologin") != 0) { return; } display = get_display_for_user_session (session); if (display == NULL) { g_debug ("GdmManager: conversation has no associated display"); return; } enabled = FALSE; gdm_display_get_timed_login_details (display, &enabled, &username, &delay, NULL); if (! enabled) { return; } if (delay == 0) { g_debug ("GdmManager: begin auto login for user '%s'", username); /* service_name will be "gdm-autologin" */ gdm_session_setup_for_user (session, service_name, username); } g_free (username); } static void on_session_conversation_stopped (GdmSession *session, const char *service_name, GdmManager *manager) { g_debug ("GdmManager: session conversation '%s' stopped", service_name); } static void on_session_reauthentication_started (GdmSession *session, int pid_of_caller, const char *address, GdmManager *manager) { GDBusMethodInvocation *invocation; gpointer source_tag; g_debug ("GdmManager: reauthentication started"); source_tag = GINT_TO_POINTER (pid_of_caller); invocation = g_hash_table_lookup (manager->priv->open_reauthentication_requests, source_tag); if (invocation != NULL) { g_hash_table_steal (manager->priv->open_reauthentication_requests, source_tag); gdm_dbus_manager_complete_open_reauthentication_channel (GDM_DBUS_MANAGER (manager), invocation, address); } } static void start_autologin_conversation_if_necessary (GdmManager *manager, GdmDisplay *display, GdmSession *session) { gboolean enabled; int delay = 0; gdm_display_get_timed_login_details (display, &enabled, NULL, &delay, NULL); if (delay == 0 && g_file_test (GDM_RAN_ONCE_MARKER_FILE, G_FILE_TEST_EXISTS)) { return; } if (!enabled) { return; } g_debug ("GdmManager: Starting automatic login conversation"); gdm_session_start_conversation (session, "gdm-autologin"); } static void touch_ran_once_marker_file (GdmManager *manager) { int fd; fd = g_creat (GDM_RAN_ONCE_MARKER_FILE, 0644); if (fd < 0 && errno != EEXIST) { g_warning ("could not create %s to mark run, this may cause auto login " "to repeat: %m", GDM_RAN_ONCE_MARKER_FILE); return; } fsync (fd); close (fd); } static void create_seed_session_for_display (GdmManager *manager, GdmDisplay *display, uid_t allowed_user) { GdmSession *session; gboolean display_is_local = FALSE; char *display_name = NULL; char *display_device = NULL; char *remote_hostname = NULL; char *display_auth_file = NULL; char *display_seat_id = NULL; char *display_id = NULL; g_object_get (G_OBJECT (display), "id", &display_id, "x11-display-name", &display_name, "is-local", &display_is_local, "remote-hostname", &remote_hostname, "x11-authority-file", &display_auth_file, "seat-id", &display_seat_id, NULL); display_device = get_display_device (manager, display); session = gdm_session_new (GDM_SESSION_VERIFICATION_MODE_LOGIN, allowed_user, display_name, remote_hostname, display_device, display_seat_id, display_auth_file, display_is_local, NULL); g_free (display_name); g_free (remote_hostname); g_free (display_auth_file); g_free (display_seat_id); g_signal_connect (session, "reauthentication-started", G_CALLBACK (on_session_reauthentication_started), manager); g_signal_connect (session, "reauthenticated", G_CALLBACK (on_session_reauthenticated), manager); g_signal_connect (session, "client-ready-for-session-to-start", G_CALLBACK (on_session_client_ready_for_session_to_start), manager); g_signal_connect (session, "client-connected", G_CALLBACK (on_session_client_connected), manager); g_signal_connect (session, "client-disconnected", G_CALLBACK (on_session_client_disconnected), manager); g_signal_connect (session, "cancelled", G_CALLBACK (on_session_cancelled), manager); g_signal_connect (session, "conversation-started", G_CALLBACK (on_session_conversation_started), manager); g_signal_connect (session, "conversation-stopped", G_CALLBACK (on_session_conversation_stopped), manager); g_signal_connect (session, "session-opened", G_CALLBACK (on_session_opened), manager); g_signal_connect (session, "session-started", G_CALLBACK (on_session_started), manager); g_signal_connect (session, "session-exited", G_CALLBACK (on_user_session_exited), manager); g_signal_connect (session, "session-died", G_CALLBACK (on_user_session_died), manager); g_object_set_data (G_OBJECT (session), "gdm-display", display); g_object_set_data_full (G_OBJECT (display), "gdm-seed-session", g_object_ref (session), (GDestroyNotify) g_object_unref); start_autologin_conversation_if_necessary (manager, display, session); } static void on_display_added (GdmDisplayStore *display_store, const char *id, GdmManager *manager) { GdmDisplay *display; display = gdm_display_store_lookup (display_store, id); if (display != NULL) { g_dbus_object_manager_server_export (manager->priv->object_manager, gdm_display_get_object_skeleton (display)); g_signal_connect (display, "notify::status", G_CALLBACK (on_display_status_changed), manager); g_signal_emit (manager, signals[DISPLAY_ADDED], 0, id); } } GQuark gdm_manager_error_quark (void) { static GQuark ret = 0; if (ret == 0) { ret = g_quark_from_static_string ("gdm_manager_error"); } return ret; } static gboolean listify_display_ids (const char *id, GdmDisplay *display, GPtrArray **array) { g_ptr_array_add (*array, g_strdup (id)); /* return FALSE to continue */ return FALSE; } /* Example: dbus-send --system --dest=org.gnome.DisplayManager \ --type=method_call --print-reply --reply-timeout=2000 \ /org/gnome/DisplayManager/Displays \ org.freedesktop.ObjectManager.GetAll */ gboolean gdm_manager_get_displays (GdmManager *manager, GPtrArray **displays, GError **error) { g_return_val_if_fail (GDM_IS_MANAGER (manager), FALSE); if (displays == NULL) { return FALSE; } *displays = g_ptr_array_new (); gdm_display_store_foreach (manager->priv->display_store, (GdmDisplayStoreFunc)listify_display_ids, displays); return TRUE; } void gdm_manager_stop (GdmManager *manager) { g_debug ("GdmManager: GDM stopping"); if (manager->priv->local_factory != NULL) { gdm_display_factory_stop (GDM_DISPLAY_FACTORY (manager->priv->local_factory)); } #ifdef HAVE_LIBXDMCP if (manager->priv->xdmcp_factory != NULL) { gdm_display_factory_stop (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory)); } #endif manager->priv->started = FALSE; } void gdm_manager_start (GdmManager *manager) { g_debug ("GdmManager: GDM starting to manage displays"); if (! manager->priv->wait_for_go && (!manager->priv->xdmcp_enabled || manager->priv->show_local_greeter)) { gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->local_factory)); } #ifdef HAVE_LIBXDMCP /* Accept remote connections */ if (manager->priv->xdmcp_enabled && ! manager->priv->wait_for_go) { if (manager->priv->xdmcp_factory != NULL) { g_debug ("GdmManager: Accepting XDMCP connections..."); gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory)); } } #endif manager->priv->started = TRUE; } void gdm_manager_set_wait_for_go (GdmManager *manager, gboolean wait_for_go) { if (manager->priv->wait_for_go != wait_for_go) { manager->priv->wait_for_go = wait_for_go; if (! wait_for_go) { /* we got a go */ if (!manager->priv->xdmcp_enabled || manager->priv->show_local_greeter) { gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->local_factory)); } #ifdef HAVE_LIBXDMCP if (manager->priv->xdmcp_enabled && manager->priv->xdmcp_factory != NULL) { g_debug ("GdmManager: Accepting XDMCP connections..."); gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory)); } #endif } } } static gboolean register_manager (GdmManager *manager) { GError *error = NULL; GDBusObjectManagerServer *object_server; error = NULL; manager->priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); if (manager->priv->connection == NULL) { g_critical ("error getting system bus: %s", error->message); g_error_free (error); exit (1); } object_server = g_dbus_object_manager_server_new (GDM_MANAGER_DISPLAYS_PATH); g_dbus_object_manager_server_set_connection (object_server, manager->priv->connection); manager->priv->object_manager = object_server; if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (manager), manager->priv->connection, GDM_MANAGER_PATH, &error)) { g_critical ("error exporting interface to %s: %s", GDM_MANAGER_PATH, error->message); g_error_free (error); exit (1); } return TRUE; } void gdm_manager_set_xdmcp_enabled (GdmManager *manager, gboolean enabled) { g_return_if_fail (GDM_IS_MANAGER (manager)); if (manager->priv->xdmcp_enabled != enabled) { manager->priv->xdmcp_enabled = enabled; #ifdef HAVE_LIBXDMCP if (manager->priv->xdmcp_enabled) { manager->priv->xdmcp_factory = gdm_xdmcp_display_factory_new (manager->priv->display_store); if (manager->priv->started) { gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory)); } } else { if (manager->priv->started) { gdm_display_factory_stop (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory)); } g_object_unref (manager->priv->xdmcp_factory); manager->priv->xdmcp_factory = NULL; } #endif } } void gdm_manager_set_show_local_greeter (GdmManager *manager, gboolean show_local_greeter) { g_return_if_fail (GDM_IS_MANAGER (manager)); manager->priv->show_local_greeter = show_local_greeter; } static void gdm_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GdmManager *self; self = GDM_MANAGER (object); switch (prop_id) { case PROP_XDMCP_ENABLED: gdm_manager_set_xdmcp_enabled (self, g_value_get_boolean (value)); break; case PROP_SHOW_LOCAL_GREETER: gdm_manager_set_show_local_greeter (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gdm_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GdmManager *self; self = GDM_MANAGER (object); switch (prop_id) { case PROP_XDMCP_ENABLED: g_value_set_boolean (value, self->priv->xdmcp_enabled); break; case PROP_SHOW_LOCAL_GREETER: g_value_set_boolean (value, self->priv->show_local_greeter); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * gdm_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GdmManager *manager; manager = GDM_MANAGER (G_OBJECT_CLASS (gdm_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); gdm_dbus_manager_set_version (GDM_DBUS_MANAGER (manager), PACKAGE_VERSION); manager->priv->local_factory = gdm_local_display_factory_new (manager->priv->display_store); #ifdef HAVE_LIBXDMCP if (manager->priv->xdmcp_enabled) { manager->priv->xdmcp_factory = gdm_xdmcp_display_factory_new (manager->priv->display_store); } #endif return G_OBJECT (manager); } static void gdm_manager_class_init (GdmManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = gdm_manager_get_property; object_class->set_property = gdm_manager_set_property; object_class->constructor = gdm_manager_constructor; object_class->dispose = gdm_manager_dispose; signals [DISPLAY_ADDED] = g_signal_new ("display-added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GdmManagerClass, display_added), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); signals [DISPLAY_REMOVED] = g_signal_new ("display-removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GdmManagerClass, display_removed), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); g_object_class_install_property (object_class, PROP_XDMCP_ENABLED, g_param_spec_boolean ("xdmcp-enabled", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (GdmManagerPrivate)); } static void gdm_manager_init (GdmManager *manager) { manager->priv = GDM_MANAGER_GET_PRIVATE (manager); manager->priv->display_store = gdm_display_store_new (); manager->priv->user_sessions = NULL; manager->priv->open_reauthentication_requests = g_hash_table_new_full (NULL, NULL, (GDestroyNotify) NULL, (GDestroyNotify) g_object_unref); manager->priv->transient_sessions = g_hash_table_new_full (NULL, NULL, (GDestroyNotify) NULL, (GDestroyNotify) g_object_unref); g_signal_connect (G_OBJECT (manager->priv->display_store), "display-added", G_CALLBACK (on_display_added), manager); g_signal_connect (G_OBJECT (manager->priv->display_store), "display-removed", G_CALLBACK (on_display_removed), manager); } static void unexport_display (const char *id, GdmDisplay *display, GdmManager *manager) { if (!g_dbus_connection_is_closed (manager->priv->connection)) g_dbus_object_manager_server_unexport (manager->priv->object_manager, id); } static void finish_display (const char *id, GdmDisplay *display, GdmManager *manager) { if (gdm_display_get_status (display) == GDM_DISPLAY_MANAGED) gdm_display_unmanage (display); gdm_display_finish (display); } static void gdm_manager_dispose (GObject *object) { GdmManager *manager; g_return_if_fail (object != NULL); g_return_if_fail (GDM_IS_MANAGER (object)); manager = GDM_MANAGER (object); g_return_if_fail (manager->priv != NULL); #ifdef HAVE_LIBXDMCP g_clear_object (&manager->priv->xdmcp_factory); #endif g_clear_object (&manager->priv->local_factory); g_hash_table_unref (manager->priv->open_reauthentication_requests); g_hash_table_unref (manager->priv->transient_sessions); g_list_free_full (manager->priv->user_sessions, (GDestroyNotify) g_object_unref); manager->priv->user_sessions = NULL; g_signal_handlers_disconnect_by_func (G_OBJECT (manager->priv->display_store), G_CALLBACK (on_display_added), manager); g_signal_handlers_disconnect_by_func (G_OBJECT (manager->priv->display_store), G_CALLBACK (on_display_removed), manager); if (!g_dbus_connection_is_closed (manager->priv->connection)) { gdm_display_store_foreach (manager->priv->display_store, (GdmDisplayStoreFunc)unexport_display, manager); g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (manager)); } gdm_display_store_foreach (manager->priv->display_store, (GdmDisplayStoreFunc) finish_display, manager); gdm_display_store_clear (manager->priv->display_store); g_dbus_object_manager_server_set_connection (manager->priv->object_manager, NULL); g_clear_object (&manager->priv->connection); g_clear_object (&manager->priv->object_manager); g_object_unref (manager->priv->display_store); G_OBJECT_CLASS (gdm_manager_parent_class)->dispose (object); } GdmManager * gdm_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { gboolean res; manager_object = g_object_new (GDM_TYPE_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); res = register_manager (manager_object); if (! res) { g_object_unref (manager_object); return NULL; } } return GDM_MANAGER (manager_object); }