1
0
Fork 0
gdm3/daemon/gdm-display.c
Daniel Baumann 83b37a3d94
Adding upstream version 48.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 19:45:29 +02:00

1942 lines
68 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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 <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#ifdef ENABLE_X11_SUPPORT
#include <xcb/xcb.h>
#include <X11/Xlib.h>
#endif
#include "gdm-common.h"
#include "gdm-display.h"
#include "gdm-display-glue.h"
#include "gdm-display-access-file.h"
#include "gdm-launch-environment.h"
#include "gdm-remote-display.h"
#include "gdm-settings-direct.h"
#include "gdm-settings-keys.h"
#include "gdm-launch-environment.h"
#include "gdm-dbus-util.h"
#define GNOME_SESSION_SESSIONS_PATH DATADIR "/gnome-session/sessions"
typedef struct _GdmDisplayPrivate
{
GObject parent;
char *id;
char *seat_id;
char *session_id;
char *session_class;
char *session_type;
char *remote_hostname;
int x11_display_number;
char *x11_display_name;
int status;
time_t creation_time;
char *x11_cookie;
gsize x11_cookie_size;
GdmDisplayAccessFile *access_file;
guint finish_idle_id;
#ifdef ENABLE_X11_SUPPORT
xcb_connection_t *xcb_connection;
int xcb_screen_number;
#endif
GDBusConnection *connection;
GdmDisplayAccessFile *user_access_file;
GdmDBusDisplay *display_skeleton;
GDBusObjectSkeleton *object_skeleton;
GDBusProxy *accountsservice_proxy;
/* this spawns and controls the greeter session */
GdmLaunchEnvironment *launch_environment;
guint is_local : 1;
guint is_initial : 1;
guint allow_timed_login : 1;
guint have_existing_user_accounts : 1;
guint doing_initial_setup : 1;
guint session_registered : 1;
GStrv supported_session_types;
} GdmDisplayPrivate;
enum {
PROP_0,
PROP_ID,
PROP_STATUS,
PROP_SEAT_ID,
PROP_SESSION_ID,
PROP_SESSION_CLASS,
PROP_SESSION_TYPE,
PROP_REMOTE_HOSTNAME,
PROP_X11_DISPLAY_NUMBER,
PROP_X11_DISPLAY_NAME,
PROP_X11_COOKIE,
PROP_X11_AUTHORITY_FILE,
PROP_IS_CONNECTED,
PROP_IS_LOCAL,
PROP_LAUNCH_ENVIRONMENT,
PROP_IS_INITIAL,
PROP_ALLOW_TIMED_LOGIN,
PROP_HAVE_EXISTING_USER_ACCOUNTS,
PROP_DOING_INITIAL_SETUP,
PROP_SESSION_REGISTERED,
PROP_SUPPORTED_SESSION_TYPES,
};
static void gdm_display_class_init (GdmDisplayClass *klass);
static void gdm_display_init (GdmDisplay *self);
static void gdm_display_finalize (GObject *object);
static void queue_finish (GdmDisplay *self);
static void _gdm_display_set_status (GdmDisplay *self,
int status);
static gboolean wants_initial_setup (GdmDisplay *self);
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GdmDisplay, gdm_display, G_TYPE_OBJECT)
GQuark
gdm_display_error_quark (void)
{
static GQuark ret = 0;
if (ret == 0) {
ret = g_quark_from_static_string ("gdm_display_error");
}
return ret;
}
time_t
gdm_display_get_creation_time (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), 0);
priv = gdm_display_get_instance_private (self);
return priv->creation_time;
}
int
gdm_display_get_status (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), 0);
priv = gdm_display_get_instance_private (self);
return priv->status;
}
const char *
gdm_display_get_session_id (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), NULL);
priv = gdm_display_get_instance_private (self);
return priv->session_id;
}
static GdmDisplayAccessFile *
_create_access_file_for_user (GdmDisplay *self,
const char *username,
GError **error)
{
GdmDisplayAccessFile *access_file;
access_file = gdm_display_access_file_new (username);
if (!gdm_display_access_file_open (access_file, error)) {
return NULL;
}
return access_file;
}
gboolean
gdm_display_create_authority (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
g_autoptr(GdmDisplayAccessFile) access_file = NULL;
g_autoptr(GError) error = NULL;
gboolean res;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
priv = gdm_display_get_instance_private (self);
g_return_val_if_fail (priv->access_file == NULL, FALSE);
access_file = _create_access_file_for_user (self, GDM_USERNAME, &error);
if (access_file == NULL) {
g_critical ("could not create display access file: %s", error->message);
return FALSE;
}
g_free (priv->x11_cookie);
priv->x11_cookie = NULL;
res = gdm_display_access_file_add_display (access_file,
self,
&priv->x11_cookie,
&priv->x11_cookie_size,
&error);
if (! res) {
g_critical ("could not add display to access file: %s", error->message);
gdm_display_access_file_close (access_file);
return FALSE;
}
priv->access_file = g_steal_pointer (&access_file);
return TRUE;
}
#ifdef ENABLE_X11_SUPPORT
static void
setup_xhost_auth (XHostAddress *host_entries)
{
host_entries[0].family = FamilyServerInterpreted;
host_entries[0].address = "localuser\0root";
host_entries[0].length = sizeof ("localuser\0root");
host_entries[1].family = FamilyServerInterpreted;
host_entries[1].address = "localuser\0" GDM_USERNAME;
host_entries[1].length = sizeof ("localuser\0" GDM_USERNAME);
host_entries[2].family = FamilyServerInterpreted;
host_entries[2].address = "localuser\0gnome-initial-setup";
host_entries[2].length = sizeof ("localuser\0gnome-initial-setup");
}
#endif
gboolean
gdm_display_add_user_authorization (GdmDisplay *self,
const char *username,
char **filename,
GError **error)
{
#ifdef ENABLE_X11_SUPPORT
GdmDisplayPrivate *priv;
g_autoptr(GdmDisplayAccessFile) access_file = NULL;
g_autoptr(GError) access_file_error = NULL;
gboolean res;
int i;
XHostAddress host_entries[3];
xcb_void_cookie_t cookies[3];
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
g_return_val_if_fail (username != NULL, FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: Adding authorization for user:%s on display %s", username, priv->x11_display_name);
if (priv->user_access_file != NULL) {
g_set_error (error,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"user access already assigned");
return FALSE;
}
g_debug ("GdmDisplay: Adding user authorization for %s", username);
access_file = _create_access_file_for_user (self,
username,
&access_file_error);
if (access_file == NULL) {
g_propagate_error (error, g_steal_pointer (&access_file_error));
return FALSE;
}
res = gdm_display_access_file_add_display_with_cookie (access_file,
self,
priv->x11_cookie,
priv->x11_cookie_size,
&access_file_error);
if (! res) {
g_debug ("GdmDisplay: Unable to add user authorization for %s: %s",
username,
access_file_error->message);
g_propagate_error (error, g_steal_pointer (&access_file_error));
gdm_display_access_file_close (access_file);
return FALSE;
}
*filename = gdm_display_access_file_get_path (access_file);
priv->user_access_file = g_steal_pointer (&access_file);
g_debug ("GdmDisplay: Added user authorization for %s: %s", username, *filename);
/* Remove access for the programs run by greeter now that the
* user session is starting.
*/
setup_xhost_auth (host_entries);
for (i = 0; i < G_N_ELEMENTS (host_entries); i++) {
cookies[i] = xcb_change_hosts_checked (priv->xcb_connection,
XCB_HOST_MODE_DELETE,
host_entries[i].family,
host_entries[i].length,
(uint8_t *) host_entries[i].address);
}
for (i = 0; i < G_N_ELEMENTS (cookies); i++) {
xcb_generic_error_t *xcb_error;
xcb_error = xcb_request_check (priv->xcb_connection, cookies[i]);
if (xcb_error != NULL) {
g_warning ("Failed to remove greeter program access to the display. Trying to proceed.");
free (xcb_error);
}
}
return TRUE;
#else
return FALSE;
#endif
}
gboolean
gdm_display_remove_user_authorization (GdmDisplay *self,
const char *username,
GError **error)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
g_return_val_if_fail (username != NULL, FALSE);
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: Removing authorization for user:%s on display %s", username, priv->x11_display_name);
gdm_display_access_file_close (priv->user_access_file);
return TRUE;
}
gboolean
gdm_display_get_x11_cookie (GdmDisplay *self,
const char **x11_cookie,
gsize *x11_cookie_size,
GError **error)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
priv = gdm_display_get_instance_private (self);
if (x11_cookie != NULL) {
*x11_cookie = priv->x11_cookie;
}
if (x11_cookie_size != NULL) {
*x11_cookie_size = priv->x11_cookie_size;
}
return TRUE;
}
gboolean
gdm_display_get_x11_authority_file (GdmDisplay *self,
char **filename,
GError **error)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
priv = gdm_display_get_instance_private (self);
if (priv->access_file != NULL) {
*filename = gdm_display_access_file_get_path (priv->access_file);
} else {
*filename = NULL;
}
return TRUE;
}
gboolean
gdm_display_get_remote_hostname (GdmDisplay *self,
char **hostname,
GError **error)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
priv = gdm_display_get_instance_private (self);
if (hostname != NULL) {
*hostname = g_strdup (priv->remote_hostname);
}
return TRUE;
}
gboolean
gdm_display_get_x11_display_number (GdmDisplay *self,
int *number,
GError **error)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
priv = gdm_display_get_instance_private (self);
if (number != NULL) {
*number = priv->x11_display_number;
}
return TRUE;
}
gboolean
gdm_display_get_seat_id (GdmDisplay *self,
char **seat_id,
GError **error)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
priv = gdm_display_get_instance_private (self);
if (seat_id != NULL) {
*seat_id = g_strdup (priv->seat_id);
}
return TRUE;
}
gboolean
gdm_display_is_initial (GdmDisplay *self,
gboolean *is_initial,
GError **error)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
priv = gdm_display_get_instance_private (self);
if (is_initial != NULL) {
*is_initial = priv->is_initial;
}
return TRUE;
}
static gboolean
finish_idle (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
priv->finish_idle_id = 0;
/* finish may end up finalizing object */
gdm_display_finish (self);
return FALSE;
}
static void
queue_finish (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
if (priv->finish_idle_id == 0) {
priv->finish_idle_id = g_idle_add ((GSourceFunc)finish_idle, self);
}
}
static void
_gdm_display_set_status (GdmDisplay *self,
int status)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
if (status != priv->status) {
priv->status = status;
g_object_notify (G_OBJECT (self), "status");
}
}
static gboolean
gdm_display_real_prepare (GdmDisplay *self)
{
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
g_debug ("GdmDisplay: prepare display");
_gdm_display_set_status (self, GDM_DISPLAY_PREPARED);
return TRUE;
}
static gboolean
look_for_existing_users_sync (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
g_autoptr(GError) error = NULL;
g_autoptr(GVariant) call_result = NULL;
g_autoptr(GVariant) user_list = NULL;
priv = gdm_display_get_instance_private (self);
priv->accountsservice_proxy = g_dbus_proxy_new_sync (priv->connection,
0, NULL,
"org.freedesktop.Accounts",
"/org/freedesktop/Accounts",
"org.freedesktop.Accounts",
NULL,
&error);
if (!priv->accountsservice_proxy) {
g_critical ("Failed to contact accountsservice: %s", error->message);
return FALSE;
}
call_result = g_dbus_proxy_call_sync (priv->accountsservice_proxy,
"ListCachedUsers",
NULL,
0,
-1,
NULL,
&error);
if (!call_result) {
g_critical ("Failed to list cached users: %s", error->message);
return FALSE;
}
g_variant_get (call_result, "(@ao)", &user_list);
priv->have_existing_user_accounts = g_variant_n_children (user_list) > 0;
return TRUE;
}
gboolean
gdm_display_prepare (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
gboolean ret;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: Preparing display: %s", priv->id);
/* FIXME: we should probably do this in a more global place,
* asynchronously
*/
if (!look_for_existing_users_sync (self)) {
exit (EXIT_FAILURE);
}
priv->doing_initial_setup = wants_initial_setup (self);
g_object_ref (self);
ret = GDM_DISPLAY_GET_CLASS (self)->prepare (self);
g_object_unref (self);
return ret;
}
gboolean
gdm_display_manage (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
gboolean res;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: Managing display: %s", priv->id);
/* If not explicitly prepared, do it now */
if (priv->status == GDM_DISPLAY_UNMANAGED) {
res = gdm_display_prepare (self);
if (! res) {
return FALSE;
}
}
if (g_strcmp0 (priv->session_class, "greeter") == 0) {
if (GDM_DISPLAY_GET_CLASS (self)->manage != NULL) {
GDM_DISPLAY_GET_CLASS (self)->manage (self);
}
}
return TRUE;
}
gboolean
gdm_display_finish (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
priv = gdm_display_get_instance_private (self);
g_clear_handle_id (&priv->finish_idle_id, g_source_remove);
_gdm_display_set_status (self, GDM_DISPLAY_FINISHED);
g_debug ("GdmDisplay: finish display");
return TRUE;
}
static void
gdm_display_disconnect (GdmDisplay *self)
{
#ifdef ENABLE_X11_SUPPORT
GdmDisplayPrivate *priv;
/* These 3 bits are reserved/unused by the X protocol */
guint32 unused_bits = 0b11100000000000000000000000000000;
XID highest_client, client;
guint32 client_increment;
const xcb_setup_t *setup;
priv = gdm_display_get_instance_private (self);
if (priv->xcb_connection == NULL) {
return;
}
setup = xcb_get_setup (priv->xcb_connection);
/* resource_id_mask is the bits given to each client for
* addressing resources */
highest_client = (XID) ~unused_bits & ~setup->resource_id_mask;
client_increment = setup->resource_id_mask + 1;
/* Kill every client but ourselves, then close our own connection
*/
for (client = 0;
client <= highest_client;
client += client_increment) {
if (client != setup->resource_id_base)
xcb_kill_client (priv->xcb_connection, client);
}
xcb_flush (priv->xcb_connection);
g_clear_pointer (&priv->xcb_connection, xcb_disconnect);
#endif
}
gboolean
gdm_display_unmanage (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
priv = gdm_display_get_instance_private (self);
gdm_display_disconnect (self);
if (priv->user_access_file != NULL) {
gdm_display_access_file_close (priv->user_access_file);
g_object_unref (priv->user_access_file);
priv->user_access_file = NULL;
}
if (priv->access_file != NULL) {
gdm_display_access_file_close (priv->access_file);
g_object_unref (priv->access_file);
priv->access_file = NULL;
}
if (!priv->session_registered) {
g_warning ("GdmDisplay: Session never registered, failing");
_gdm_display_set_status (self, GDM_DISPLAY_FAILED);
} else {
_gdm_display_set_status (self, GDM_DISPLAY_UNMANAGED);
}
return TRUE;
}
gboolean
gdm_display_get_id (GdmDisplay *self,
char **id,
GError **error)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
priv = gdm_display_get_instance_private (self);
if (id != NULL) {
*id = g_strdup (priv->id);
}
return TRUE;
}
gboolean
gdm_display_get_x11_display_name (GdmDisplay *self,
char **x11_display,
GError **error)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
priv = gdm_display_get_instance_private (self);
if (x11_display != NULL) {
*x11_display = g_strdup (priv->x11_display_name);
}
return TRUE;
}
gboolean
gdm_display_is_local (GdmDisplay *self,
gboolean *local,
GError **error)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
priv = gdm_display_get_instance_private (self);
if (local != NULL) {
*local = priv->is_local;
}
return TRUE;
}
static void
_gdm_display_set_id (GdmDisplay *self,
const char *id)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: id: %s", id);
g_free (priv->id);
priv->id = g_strdup (id);
}
static void
_gdm_display_set_seat_id (GdmDisplay *self,
const char *seat_id)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: seat id: %s", seat_id);
g_free (priv->seat_id);
priv->seat_id = g_strdup (seat_id);
}
static void
_gdm_display_set_session_id (GdmDisplay *self,
const char *session_id)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: session id: %s", session_id);
g_free (priv->session_id);
priv->session_id = g_strdup (session_id);
}
static void
_gdm_display_set_session_class (GdmDisplay *self,
const char *session_class)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: session class: %s", session_class);
g_free (priv->session_class);
priv->session_class = g_strdup (session_class);
}
static void
_gdm_display_set_session_type (GdmDisplay *self,
const char *session_type)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: session type: %s", session_type);
g_free (priv->session_type);
priv->session_type = g_strdup (session_type);
}
static void
_gdm_display_set_remote_hostname (GdmDisplay *self,
const char *hostname)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
g_free (priv->remote_hostname);
priv->remote_hostname = g_strdup (hostname);
}
static void
_gdm_display_set_x11_display_number (GdmDisplay *self,
int num)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
priv->x11_display_number = num;
}
static void
_gdm_display_set_x11_display_name (GdmDisplay *self,
const char *x11_display)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
g_free (priv->x11_display_name);
priv->x11_display_name = g_strdup (x11_display);
}
static void
_gdm_display_set_x11_cookie (GdmDisplay *self,
const char *x11_cookie)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
g_free (priv->x11_cookie);
priv->x11_cookie = g_strdup (x11_cookie);
}
static void
_gdm_display_set_is_local (GdmDisplay *self,
gboolean is_local)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: local: %s", is_local? "yes" : "no");
priv->is_local = is_local;
}
static void
_gdm_display_set_session_registered (GdmDisplay *self,
gboolean registered)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: session registered: %s", registered? "yes" : "no");
priv->session_registered = registered;
}
static void
_gdm_display_set_launch_environment (GdmDisplay *self,
GdmLaunchEnvironment *launch_environment)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
g_clear_object (&priv->launch_environment);
priv->launch_environment = g_object_ref (launch_environment);
}
static void
_gdm_display_set_is_initial (GdmDisplay *self,
gboolean initial)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: initial: %s", initial? "yes" : "no");
priv->is_initial = initial;
}
static void
_gdm_display_set_allow_timed_login (GdmDisplay *self,
gboolean allow_timed_login)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: allow timed login: %s", allow_timed_login? "yes" : "no");
priv->allow_timed_login = allow_timed_login;
}
static void
_gdm_display_set_supported_session_types (GdmDisplay *self,
const char * const *supported_session_types)
{
GdmDisplayPrivate *priv;
g_autofree char *supported_session_types_string = NULL;
if (supported_session_types != NULL)
supported_session_types_string = g_strjoinv (":", (GStrv) supported_session_types);
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: supported session types: %s", supported_session_types_string);
g_strfreev (priv->supported_session_types);
priv->supported_session_types = g_strdupv ((GStrv) supported_session_types);
}
static void
gdm_display_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdmDisplay *self;
self = GDM_DISPLAY (object);
switch (prop_id) {
case PROP_ID:
_gdm_display_set_id (self, g_value_get_string (value));
break;
case PROP_STATUS:
_gdm_display_set_status (self, g_value_get_int (value));
break;
case PROP_SEAT_ID:
_gdm_display_set_seat_id (self, g_value_get_string (value));
break;
case PROP_SESSION_ID:
_gdm_display_set_session_id (self, g_value_get_string (value));
break;
case PROP_SESSION_CLASS:
_gdm_display_set_session_class (self, g_value_get_string (value));
break;
case PROP_SESSION_TYPE:
_gdm_display_set_session_type (self, g_value_get_string (value));
break;
case PROP_REMOTE_HOSTNAME:
_gdm_display_set_remote_hostname (self, g_value_get_string (value));
break;
case PROP_X11_DISPLAY_NUMBER:
_gdm_display_set_x11_display_number (self, g_value_get_int (value));
break;
case PROP_X11_DISPLAY_NAME:
_gdm_display_set_x11_display_name (self, g_value_get_string (value));
break;
case PROP_X11_COOKIE:
_gdm_display_set_x11_cookie (self, g_value_get_string (value));
break;
case PROP_IS_LOCAL:
_gdm_display_set_is_local (self, g_value_get_boolean (value));
break;
case PROP_ALLOW_TIMED_LOGIN:
_gdm_display_set_allow_timed_login (self, g_value_get_boolean (value));
break;
case PROP_LAUNCH_ENVIRONMENT:
_gdm_display_set_launch_environment (self, g_value_get_object (value));
break;
case PROP_IS_INITIAL:
_gdm_display_set_is_initial (self, g_value_get_boolean (value));
break;
case PROP_SESSION_REGISTERED:
_gdm_display_set_session_registered (self, g_value_get_boolean (value));
break;
case PROP_SUPPORTED_SESSION_TYPES:
_gdm_display_set_supported_session_types (self, g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_display_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdmDisplay *self;
GdmDisplayPrivate *priv;
self = GDM_DISPLAY (object);
priv = gdm_display_get_instance_private (self);
switch (prop_id) {
case PROP_ID:
g_value_set_string (value, priv->id);
break;
case PROP_STATUS:
g_value_set_int (value, priv->status);
break;
case PROP_SEAT_ID:
g_value_set_string (value, priv->seat_id);
break;
case PROP_SESSION_ID:
g_value_set_string (value, priv->session_id);
break;
case PROP_SESSION_CLASS:
g_value_set_string (value, priv->session_class);
break;
case PROP_SESSION_TYPE:
g_value_set_string (value, priv->session_type);
break;
case PROP_REMOTE_HOSTNAME:
g_value_set_string (value, priv->remote_hostname);
break;
case PROP_X11_DISPLAY_NUMBER:
g_value_set_int (value, priv->x11_display_number);
break;
case PROP_X11_DISPLAY_NAME:
g_value_set_string (value, priv->x11_display_name);
break;
case PROP_X11_COOKIE:
g_value_set_string (value, priv->x11_cookie);
break;
case PROP_X11_AUTHORITY_FILE:
g_value_take_string (value,
priv->access_file?
gdm_display_access_file_get_path (priv->access_file) : NULL);
break;
case PROP_IS_LOCAL:
g_value_set_boolean (value, priv->is_local);
break;
case PROP_IS_CONNECTED:
#ifdef ENABLE_X11_SUPPORT
g_value_set_boolean (value, priv->xcb_connection != NULL);
#else
g_value_set_boolean (value, FALSE);
#endif
break;
case PROP_LAUNCH_ENVIRONMENT:
g_value_set_object (value, priv->launch_environment);
break;
case PROP_IS_INITIAL:
g_value_set_boolean (value, priv->is_initial);
break;
case PROP_HAVE_EXISTING_USER_ACCOUNTS:
g_value_set_boolean (value, priv->have_existing_user_accounts);
break;
case PROP_DOING_INITIAL_SETUP:
g_value_set_boolean (value, priv->doing_initial_setup);
break;
case PROP_SESSION_REGISTERED:
g_value_set_boolean (value, priv->session_registered);
break;
case PROP_ALLOW_TIMED_LOGIN:
g_value_set_boolean (value, priv->allow_timed_login);
break;
case PROP_SUPPORTED_SESSION_TYPES:
g_value_set_boxed (value, priv->supported_session_types);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
handle_get_id (GdmDBusDisplay *skeleton,
GDBusMethodInvocation *invocation,
GdmDisplay *self)
{
g_autofree char *id = NULL;
gdm_display_get_id (self, &id, NULL);
gdm_dbus_display_complete_get_id (skeleton, invocation, id);
return TRUE;
}
static gboolean
handle_get_remote_hostname (GdmDBusDisplay *skeleton,
GDBusMethodInvocation *invocation,
GdmDisplay *self)
{
g_autofree char *hostname = NULL;
gdm_display_get_remote_hostname (self, &hostname, NULL);
gdm_dbus_display_complete_get_remote_hostname (skeleton,
invocation,
hostname ? hostname : "");
return TRUE;
}
static gboolean
handle_get_seat_id (GdmDBusDisplay *skeleton,
GDBusMethodInvocation *invocation,
GdmDisplay *self)
{
g_autofree char *seat_id = NULL;
gdm_display_get_seat_id (self, &seat_id, NULL);
if (seat_id == NULL) {
seat_id = g_strdup ("");
}
gdm_dbus_display_complete_get_seat_id (skeleton, invocation, seat_id);
return TRUE;
}
static gboolean
handle_get_x11_display_name (GdmDBusDisplay *skeleton,
GDBusMethodInvocation *invocation,
GdmDisplay *self)
{
g_autofree char *name = NULL;
gdm_display_get_x11_display_name (self, &name, NULL);
gdm_dbus_display_complete_get_x11_display_name (skeleton, invocation, name);
return TRUE;
}
static gboolean
handle_is_local (GdmDBusDisplay *skeleton,
GDBusMethodInvocation *invocation,
GdmDisplay *self)
{
gboolean is_local;
gdm_display_is_local (self, &is_local, NULL);
gdm_dbus_display_complete_is_local (skeleton, invocation, is_local);
return TRUE;
}
static gboolean
handle_is_initial (GdmDBusDisplay *skeleton,
GDBusMethodInvocation *invocation,
GdmDisplay *self)
{
gboolean is_initial = FALSE;
gdm_display_is_initial (self, &is_initial, NULL);
gdm_dbus_display_complete_is_initial (skeleton, invocation, is_initial);
return TRUE;
}
static gboolean
register_display (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
g_autoptr(GError) error = NULL;
priv = gdm_display_get_instance_private (self);
priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (priv->connection == NULL) {
g_critical ("error getting system bus: %s", error->message);
exit (EXIT_FAILURE);
}
priv->object_skeleton = g_dbus_object_skeleton_new (priv->id);
priv->display_skeleton = GDM_DBUS_DISPLAY (gdm_dbus_display_skeleton_new ());
g_signal_connect_object (priv->display_skeleton, "handle-get-id",
G_CALLBACK (handle_get_id), self, 0);
g_signal_connect_object (priv->display_skeleton, "handle-get-remote-hostname",
G_CALLBACK (handle_get_remote_hostname), self, 0);
g_signal_connect_object (priv->display_skeleton, "handle-get-seat-id",
G_CALLBACK (handle_get_seat_id), self, 0);
g_signal_connect_object (priv->display_skeleton, "handle-get-x11-display-name",
G_CALLBACK (handle_get_x11_display_name), self, 0);
g_signal_connect_object (priv->display_skeleton, "handle-is-local",
G_CALLBACK (handle_is_local), self, 0);
g_signal_connect_object (priv->display_skeleton, "handle-is-initial",
G_CALLBACK (handle_is_initial), self, 0);
g_dbus_object_skeleton_add_interface (priv->object_skeleton,
G_DBUS_INTERFACE_SKELETON (priv->display_skeleton));
return TRUE;
}
/*
dbus-send --system --print-reply --dest=org.gnome.DisplayManager /org/gnome/DisplayManager/Displays/1 org.freedesktop.DBus.Introspectable.Introspect
*/
static GObject *
gdm_display_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GdmDisplay *self;
GdmDisplayPrivate *priv;
gboolean res;
self = GDM_DISPLAY (G_OBJECT_CLASS (gdm_display_parent_class)->constructor (type,
n_construct_properties,
construct_properties));
priv = gdm_display_get_instance_private (self);
g_free (priv->id);
priv->id = g_strdup_printf ("/org/gnome/DisplayManager/Displays/%lu",
(gulong) self);
res = register_display (self);
if (! res) {
g_warning ("Unable to register display with system bus");
}
return G_OBJECT (self);
}
static void
gdm_display_dispose (GObject *object)
{
GdmDisplay *self;
GdmDisplayPrivate *priv;
self = GDM_DISPLAY (object);
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: Disposing display");
g_clear_handle_id (&priv->finish_idle_id, g_source_remove);
g_clear_object (&priv->launch_environment);
g_clear_pointer (&priv->supported_session_types, g_strfreev);
g_warn_if_fail (priv->status != GDM_DISPLAY_MANAGED);
g_warn_if_fail (priv->user_access_file == NULL);
g_warn_if_fail (priv->access_file == NULL);
G_OBJECT_CLASS (gdm_display_parent_class)->dispose (object);
}
static void
gdm_display_class_init (GdmDisplayClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gdm_display_get_property;
object_class->set_property = gdm_display_set_property;
object_class->constructor = gdm_display_constructor;
object_class->dispose = gdm_display_dispose;
object_class->finalize = gdm_display_finalize;
klass->prepare = gdm_display_real_prepare;
g_object_class_install_property (object_class,
PROP_ID,
g_param_spec_string ("id",
"id",
"id",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_REMOTE_HOSTNAME,
g_param_spec_string ("remote-hostname",
"remote-hostname",
"remote-hostname",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_X11_DISPLAY_NUMBER,
g_param_spec_int ("x11-display-number",
"x11 display number",
"x11 display number",
-1,
G_MAXINT,
-1,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_X11_DISPLAY_NAME,
g_param_spec_string ("x11-display-name",
"x11-display-name",
"x11-display-name",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_SEAT_ID,
g_param_spec_string ("seat-id",
"seat id",
"seat id",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_SESSION_ID,
g_param_spec_string ("session-id",
"session id",
"session id",
NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_SESSION_CLASS,
g_param_spec_string ("session-class",
NULL,
NULL,
"greeter",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_SESSION_TYPE,
g_param_spec_string ("session-type",
NULL,
NULL,
NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_IS_INITIAL,
g_param_spec_boolean ("is-initial",
NULL,
NULL,
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_ALLOW_TIMED_LOGIN,
g_param_spec_boolean ("allow-timed-login",
NULL,
NULL,
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_X11_COOKIE,
g_param_spec_string ("x11-cookie",
"cookie",
"cookie",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_X11_AUTHORITY_FILE,
g_param_spec_string ("x11-authority-file",
"authority file",
"authority file",
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_IS_LOCAL,
g_param_spec_boolean ("is-local",
NULL,
NULL,
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_IS_CONNECTED,
g_param_spec_boolean ("is-connected",
NULL,
NULL,
TRUE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_HAVE_EXISTING_USER_ACCOUNTS,
g_param_spec_boolean ("have-existing-user-accounts",
NULL,
NULL,
FALSE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_DOING_INITIAL_SETUP,
g_param_spec_boolean ("doing-initial-setup",
NULL,
NULL,
FALSE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_SESSION_REGISTERED,
g_param_spec_boolean ("session-registered",
NULL,
NULL,
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_LAUNCH_ENVIRONMENT,
g_param_spec_object ("launch-environment",
NULL,
NULL,
GDM_TYPE_LAUNCH_ENVIRONMENT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_STATUS,
g_param_spec_int ("status",
"status",
"status",
-1,
G_MAXINT,
GDM_DISPLAY_UNMANAGED,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_SUPPORTED_SESSION_TYPES,
g_param_spec_boxed ("supported-session-types",
"supported session types",
"supported session types",
G_TYPE_STRV,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
}
static void
gdm_display_init (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
priv = gdm_display_get_instance_private (self);
priv->creation_time = time (NULL);
}
static void
gdm_display_finalize (GObject *object)
{
GdmDisplay *self;
GdmDisplayPrivate *priv;
g_return_if_fail (object != NULL);
g_return_if_fail (GDM_IS_DISPLAY (object));
self = GDM_DISPLAY (object);
priv = gdm_display_get_instance_private (self);
g_return_if_fail (priv != NULL);
g_debug ("GdmDisplay: Finalizing display: %s", priv->id);
g_free (priv->id);
g_free (priv->seat_id);
g_free (priv->session_class);
g_free (priv->remote_hostname);
g_free (priv->x11_display_name);
g_free (priv->x11_cookie);
g_clear_object (&priv->display_skeleton);
g_clear_object (&priv->object_skeleton);
g_clear_object (&priv->connection);
g_clear_object (&priv->accountsservice_proxy);
if (priv->access_file != NULL) {
g_object_unref (priv->access_file);
}
if (priv->user_access_file != NULL) {
g_object_unref (priv->user_access_file);
}
G_OBJECT_CLASS (gdm_display_parent_class)->finalize (object);
}
GDBusObjectSkeleton *
gdm_display_get_object_skeleton (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
g_return_val_if_fail (GDM_IS_DISPLAY (self), NULL);
priv = gdm_display_get_instance_private (self);
return priv->object_skeleton;
}
static void
on_launch_environment_session_opened (GdmLaunchEnvironment *launch_environment,
GdmDisplay *self)
{
g_autofree char *session_id = NULL;
g_debug ("GdmDisplay: Greeter session opened");
session_id = gdm_launch_environment_get_session_id (launch_environment);
g_object_set (G_OBJECT (self), "session-id", session_id, NULL);
}
static void
on_launch_environment_session_started (GdmLaunchEnvironment *launch_environment,
GdmDisplay *self)
{
g_debug ("GdmDisplay: Greeter started");
}
static void
self_destruct (GdmDisplay *self)
{
g_object_ref (self);
g_debug ("GdmDisplay: initiating display self-destruct");
gdm_display_unmanage (self);
if (gdm_display_get_status (self) != GDM_DISPLAY_FINISHED) {
queue_finish (self);
}
g_object_unref (self);
}
static void
on_launch_environment_session_stopped (GdmLaunchEnvironment *launch_environment,
GdmDisplay *self)
{
g_debug ("GdmDisplay: Greeter stopped");
self_destruct (self);
}
static void
on_launch_environment_session_exited (GdmLaunchEnvironment *launch_environment,
int code,
GdmDisplay *self)
{
g_debug ("GdmDisplay: Greeter exited: %d", code);
self_destruct (self);
}
static void
on_launch_environment_session_died (GdmLaunchEnvironment *launch_environment,
int signal,
GdmDisplay *self)
{
g_debug ("GdmDisplay: Greeter died: %d", signal);
self_destruct (self);
}
static gboolean
can_create_environment (const char *session_id)
{
g_autofree char *path = NULL;
gboolean session_exists;
path = g_strdup_printf (GNOME_SESSION_SESSIONS_PATH "/%s.session", session_id);
session_exists = g_file_test (path, G_FILE_TEST_EXISTS);
return session_exists;
}
#define ALREADY_RAN_INITIAL_SETUP_ON_THIS_BOOT GDM_RUN_DIR "/gdm.ran-initial-setup"
static gboolean
already_done_initial_setup_on_this_boot (void)
{
if (g_file_test (ALREADY_RAN_INITIAL_SETUP_ON_THIS_BOOT, G_FILE_TEST_EXISTS))
return TRUE;
return FALSE;
}
static gboolean
kernel_cmdline_initial_setup_argument (const gchar *contents,
gchar **initial_setup_argument,
GError **error)
{
g_autoptr(GRegex) regex = NULL;
g_autoptr(GMatchInfo) match_info = NULL;
g_autofree gchar *match_group = NULL;
g_return_val_if_fail (initial_setup_argument != NULL, FALSE);
regex = g_regex_new ("\\bgnome.initial-setup=([^\\s]*)\\b", 0, 0, error);
if (!regex)
return FALSE;
if (!g_regex_match (regex, contents, 0, &match_info)) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Could not match gnome.initial-setup= in kernel cmdline");
return FALSE;
}
match_group = g_match_info_fetch (match_info, 1);
if (!match_group) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Could not match gnome.initial-setup= in kernel cmdline");
return FALSE;
}
*initial_setup_argument = g_steal_pointer (&match_group);
return TRUE;
}
/* Function returns true if we had a force state in the kernel
* cmdline */
static gboolean
kernel_cmdline_initial_setup_force_state (gboolean *force_state)
{
g_autoptr(GError) error = NULL;
g_autofree gchar *contents = NULL;
g_autofree gchar *setup_argument = NULL;
g_return_val_if_fail (force_state != NULL, FALSE);
if (!g_file_get_contents ("/proc/cmdline", &contents, NULL, &error)) {
g_debug ("GdmDisplay: Could not check kernel parameters, not forcing initial setup: %s",
error->message);
return FALSE;
}
g_debug ("GdmDisplay: Checking kernel command buffer %s", contents);
if (!kernel_cmdline_initial_setup_argument (contents, &setup_argument, &error)) {
g_debug ("GdmDisplay: Failed to read kernel commandline: %s", error->message);
return FALSE;
}
/* Poor-man's check for truthy or falsey values */
*force_state = setup_argument[0] == '1';
return TRUE;
}
static gboolean
wants_initial_setup (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
gboolean enabled = FALSE;
gboolean forced = FALSE;
priv = gdm_display_get_instance_private (self);
if (already_done_initial_setup_on_this_boot ()) {
return FALSE;
}
if (kernel_cmdline_initial_setup_force_state (&forced)) {
if (forced) {
g_debug ("GdmDisplay: Forcing gnome-initial-setup");
return TRUE;
}
g_debug ("GdmDisplay: Forcing no gnome-initial-setup");
return FALSE;
}
/* don't run initial-setup on remote displays
*/
if (!priv->is_local) {
return FALSE;
}
/* don't run if the system has existing users */
if (priv->have_existing_user_accounts) {
return FALSE;
}
/* don't run if initial-setup is unavailable */
if (!can_create_environment ("gnome-initial-setup")) {
return FALSE;
}
if (!gdm_settings_direct_get_boolean (GDM_KEY_INITIAL_SETUP_ENABLE, &enabled)) {
return FALSE;
}
return enabled;
}
void
gdm_display_start_greeter_session (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
GdmSession *session;
g_autofree char *display_name = NULL;
g_autofree char *seat_id = NULL;
g_autofree char *hostname = NULL;
g_autofree char *auth_file = NULL;
g_return_if_fail (GDM_IS_DISPLAY (self));
priv = gdm_display_get_instance_private (self);
g_return_if_fail (g_strcmp0 (priv->session_class, "greeter") == 0);
g_debug ("GdmDisplay: Running greeter");
g_object_get (self,
"x11-display-name", &display_name,
"seat-id", &seat_id,
"remote-hostname", &hostname,
NULL);
if (priv->access_file != NULL) {
auth_file = gdm_display_access_file_get_path (priv->access_file);
}
g_debug ("GdmDisplay: Creating greeter for %s %s", display_name, hostname);
g_signal_connect_object (priv->launch_environment,
"opened",
G_CALLBACK (on_launch_environment_session_opened),
self, 0);
g_signal_connect_object (priv->launch_environment,
"started",
G_CALLBACK (on_launch_environment_session_started),
self, 0);
g_signal_connect_object (priv->launch_environment,
"stopped",
G_CALLBACK (on_launch_environment_session_stopped),
self, 0);
g_signal_connect_object (priv->launch_environment,
"exited",
G_CALLBACK (on_launch_environment_session_exited),
self, 0);
g_signal_connect_object (priv->launch_environment,
"died",
G_CALLBACK (on_launch_environment_session_died),
self, 0);
if (auth_file != NULL) {
g_object_set (priv->launch_environment,
"x11-authority-file", auth_file,
NULL);
}
gdm_launch_environment_start (priv->launch_environment);
session = gdm_launch_environment_get_session (priv->launch_environment);
g_object_set (G_OBJECT (session),
"display-is-initial", priv->is_initial,
"supported-session-types", priv->supported_session_types,
NULL);
}
void
gdm_display_stop_greeter_session (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
g_return_if_fail (GDM_IS_DISPLAY (self));
priv = gdm_display_get_instance_private (self);
if (priv->launch_environment != NULL) {
g_signal_handlers_disconnect_by_func (priv->launch_environment,
G_CALLBACK (on_launch_environment_session_opened),
self);
g_signal_handlers_disconnect_by_func (priv->launch_environment,
G_CALLBACK (on_launch_environment_session_started),
self);
g_signal_handlers_disconnect_by_func (priv->launch_environment,
G_CALLBACK (on_launch_environment_session_stopped),
self);
g_signal_handlers_disconnect_by_func (priv->launch_environment,
G_CALLBACK (on_launch_environment_session_exited),
self);
g_signal_handlers_disconnect_by_func (priv->launch_environment,
G_CALLBACK (on_launch_environment_session_died),
self);
gdm_launch_environment_stop (priv->launch_environment);
g_clear_object (&priv->launch_environment);
}
}
#ifdef ENABLE_X11_SUPPORT
static xcb_window_t
get_root_window (xcb_connection_t *connection,
int screen_number)
{
xcb_screen_t *screen = NULL;
xcb_screen_iterator_t iter;
iter = xcb_setup_roots_iterator (xcb_get_setup (connection));
while (iter.rem) {
if (screen_number == 0)
screen = iter.data;
screen_number--;
xcb_screen_next (&iter);
}
if (screen != NULL) {
return screen->root;
}
return XCB_WINDOW_NONE;
}
static void
gdm_display_set_windowpath (GdmDisplay *self)
{
GdmDisplayPrivate *priv;
/* setting WINDOWPATH for clients */
xcb_intern_atom_cookie_t atom_cookie;
xcb_intern_atom_reply_t *atom_reply = NULL;
xcb_get_property_cookie_t get_property_cookie;
xcb_get_property_reply_t *get_property_reply = NULL;
xcb_window_t root_window = XCB_WINDOW_NONE;
const char *windowpath;
g_autofree gchar *newwindowpath = NULL;
uint32_t num;
priv = gdm_display_get_instance_private (self);
atom_cookie = xcb_intern_atom (priv->xcb_connection, 0, strlen("XFree86_VT"), "XFree86_VT");
atom_reply = xcb_intern_atom_reply (priv->xcb_connection, atom_cookie, NULL);
if (atom_reply == NULL) {
g_debug ("no XFree86_VT atom\n");
goto out;
}
root_window = get_root_window (priv->xcb_connection,
priv->xcb_screen_number);
if (root_window == XCB_WINDOW_NONE) {
g_debug ("couldn't find root window\n");
goto out;
}
get_property_cookie = xcb_get_property (priv->xcb_connection,
FALSE,
root_window,
atom_reply->atom,
XCB_ATOM_INTEGER,
0,
1);
get_property_reply = xcb_get_property_reply (priv->xcb_connection, get_property_cookie, NULL);
if (get_property_reply == NULL) {
g_debug ("no XFree86_VT property\n");
goto out;
}
num = ((uint32_t *) xcb_get_property_value (get_property_reply))[0];
windowpath = getenv ("WINDOWPATH");
if (!windowpath) {
newwindowpath = g_strdup_printf ("%u", num);
} else {
newwindowpath = g_strdup_printf ("%s:%u", windowpath, num);
}
g_setenv ("WINDOWPATH", newwindowpath, TRUE);
out:
g_clear_pointer (&atom_reply, free);
g_clear_pointer (&get_property_reply, free);
}
#endif
gboolean
gdm_display_connect (GdmDisplay *self)
{
#ifdef ENABLE_X11_SUPPORT
GdmDisplayPrivate *priv;
xcb_auth_info_t *auth_info = NULL;
gboolean ret;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
priv = gdm_display_get_instance_private (self);
g_debug ("GdmDisplay: Server is ready - opening display %s", priv->x11_display_name);
/* Get access to the display independent of current hostname */
if (priv->x11_cookie != NULL) {
auth_info = g_alloca (sizeof (xcb_auth_info_t));
auth_info->namelen = strlen ("MIT-MAGIC-COOKIE-1");
auth_info->name = "MIT-MAGIC-COOKIE-1";
auth_info->datalen = priv->x11_cookie_size;
auth_info->data = priv->x11_cookie;
}
priv->xcb_connection = xcb_connect_to_display_with_auth_info (priv->x11_display_name,
auth_info,
&priv->xcb_screen_number);
if (xcb_connection_has_error (priv->xcb_connection)) {
g_clear_pointer (&priv->xcb_connection, xcb_disconnect);
g_warning ("Unable to connect to display %s", priv->x11_display_name);
ret = FALSE;
} else if (priv->is_local) {
XHostAddress host_entries[3];
xcb_void_cookie_t cookies[3];
int i;
g_debug ("GdmDisplay: Connected to display %s", priv->x11_display_name);
ret = TRUE;
/* Give programs access to the display independent of current hostname
*/
setup_xhost_auth (host_entries);
for (i = 0; i < G_N_ELEMENTS (host_entries); i++) {
cookies[i] = xcb_change_hosts_checked (priv->xcb_connection,
XCB_HOST_MODE_INSERT,
host_entries[i].family,
host_entries[i].length,
(uint8_t *) host_entries[i].address);
}
for (i = 0; i < G_N_ELEMENTS (cookies); i++) {
xcb_generic_error_t *xcb_error;
xcb_error = xcb_request_check (priv->xcb_connection, cookies[i]);
if (xcb_error != NULL) {
g_debug ("Failed to give system user '%s' access to the display. Trying to proceed.", host_entries[i].address + sizeof ("localuser"));
free (xcb_error);
} else {
g_debug ("Gave system user '%s' access to the display.", host_entries[i].address + sizeof ("localuser"));
}
}
gdm_display_set_windowpath (self);
} else {
g_debug ("GdmDisplay: Connected to display %s", priv->x11_display_name);
ret = TRUE;
}
if (ret == TRUE) {
g_object_notify (G_OBJECT (self), "is-connected");
}
return ret;
#else
return FALSE;
#endif
}