From 675525ceb5576a4806f5c5fe7cef4af53198b8f7 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Mar 31 2020 09:36:57 +0000 Subject: import gdm-3.28.2-22.el7 --- diff --git a/SOURCES/0001-session-worker-expose-worker-state-enum-to-type-syst.patch b/SOURCES/0001-session-worker-expose-worker-state-enum-to-type-syst.patch new file mode 100644 index 0000000..9acd4e1 --- /dev/null +++ b/SOURCES/0001-session-worker-expose-worker-state-enum-to-type-syst.patch @@ -0,0 +1,557 @@ +From 82f67be72a5c3ef0f2674e6f87a9ced866ebc82a Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Mon, 24 Jun 2019 14:48:23 -0400 +Subject: [PATCH 1/7] session-worker: expose worker state enum to type system + +We're going to need to access the worker state as a property on +the worker object. + +This commit hooks it up to glib-mkenums so the requisite goo can +get generated +--- + daemon/Makefile.am | 14 ++++++++ + daemon/gdm-session-worker-enum-types.c.in | 42 +++++++++++++++++++++++ + daemon/gdm-session-worker-enum-types.h.in | 24 +++++++++++++ + daemon/gdm-session-worker.c | 16 +++------ + daemon/gdm-session-worker.h | 12 +++++++ + 5 files changed, 96 insertions(+), 12 deletions(-) + create mode 100644 daemon/gdm-session-worker-enum-types.c.in + create mode 100644 daemon/gdm-session-worker-enum-types.h.in + +diff --git a/daemon/Makefile.am b/daemon/Makefile.am +index 3b1b15122..7498115cd 100644 +--- a/daemon/Makefile.am ++++ b/daemon/Makefile.am +@@ -14,68 +14,75 @@ AM_CPPFLAGS = \ + -DLIBEXECDIR=\"$(libexecdir)\" \ + -DLOCALSTATEDIR=\"$(localstatedir)\" \ + -DLOGDIR=\"$(logdir)\" \ + -DSBINDIR=\"$(sbindir)\" \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ + -DGDM_RUN_DIR=\"$(GDM_RUN_DIR)\" \ + -DGDM_XAUTH_DIR=\"$(GDM_XAUTH_DIR)\" \ + -DGDM_SCREENSHOT_DIR=\"$(GDM_SCREENSHOT_DIR)\" \ + -DGDM_CACHE_DIR=\""$(localstatedir)/cache/gdm"\" \ + -DGDM_SESSION_DEFAULT_PATH=\"$(GDM_SESSION_DEFAULT_PATH)\" \ + $(DISABLE_DEPRECATED_CFLAGS) \ + $(DAEMON_CFLAGS) \ + $(XLIB_CFLAGS) \ + $(WARN_CFLAGS) \ + $(DEBUG_CFLAGS) \ + $(SYSTEMD_CFLAGS) \ + $(JOURNALD_CFLAGS) \ + $(LIBSELINUX_CFLAGS) \ + -DLANG_CONFIG_FILE=\"$(LANG_CONFIG_FILE)\" \ + $(NULL) + + BUILT_SOURCES = \ + gdm-display-glue.h \ + gdm-manager-glue.h \ + gdm-local-display-glue.h \ + gdm-local-display-factory-glue.h \ + gdm-session-glue.h \ + gdm-session-worker-glue.h \ + gdm-session-enum-types.h \ ++ gdm-session-worker-enum-types.h \ + $(NULL) + + gdm-session-enum-types.h: gdm-session-enum-types.h.in gdm-session.h + $(AM_V_GEN) glib-mkenums --template $^ > $@ + + gdm-session-enum-types.c: gdm-session-enum-types.c.in gdm-session.h + $(AM_V_GEN) glib-mkenums --template $^ > $@ + ++gdm-session-worker-enum-types.h: gdm-session-worker-enum-types.h.in gdm-session-worker.h ++ $(AM_V_GEN) glib-mkenums --template $^ > $@ ++ ++gdm-session-worker-enum-types.c: gdm-session-worker-enum-types.c.in gdm-session-worker.h ++ $(AM_V_GEN) glib-mkenums --template $^ > $@ ++ + gdm-display-glue.c gdm-display-glue.h: gdm-display.xml Makefile.am + $(AM_V_GEN)gdbus-codegen \ + --c-namespace=GdmDBus \ + --interface-prefix=org.gnome.DisplayManager \ + --generate-c-code=gdm-display-glue \ + $(srcdir)/gdm-display.xml + + gdm-local-display-glue.c gdm-local-display-glue.h: gdm-local-display.xml Makefile.am + $(AM_V_GEN)gdbus-codegen \ + --c-namespace=GdmDBus \ + --interface-prefix=org.gnome.DisplayManager \ + --generate-c-code=gdm-local-display-glue \ + $(srcdir)/gdm-local-display.xml + + gdm-local-display-factory-glue.c gdm-local-display-factory-glue.h : gdm-local-display-factory.xml Makefile.am + $(AM_V_GEN)gdbus-codegen \ + --c-namespace=GdmDBus \ + --interface-prefix=org.gnome.DisplayManager \ + --generate-c-code=gdm-local-display-factory-glue \ + $(srcdir)/gdm-local-display-factory.xml + + gdm-manager-glue.c gdm-manager-glue.h : gdm-manager.xml Makefile.am + $(AM_V_GEN)gdbus-codegen \ + --c-namespace=GdmDBus \ + --interface-prefix=org.gnome.DisplayManager \ + --generate-c-code=gdm-manager-glue \ + $(srcdir)/gdm-manager.xml + + gdm-session-glue.c gdm-session-glue.h : gdm-session.xml Makefile.am + $(AM_V_GEN)gdbus-codegen \ +@@ -119,60 +126,62 @@ libexec_PROGRAMS = \ + gdm_session_worker_SOURCES = \ + session-worker-main.c \ + gdm-session.c \ + gdm-session.h \ + gdm-session-settings.h \ + gdm-session-settings.c \ + gdm-session-auditor.h \ + gdm-session-auditor.c \ + gdm-session-record.c \ + gdm-session-record.h \ + gdm-session-worker.h \ + gdm-session-worker.c \ + gdm-session-worker-job.c \ + gdm-session-worker-common.c \ + gdm-session-worker-common.h \ + gdm-dbus-util.c \ + gdm-dbus-util.h \ + $(NULL) + + if SUPPORTS_PAM_EXTENSIONS + gdm_session_worker_SOURCES += $(top_srcdir)/pam-extensions/gdm-pam-extensions.h + endif + + nodist_gdm_session_worker_SOURCES = \ + gdm-session-glue.h \ + gdm-session-glue.c \ + gdm-session-worker-glue.c \ + gdm-session-worker-glue.h \ + gdm-session-enum-types.c \ + gdm-session-enum-types.h \ ++ gdm-session-worker-enum-types.h \ ++ gdm-session-worker-enum-types.c \ + $(NULL) + + gdm_wayland_session_LDADD = \ + $(top_builddir)/common/libgdmcommon.la \ + $(GTK_LIBS) \ + $(COMMON_LIBS) \ + $(SYSTEMD_LIBS) \ + $(NULL) + + gdm_wayland_session_SOURCES = \ + gdm-manager-glue.h \ + gdm-manager-glue.c \ + gdm-wayland-session.c \ + $(NULL) + + gdm_x_session_LDADD = \ + $(top_builddir)/common/libgdmcommon.la \ + $(GTK_LIBS) \ + $(COMMON_LIBS) \ + $(SYSTEMD_LIBS) \ + $(XLIB_LIBS) \ + $(NULL) + + gdm_x_session_SOURCES = \ + gdm-manager-glue.h \ + gdm-manager-glue.c \ + gdm-x-session.c \ + $(NULL) + + if HAVE_LIBAUDIT +@@ -222,81 +231,86 @@ gdm_SOURCES = \ + gdm-manager.h \ + gdm-server.c \ + gdm-server.h \ + gdm-session.c \ + gdm-session.h \ + gdm-session-record.c \ + gdm-session-record.h \ + gdm-session-worker-common.c \ + gdm-session-worker-common.h \ + gdm-session-worker-job.c \ + gdm-session-worker-job.h \ + gdm-dbus-util.c \ + gdm-dbus-util.h \ + $(NULL) + + nodist_gdm_SOURCES = \ + gdm-display-glue.h \ + gdm-display-glue.c \ + gdm-local-display-factory-glue.h \ + gdm-local-display-factory-glue.c \ + gdm-manager-glue.h \ + gdm-manager-glue.c \ + gdm-local-display-glue.h \ + gdm-local-display-glue.c \ + gdm-session-glue.h \ + gdm-session-glue.c \ + gdm-session-worker-glue.c \ + gdm-session-worker-glue.h \ + gdm-session-enum-types.c \ + gdm-session-enum-types.h \ ++ gdm-session-worker-enum-types.h \ ++ gdm-session-worker-enum-types.c \ + $(NULL) + + XDMCP_SOURCES = \ + gdm-xdmcp-display-factory.c \ + gdm-xdmcp-display-factory.h \ + gdm-xdmcp-display.c \ + gdm-xdmcp-display.h \ + gdm-xdmcp-chooser-display.c \ + gdm-xdmcp-chooser-display.h \ + $(NULL) + + if XDMCP_SUPPORT + gdm_SOURCES += $(XDMCP_SOURCES) + endif + + EXTRA_gdm_SOURCES = \ + $(XDMCP_SOURCES) \ + $(NULL) + + gdm_LDADD = \ + $(top_builddir)/common/libgdmcommon.la \ + $(XLIB_LIBS) \ + $(DAEMON_LIBS) \ + $(XDMCP_LIBS) \ + $(LIBWRAP_LIBS) \ + $(SYSTEMD_LIBS) \ + $(JOURNALD_LIBS) \ + $(EXTRA_DAEMON_LIBS) \ + $(NULL) + + CLEANFILES = \ + gdm-display-glue.c \ + gdm-local-display-factory-glue.c \ + gdm-manager-glue.c \ + gdm-session-glue.c \ + gdm-session-worker-glue.c \ + gdm-session-enum-types.c \ ++ gdm-session-worker-enum-types.c \ + gdm-local-display-glue.c \ + $(BUILT_SOURCES) \ + $(NULL) + + EXTRA_DIST = \ + gdm-manager.xml \ + gdm-session-worker.xml \ + gdm-session.xml \ + gdm-display.xml \ + gdm-local-display.xml \ + gdm-local-display-factory.xml \ + gdm-session-enum-types.c.in \ + gdm-session-enum-types.h.in \ ++ gdm-session-worker-enum-types.c.in \ ++ gdm-session-worker-enum-types.h.in \ + $(NULL) +diff --git a/daemon/gdm-session-worker-enum-types.c.in b/daemon/gdm-session-worker-enum-types.c.in +new file mode 100644 +index 000000000..c02869076 +--- /dev/null ++++ b/daemon/gdm-session-worker-enum-types.c.in +@@ -0,0 +1,42 @@ ++/*** BEGIN file-header ***/ ++ ++#include ++ ++/*** END file-header ***/ ++ ++/*** BEGIN file-production ***/ ++#include "@filename@" ++/* enumerations from "@filename@" */ ++/*** END file-production ***/ ++ ++/*** BEGIN value-header ***/ ++GType @enum_name@_get_type (void) G_GNUC_CONST; ++ ++GType ++@enum_name@_get_type (void) ++{ ++ static GType etype = 0; ++ ++ if (G_UNLIKELY(etype == 0)) { ++ static const G@Type@Value values[] = { ++/*** END value-header ***/ ++ ++/*** BEGIN value-production ***/ ++ { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, ++/*** END value-production ***/ ++ ++/*** BEGIN value-tail ***/ ++ { 0, NULL, NULL } ++ }; ++ ++ etype = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); ++ } ++ ++ return etype; ++} ++ ++/*** END value-tail ***/ ++ ++/*** BEGIN file-tail ***/ ++ /**/ ++/*** END file-tail ***/ +diff --git a/daemon/gdm-session-worker-enum-types.h.in b/daemon/gdm-session-worker-enum-types.h.in +new file mode 100644 +index 000000000..64f4b4bb6 +--- /dev/null ++++ b/daemon/gdm-session-worker-enum-types.h.in +@@ -0,0 +1,24 @@ ++/*** BEGIN file-header ***/ ++#ifndef GDM_SESSION_WORKER_ENUM_TYPES_H ++#define GDM_SESSION_WORKER_ENUM_TYPES_H ++ ++#include ++ ++G_BEGIN_DECLS ++/*** END file-header ***/ ++ ++/*** BEGIN file-production ***/ ++ ++/* enumerations from "@filename@" */ ++/*** END file-production ***/ ++ ++/*** BEGIN value-header ***/ ++GType @enum_name@_get_type (void) G_GNUC_CONST; ++#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) ++/*** END value-header ***/ ++ ++/*** BEGIN file-tail ***/ ++G_END_DECLS ++ ++#endif /* GDM_SESSION_WORKER_ENUM_TYPES_H */ ++/*** END file-tail ***/ +diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c +index f71594c22..d897779f3 100644 +--- a/daemon/gdm-session-worker.c ++++ b/daemon/gdm-session-worker.c +@@ -83,83 +83,72 @@ + #define GDM_SESSION_WORKER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SESSION_WORKER, GdmSessionWorkerPrivate)) + + #define GDM_SESSION_DBUS_PATH "/org/gnome/DisplayManager/Session" + #define GDM_SESSION_DBUS_NAME "org.gnome.DisplayManager.Session" + #define GDM_SESSION_DBUS_ERROR_CANCEL "org.gnome.DisplayManager.Session.Error.Cancel" + + #define GDM_WORKER_DBUS_PATH "/org/gnome/DisplayManager/Worker" + + #ifndef GDM_PASSWD_AUXILLARY_BUFFER_SIZE + #define GDM_PASSWD_AUXILLARY_BUFFER_SIZE 1024 + #endif + + #ifndef GDM_SESSION_DEFAULT_PATH + #define GDM_SESSION_DEFAULT_PATH "/usr/local/bin:/usr/bin:/bin" + #endif + + #ifndef GDM_SESSION_ROOT_UID + #define GDM_SESSION_ROOT_UID 0 + #endif + + #ifndef GDM_SESSION_LOG_FILENAME + #define GDM_SESSION_LOG_FILENAME "session.log" + #endif + + #define MAX_FILE_SIZE 65536 + #define MAX_LOGS 5 + + #define RELEASE_DISPLAY_SIGNAL (SIGRTMAX) + #define ACQUIRE_DISPLAY_SIGNAL (SIGRTMAX - 1) + +-enum { +- GDM_SESSION_WORKER_STATE_NONE = 0, +- GDM_SESSION_WORKER_STATE_SETUP_COMPLETE, +- GDM_SESSION_WORKER_STATE_AUTHENTICATED, +- GDM_SESSION_WORKER_STATE_AUTHORIZED, +- GDM_SESSION_WORKER_STATE_ACCREDITED, +- GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED, +- GDM_SESSION_WORKER_STATE_SESSION_OPENED, +- GDM_SESSION_WORKER_STATE_SESSION_STARTED +-}; +- + typedef struct + { + GdmSessionWorker *worker; + GdmSession *session; + GPid pid_of_caller; + uid_t uid_of_caller; + + } ReauthenticationRequest; + + struct GdmSessionWorkerPrivate + { +- int state; ++ GdmSessionWorkerState state; + + int exit_code; + + pam_handle_t *pam_handle; + + GPid child_pid; + guint child_watch_id; + + /* from Setup */ + char *service; + char *x11_display_name; + char *x11_authority_file; + char *display_device; + char *display_seat_id; + char *hostname; + char *username; + char *log_file; + char *session_id; + uid_t uid; + gid_t gid; + gboolean password_is_required; + char **extensions; + + int cred_flags; + int login_vt; + int session_vt; + int session_tty_fd; + + char **arguments; + guint32 cancelled : 1; +@@ -2464,60 +2453,63 @@ gdm_session_worker_set_property (GObject *object, + switch (prop_id) { + case PROP_SERVER_ADDRESS: + gdm_session_worker_set_server_address (self, g_value_get_string (value)); + break; + case PROP_IS_REAUTH_SESSION: + gdm_session_worker_set_is_reauth_session (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } + + static void + gdm_session_worker_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) + { + GdmSessionWorker *self; + + self = GDM_SESSION_WORKER (object); + + switch (prop_id) { + case PROP_SERVER_ADDRESS: + g_value_set_string (value, self->priv->server_address); + break; + case PROP_IS_REAUTH_SESSION: + g_value_set_boolean (value, self->priv->is_reauth_session); + break; ++ case PROP_STATE: ++ g_value_set_int (value, self->priv->state); ++ break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } + + static gboolean + gdm_session_worker_handle_set_environment_variable (GdmDBusWorker *object, + GDBusMethodInvocation *invocation, + const char *key, + const char *value) + { + GdmSessionWorker *worker = GDM_SESSION_WORKER (object); + gdm_session_worker_set_environment_variable (worker, key, value); + gdm_dbus_worker_complete_set_environment_variable (object, invocation); + return TRUE; + } + + static gboolean + gdm_session_worker_handle_set_session_name (GdmDBusWorker *object, + GDBusMethodInvocation *invocation, + const char *session_name) + { + GdmSessionWorker *worker = GDM_SESSION_WORKER (object); + g_debug ("GdmSessionWorker: session name set to %s", session_name); + gdm_session_settings_set_session_name (worker->priv->user_settings, + session_name); + gdm_dbus_worker_complete_set_session_name (object, invocation); + return TRUE; + } +diff --git a/daemon/gdm-session-worker.h b/daemon/gdm-session-worker.h +index 5603e80e0..2814eab4d 100644 +--- a/daemon/gdm-session-worker.h ++++ b/daemon/gdm-session-worker.h +@@ -1,56 +1,68 @@ + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2006 Ray Strode + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + #ifndef __GDM_SESSION_WORKER_H + #define __GDM_SESSION_WORKER_H + + #include + + #include "gdm-session-worker-glue.h" + #include "gdm-session-worker-common.h" ++#include "gdm-session-worker-enum-types.h" + + G_BEGIN_DECLS + + #define GDM_TYPE_SESSION_WORKER (gdm_session_worker_get_type ()) + #define GDM_SESSION_WORKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDM_TYPE_SESSION_WORKER, GdmSessionWorker)) + #define GDM_SESSION_WORKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_SESSION_WORKER, GdmSessionWorkerClass)) + #define GDM_IS_SESSION_WORKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDM_TYPE_SESSION_WORKER)) + #define GDM_IS_SESSION_WORKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_SESSION_WORKER)) + #define GDM_SESSION_WORKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_SESSION_WORKER, GdmSessionWorkerClass)) + ++typedef enum { ++ GDM_SESSION_WORKER_STATE_NONE = 0, ++ GDM_SESSION_WORKER_STATE_SETUP_COMPLETE, ++ GDM_SESSION_WORKER_STATE_AUTHENTICATED, ++ GDM_SESSION_WORKER_STATE_AUTHORIZED, ++ GDM_SESSION_WORKER_STATE_ACCREDITED, ++ GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED, ++ GDM_SESSION_WORKER_STATE_SESSION_OPENED, ++ GDM_SESSION_WORKER_STATE_SESSION_STARTED ++} GdmSessionWorkerState; ++ + typedef struct GdmSessionWorkerPrivate GdmSessionWorkerPrivate; + + typedef struct + { + GdmDBusWorkerSkeleton parent; + GdmSessionWorkerPrivate *priv; + } GdmSessionWorker; + + typedef struct + { + GdmDBusWorkerSkeletonClass parent_class; + } GdmSessionWorkerClass; + + GType gdm_session_worker_get_type (void); + + GdmSessionWorker * gdm_session_worker_new (const char *server_address, + gboolean is_for_reauth) G_GNUC_MALLOC; + G_END_DECLS + #endif /* GDM_SESSION_WORKER_H */ +-- +2.21.0 + diff --git a/SOURCES/0001-utils-add-new-gdm-disable-wayland-binary.patch b/SOURCES/0001-utils-add-new-gdm-disable-wayland-binary.patch new file mode 100644 index 0000000..823312a --- /dev/null +++ b/SOURCES/0001-utils-add-new-gdm-disable-wayland-binary.patch @@ -0,0 +1,160 @@ +From 12e58deaa909c5d87bcb56ad6c47e33f5740722b Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Mon, 21 May 2018 15:03:29 +0000 +Subject: [PATCH] utils: add new gdm-disable-wayland binary + +We currently disable wayland for cirrus by calling printf +from a udev rule. This works, but it's a little too open +coded to easily write SELinux policy for. + +This commit introduces a new program, gdm-disable-wayland, +that does the same thing, but in a dedicated binary. + +A future commit will change the udev rule to use the binary. + +https://bugzilla.gnome.org/show_bug.cgi?id=796315 + +(cherry picked from commit 2dc57da31781dedfe374ce353b0f5fd6aa9da56f) +--- + utils/Makefile.am | 14 ++++++++++ + utils/gdm-disable-wayland.c | 53 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 67 insertions(+) + create mode 100644 utils/gdm-disable-wayland.c + +diff --git a/utils/Makefile.am b/utils/Makefile.am +index ae3cc01fb..babe890b9 100644 +--- a/utils/Makefile.am ++++ b/utils/Makefile.am +@@ -1,56 +1,70 @@ + NULL = + + AM_CPPFLAGS = \ + -I$(srcdir) \ + -I$(builddir) \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + -I$(top_srcdir)/common \ + -I$(top_builddir)/common \ + -DDATADIR=\"$(datadir)\" \ + -DGDMCONFDIR=\"$(gdmconfdir)\" \ + -DLOCALSTATEDIR=\""$(localstatedir)"\" \ ++ -DGDM_RUN_DIR=\"$(GDM_RUN_DIR)\" \ ++ -DGDM_RUNTIME_CONF=\"$(GDM_RUNTIME_CONF)\" \ + -DGDM_SCREENSHOT_DIR=\""$(GDM_SCREENSHOT_DIR)"\"\ + -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ + $(UTILS_CFLAGS) \ + $(CANBERRA_GTK_CFLAGS) \ + $(GTK_CFLAGS) \ + $(XLIB_CFLAGS) \ + $(SYSTEMD_CFLAGS) \ + $(COMMON_CFLAGS) \ + $(NULL) + + edit = sed \ + -e 's|@sbindir[@]|$(sbindir)|g' \ + -e 's|@sysconfdir[@]|$(sysconfdir)|g' \ + -e 's|@localstatedir[@]|$(localstatedir)|g' \ + -e 's|@GDM_PID_FILE[@]|$(GDM_PID_FILE)|g' + + bin_PROGRAMS = \ + gdmflexiserver \ + gdm-screenshot \ + $(NULL) + ++libexec_PROGRAMS = \ ++ gdm-disable-wayland \ ++ $(NULL) ++ + gdmflexiserver_LDADD = \ + $(top_builddir)/common/libgdmcommon.la \ + $(GTK_LIBS) \ + $(COMMON_LIBS) \ + $(SYSTEMD_LIBS) \ + $(NULL) + + gdm_screenshot_SOURCES = \ + gdm-screenshot.c \ + $(NULL) + + gdm_screenshot_LDADD = \ + $(GTK_LIBS) \ + $(CANBERRA_GTK_LIBS) \ + $(XLIB_LIBS) \ + $(COMMON_LIBS) \ + $(NULL) + ++gdm_disable_wayland_LDADD = \ ++ $(COMMON_LIBS) \ ++ $(NULL) ++ ++gdm_disable_wayland_SOURCES = \ ++ gdm-disable-wayland.c \ ++ $(NULL) ++ + CLEANFILES = \ + $(NULL) + + DISTCLEANFILES = \ + $(NULL) +diff --git a/utils/gdm-disable-wayland.c b/utils/gdm-disable-wayland.c +new file mode 100644 +index 000000000..be61c4d8f +--- /dev/null ++++ b/utils/gdm-disable-wayland.c +@@ -0,0 +1,53 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2018 Red Hat, Inc. ++ * ++ * 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 ++ ++int ++main (int argc, char *argv[]) ++{ ++ g_autoptr(GKeyFile) key_file = NULL; ++ g_autoptr(GError) error = NULL; ++ gboolean saved_okay; ++ ++ setlocale (LC_ALL, ""); ++ ++ key_file = g_key_file_new (); ++ ++ g_key_file_set_boolean (key_file, "daemon", "WaylandEnable", FALSE); ++ ++ g_mkdir_with_parents (GDM_RUN_DIR, 0711); ++ ++ saved_okay = g_key_file_save_to_file (key_file, GDM_RUNTIME_CONF, &error); ++ ++ if (!saved_okay) { ++ g_printerr ("gdm-disable-wayland: unable to disable wayland: %s", ++ error->message); ++ return EX_CANTCREAT; ++ } ++ ++ return EX_OK; ++} +-- +2.21.0 + diff --git a/SOURCES/0002-session-worker-kill-user-sessions-when-stopping-gdm-.patch b/SOURCES/0002-session-worker-kill-user-sessions-when-stopping-gdm-.patch new file mode 100644 index 0000000..c2342c3 --- /dev/null +++ b/SOURCES/0002-session-worker-kill-user-sessions-when-stopping-gdm-.patch @@ -0,0 +1,922 @@ +From 35a4d47385d043cf4df62c2723508e4edce4dfb4 Mon Sep 17 00:00:00 2001 +From: Xiaoguang Wang +Date: Thu, 16 May 2019 13:26:16 +0800 +Subject: [PATCH 2/7] session-worker: kill user sessions when stopping gdm + service + +At the moment the session worker exits as soon as it gets SIGTERM. +That means it may fail to stop the user session (which only happens +in the orderly shutdown path). + +This commit sets up a SIGTERM handler that integrates with and +quits the main loop after the session is started. + +It still retains the _exit-on-SIGTERM behavior before the session +is started, to ensure a stuck pam module doesn't prevent the +process from dying. + +Some small changes to commit by Ray Strode. + +Closes #400 +--- + daemon/gdm-session-worker.c | 38 +++++++++++++++++++++++++++--------- + daemon/session-worker-main.c | 33 +++++++++++++++++++++++++++++++ + 2 files changed, 62 insertions(+), 9 deletions(-) + +diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c +index d897779f3..e526fa5db 100644 +--- a/daemon/gdm-session-worker.c ++++ b/daemon/gdm-session-worker.c +@@ -159,60 +159,61 @@ struct GdmSessionWorkerPrivate + guint32 display_is_initial : 1; + guint state_change_idle_id; + GdmSessionDisplayMode display_mode; + + char *server_address; + GDBusConnection *connection; + GdmDBusWorkerManager *manager; + + GHashTable *reauthentication_requests; + + GdmSessionAuditor *auditor; + GdmSessionSettings *user_settings; + + GDBusMethodInvocation *pending_invocation; + }; + + #ifdef SUPPORTS_PAM_EXTENSIONS + static char gdm_pam_extension_environment_block[_POSIX_ARG_MAX]; + + static const char * const + gdm_supported_pam_extensions[] = { + GDM_PAM_EXTENSION_CHOICE_LIST, + NULL + }; + #endif + + enum { + PROP_0, + PROP_SERVER_ADDRESS, + PROP_IS_REAUTH_SESSION, ++ PROP_STATE, + }; + + static void gdm_session_worker_class_init (GdmSessionWorkerClass *klass); + static void gdm_session_worker_init (GdmSessionWorker *session_worker); + static void gdm_session_worker_finalize (GObject *object); + + static void gdm_session_worker_set_environment_variable (GdmSessionWorker *worker, + const char *key, + const char *value); + + static void queue_state_change (GdmSessionWorker *worker); + + static void worker_interface_init (GdmDBusWorkerIface *iface); + + + typedef int (* GdmSessionWorkerPamNewMessagesFunc) (int, + const struct pam_message **, + struct pam_response **, + gpointer); + + G_DEFINE_TYPE_WITH_CODE (GdmSessionWorker, + gdm_session_worker, + GDM_DBUS_TYPE_WORKER_SKELETON, + G_IMPLEMENT_INTERFACE (GDM_DBUS_TYPE_WORKER, + worker_interface_init)) + + /* adapted from glib script_execute */ + static void + script_execute (const gchar *file, + char **argv, +@@ -966,100 +967,111 @@ jump_to_vt (GdmSessionWorker *worker, + + g_debug ("GdmSessionWorker: first setting graphics mode to prevent flicker"); + if (ioctl (fd, KDSETMODE, KD_GRAPHICS) < 0) { + g_debug ("GdmSessionWorker: couldn't set graphics mode: %m"); + } + + /* It's possible that the current VT was left in a broken + * combination of states (KD_GRAPHICS with VT_AUTO), that + * can't be switched away from. This call makes sure things + * are set in a way that VT_ACTIVATE should work and + * VT_WAITACTIVE shouldn't hang. + */ + fix_terminal_vt_mode (worker, active_vt_tty_fd); + } else { + fd = active_vt_tty_fd; + } + + handle_terminal_vt_switches (worker, fd); + + if (ioctl (fd, VT_ACTIVATE, vt_number) < 0) { + g_debug ("GdmSessionWorker: couldn't initiate jump to VT %d: %m", + vt_number); + } else if (ioctl (fd, VT_WAITACTIVE, vt_number) < 0) { + g_debug ("GdmSessionWorker: couldn't finalize jump to VT %d: %m", + vt_number); + } + + close (active_vt_tty_fd); + } + ++static void ++gdm_session_worker_set_state (GdmSessionWorker *worker, ++ GdmSessionWorkerState state) ++{ ++ if (worker->priv->state == state) ++ return; ++ ++ worker->priv->state = state; ++ g_object_notify (G_OBJECT (worker), "state"); ++} ++ + static void + gdm_session_worker_uninitialize_pam (GdmSessionWorker *worker, + int status) + { + g_debug ("GdmSessionWorker: uninitializing PAM"); + + if (worker->priv->pam_handle == NULL) + return; + + gdm_session_worker_get_username (worker, NULL); + + if (worker->priv->state >= GDM_SESSION_WORKER_STATE_SESSION_OPENED) { + pam_close_session (worker->priv->pam_handle, 0); + gdm_session_auditor_report_logout (worker->priv->auditor); + } else { + gdm_session_auditor_report_login_failure (worker->priv->auditor, + status, + pam_strerror (worker->priv->pam_handle, status)); + } + + if (worker->priv->state >= GDM_SESSION_WORKER_STATE_ACCREDITED) { + pam_setcred (worker->priv->pam_handle, PAM_DELETE_CRED); + } + + pam_end (worker->priv->pam_handle, status); + worker->priv->pam_handle = NULL; + + gdm_session_worker_stop_auditor (worker); + + if (g_strcmp0 (worker->priv->display_seat_id, "seat0") == 0) { + if (worker->priv->login_vt != worker->priv->session_vt) { + jump_to_vt (worker, worker->priv->login_vt); + } + } + + worker->priv->login_vt = 0; + worker->priv->session_vt = 0; + + g_debug ("GdmSessionWorker: state NONE"); +- worker->priv->state = GDM_SESSION_WORKER_STATE_NONE; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_NONE); + } + + static char * + _get_tty_for_pam (const char *x11_display_name, + const char *display_device) + { + #ifdef __sun + return g_strdup (display_device); + #else + return g_strdup (x11_display_name); + #endif + } + + #ifdef PAM_XAUTHDATA + static struct pam_xauth_data * + _get_xauth_for_pam (const char *x11_authority_file) + { + FILE *fh; + Xauth *auth = NULL; + struct pam_xauth_data *retval = NULL; + gsize len = sizeof (*retval) + 1; + + fh = fopen (x11_authority_file, "r"); + if (fh) { + auth = XauReadAuth (fh); + fclose (fh); + } + if (auth) { + len += auth->name_length + auth->data_length; + retval = g_malloc0 (len); +@@ -1168,61 +1180,61 @@ gdm_session_worker_initialize_pam (GdmSessionWorker *worker, + goto out; + } + } + + /* set RHOST */ + if (hostname != NULL && hostname[0] != '\0') { + error_code = pam_set_item (worker->priv->pam_handle, PAM_RHOST, hostname); + g_debug ("error informing authentication system of user's hostname %s: %s", + hostname, + pam_strerror (worker->priv->pam_handle, error_code)); + + if (error_code != PAM_SUCCESS) { + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_AUTHENTICATING, + "%s", ""); + goto out; + } + } + + /* set seat ID */ + if (seat_id != NULL && seat_id[0] != '\0') { + gdm_session_worker_set_environment_variable (worker, "XDG_SEAT", seat_id); + } + + if (strcmp (service, "gdm-launch-environment") == 0) { + gdm_session_worker_set_environment_variable (worker, "XDG_SESSION_CLASS", "greeter"); + } + + g_debug ("GdmSessionWorker: state SETUP_COMPLETE"); +- worker->priv->state = GDM_SESSION_WORKER_STATE_SETUP_COMPLETE; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE); + + /* Temporarily set PAM_TTY with the currently active VT (login screen) + PAM_TTY will be reset with the users VT right before the user session is opened */ + ensure_login_vt (worker); + g_snprintf (tty_string, 256, "/dev/tty%d", worker->priv->login_vt); + pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string); + if (!display_is_local) + worker->priv->password_is_required = TRUE; + + out: + if (error_code != PAM_SUCCESS) { + gdm_session_worker_uninitialize_pam (worker, error_code); + return FALSE; + } + + return TRUE; + } + + static gboolean + gdm_session_worker_authenticate_user (GdmSessionWorker *worker, + gboolean password_is_required, + GError **error) + { + int error_code; + int authentication_flags; + + g_debug ("GdmSessionWorker: authenticating user %s", worker->priv->username); + + authentication_flags = 0; + +@@ -1233,61 +1245,61 @@ gdm_session_worker_authenticate_user (GdmSessionWorker *worker, + /* blocking call, does the actual conversation */ + error_code = pam_authenticate (worker->priv->pam_handle, authentication_flags); + + if (error_code == PAM_AUTHINFO_UNAVAIL) { + g_debug ("GdmSessionWorker: authentication service unavailable"); + + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE, + "%s", ""); + goto out; + } else if (error_code != PAM_SUCCESS) { + g_debug ("GdmSessionWorker: authentication returned %d: %s", error_code, pam_strerror (worker->priv->pam_handle, error_code)); + + /* + * Do not display a different message for user unknown versus + * a failed password for a valid user. + */ + if (error_code == PAM_USER_UNKNOWN) { + error_code = PAM_AUTH_ERR; + } + + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_AUTHENTICATING, + "%s", get_friendly_error_message (error_code)); + goto out; + } + + g_debug ("GdmSessionWorker: state AUTHENTICATED"); +- worker->priv->state = GDM_SESSION_WORKER_STATE_AUTHENTICATED; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_AUTHENTICATED); + + out: + if (error_code != PAM_SUCCESS) { + gdm_session_worker_uninitialize_pam (worker, error_code); + return FALSE; + } + + return TRUE; + } + + static gboolean + gdm_session_worker_authorize_user (GdmSessionWorker *worker, + gboolean password_is_required, + GError **error) + { + int error_code; + int authentication_flags; + + g_debug ("GdmSessionWorker: determining if authenticated user (password required:%d) is authorized to session", + password_is_required); + + authentication_flags = 0; + + if (password_is_required) { + authentication_flags |= PAM_DISALLOW_NULL_AUTHTOK; + } + + /* check that the account isn't disabled or expired + */ + error_code = pam_acct_mgmt (worker->priv->pam_handle, authentication_flags); +@@ -1298,61 +1310,61 @@ gdm_session_worker_authorize_user (GdmSessionWorker *worker, + g_debug ("GdmSessionWorker: authenticated user requires new auth token"); + error_code = pam_chauthtok (worker->priv->pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK); + + gdm_session_worker_get_username (worker, NULL); + + if (error_code != PAM_SUCCESS) { + gdm_session_auditor_report_password_change_failure (worker->priv->auditor); + } else { + gdm_session_auditor_report_password_changed (worker->priv->auditor); + } + } + + /* If the user is reauthenticating, then authorization isn't required to + * proceed, the user is already logged in after all. + */ + if (worker->priv->is_reauth_session) { + error_code = PAM_SUCCESS; + } + + if (error_code != PAM_SUCCESS) { + g_debug ("GdmSessionWorker: user is not authorized to log in: %s", + pam_strerror (worker->priv->pam_handle, error_code)); + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_AUTHORIZING, + "%s", get_friendly_error_message (error_code)); + goto out; + } + + g_debug ("GdmSessionWorker: state AUTHORIZED"); +- worker->priv->state = GDM_SESSION_WORKER_STATE_AUTHORIZED; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_AUTHORIZED); + + out: + if (error_code != PAM_SUCCESS) { + gdm_session_worker_uninitialize_pam (worker, error_code); + return FALSE; + } + + return TRUE; + } + + static void + gdm_session_worker_set_environment_variable (GdmSessionWorker *worker, + const char *key, + const char *value) + { + int error_code; + char *environment_entry; + + if (value != NULL) { + environment_entry = g_strdup_printf ("%s=%s", key, value); + } else { + /* empty value means "remove from environment" */ + environment_entry = g_strdup (key); + } + + error_code = pam_putenv (worker->priv->pam_handle, + environment_entry); + + if (error_code != PAM_SUCCESS) { + g_warning ("cannot put %s in pam environment: %s\n", +@@ -1710,61 +1722,61 @@ gdm_session_worker_accredit_user (GdmSessionWorker *worker, + + /* If the user is reauthenticating and they've made it this far, then there + * is no reason we should lock them out of their session. They've already + * proved they are they same person who logged in, and that's all we care + * about. + */ + if (worker->priv->is_reauth_session) { + error_code = PAM_SUCCESS; + } + + if (error_code != PAM_SUCCESS) { + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_GIVING_CREDENTIALS, + "%s", + pam_strerror (worker->priv->pam_handle, error_code)); + goto out; + } + + ret = TRUE; + + out: + g_free (home); + g_free (shell); + if (ret) { + g_debug ("GdmSessionWorker: state ACCREDITED"); + ret = TRUE; + + gdm_session_worker_get_username (worker, NULL); + gdm_session_auditor_report_user_accredited (worker->priv->auditor); +- worker->priv->state = GDM_SESSION_WORKER_STATE_ACCREDITED; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_ACCREDITED); + } else { + gdm_session_worker_uninitialize_pam (worker, error_code); + } + + return ret; + } + + static const char * const * + gdm_session_worker_get_environment (GdmSessionWorker *worker) + { + return (const char * const *) pam_getenvlist (worker->priv->pam_handle); + } + + static gboolean + run_script (GdmSessionWorker *worker, + const char *dir) + { + /* scripts are for non-program sessions only */ + if (worker->priv->is_program_session) { + return TRUE; + } + + return gdm_run_script (dir, + worker->priv->username, + worker->priv->x11_display_name, + worker->priv->display_is_local? NULL : worker->priv->hostname, + worker->priv->x11_authority_file); + } + + static void +@@ -2154,61 +2166,61 @@ gdm_session_worker_start_session (GdmSessionWorker *worker, + (char **) + environment, + TRUE); + + gdm_log_init (); + g_debug ("GdmSessionWorker: child '%s' could not be started: %s", + worker->priv->arguments[0], + g_strerror (errno)); + + _exit (EXIT_FAILURE); + } + + if (worker->priv->session_tty_fd > 0) { + close (worker->priv->session_tty_fd); + worker->priv->session_tty_fd = -1; + } + + /* If we end up execing again, make sure we don't use the executable context set up + * by pam_selinux durin pam_open_session + */ + #ifdef HAVE_SELINUX + setexeccon (NULL); + #endif + + worker->priv->child_pid = session_pid; + + g_debug ("GdmSessionWorker: session opened creating reply..."); + g_assert (sizeof (GPid) <= sizeof (int)); + + g_debug ("GdmSessionWorker: state SESSION_STARTED"); +- worker->priv->state = GDM_SESSION_WORKER_STATE_SESSION_STARTED; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SESSION_STARTED); + + gdm_session_worker_watch_child (worker); + + out: + if (error_code != PAM_SUCCESS) { + gdm_session_worker_uninitialize_pam (worker, error_code); + return FALSE; + } + + return TRUE; + } + + static gboolean + set_up_for_new_vt (GdmSessionWorker *worker) + { + int fd; + char vt_string[256], tty_string[256]; + int session_vt = 0; + + fd = open ("/dev/tty0", O_RDWR | O_NOCTTY); + + if (fd < 0) { + g_debug ("GdmSessionWorker: couldn't open VT master: %m"); + return FALSE; + } + + if (worker->priv->display_is_initial) { + session_vt = atoi (GDM_INITIAL_VT); + } else { + if (ioctl(fd, VT_OPENQRY, &session_vt) < 0) { +@@ -2377,61 +2389,61 @@ gdm_session_worker_open_session (GdmSessionWorker *worker, + break; + case GDM_SESSION_DISPLAY_MODE_NEW_VT: + case GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED: + if (!set_up_for_new_vt (worker)) { + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_OPENING_SESSION, + "Unable to open VT"); + return FALSE; + } + break; + } + + flags = 0; + + if (worker->priv->is_program_session) { + flags |= PAM_SILENT; + } + + error_code = pam_open_session (worker->priv->pam_handle, flags); + + if (error_code != PAM_SUCCESS) { + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_OPENING_SESSION, + "%s", pam_strerror (worker->priv->pam_handle, error_code)); + goto out; + } + + g_debug ("GdmSessionWorker: state SESSION_OPENED"); +- worker->priv->state = GDM_SESSION_WORKER_STATE_SESSION_OPENED; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SESSION_OPENED); + + session_id = gdm_session_worker_get_environment_variable (worker, "XDG_SESSION_ID"); + + if (session_id != NULL) { + g_free (worker->priv->session_id); + worker->priv->session_id = session_id; + } + + out: + if (error_code != PAM_SUCCESS) { + gdm_session_worker_uninitialize_pam (worker, error_code); + return FALSE; + } + + gdm_session_worker_get_username (worker, NULL); + gdm_session_auditor_report_login (worker->priv->auditor); + + return TRUE; + } + + static void + gdm_session_worker_set_server_address (GdmSessionWorker *worker, + const char *address) + { + g_free (worker->priv->server_address); + worker->priv->server_address = g_strdup (address); + } + + static void + gdm_session_worker_set_is_reauth_session (GdmSessionWorker *worker, +@@ -2454,61 +2466,61 @@ gdm_session_worker_set_property (GObject *object, + case PROP_SERVER_ADDRESS: + gdm_session_worker_set_server_address (self, g_value_get_string (value)); + break; + case PROP_IS_REAUTH_SESSION: + gdm_session_worker_set_is_reauth_session (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } + + static void + gdm_session_worker_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) + { + GdmSessionWorker *self; + + self = GDM_SESSION_WORKER (object); + + switch (prop_id) { + case PROP_SERVER_ADDRESS: + g_value_set_string (value, self->priv->server_address); + break; + case PROP_IS_REAUTH_SESSION: + g_value_set_boolean (value, self->priv->is_reauth_session); + break; + case PROP_STATE: +- g_value_set_int (value, self->priv->state); ++ g_value_set_enum (value, self->priv->state); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } + + static gboolean + gdm_session_worker_handle_set_environment_variable (GdmDBusWorker *object, + GDBusMethodInvocation *invocation, + const char *key, + const char *value) + { + GdmSessionWorker *worker = GDM_SESSION_WORKER (object); + gdm_session_worker_set_environment_variable (worker, key, value); + gdm_dbus_worker_complete_set_environment_variable (object, invocation); + return TRUE; + } + + static gboolean + gdm_session_worker_handle_set_session_name (GdmDBusWorker *object, + GDBusMethodInvocation *invocation, + const char *session_name) + { + GdmSessionWorker *worker = GDM_SESSION_WORKER (object); + g_debug ("GdmSessionWorker: session name set to %s", session_name); + gdm_session_settings_set_session_name (worker->priv->user_settings, + session_name); + gdm_dbus_worker_complete_set_session_name (object, invocation); + return TRUE; +@@ -2639,61 +2651,61 @@ do_authorize (GdmSessionWorker *worker) + g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error); + } + worker->priv->pending_invocation = NULL; + } + + static void + do_accredit (GdmSessionWorker *worker) + { + GError *error; + gboolean res; + + /* get kerberos tickets, setup group lists, etc + */ + error = NULL; + res = gdm_session_worker_accredit_user (worker, &error); + + if (res) { + gdm_dbus_worker_complete_establish_credentials (GDM_DBUS_WORKER (worker), worker->priv->pending_invocation); + } else { + g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error); + } + worker->priv->pending_invocation = NULL; + } + + static void + save_account_details_now (GdmSessionWorker *worker) + { + g_assert (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCREDITED); + + g_debug ("GdmSessionWorker: saving account details for user %s", worker->priv->username); +- worker->priv->state = GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED); + if (!gdm_session_settings_save (worker->priv->user_settings, + worker->priv->username)) { + g_warning ("could not save session and language settings"); + } + queue_state_change (worker); + } + + static void + on_settings_is_loaded_changed (GdmSessionSettings *user_settings, + GParamSpec *pspec, + GdmSessionWorker *worker) + { + if (!gdm_session_settings_is_loaded (worker->priv->user_settings)) { + return; + } + + /* These signal handlers should be disconnected after the loading, + * so that gdm_session_settings_set_* APIs don't cause the emitting + * of Saved*NameRead D-Bus signals any more. + */ + g_signal_handlers_disconnect_by_func (worker->priv->user_settings, + G_CALLBACK (on_saved_session_name_read), + worker); + + g_signal_handlers_disconnect_by_func (worker->priv->user_settings, + G_CALLBACK (on_saved_language_name_read), + worker); + + if (worker->priv->state == GDM_SESSION_WORKER_STATE_NONE) { + g_debug ("GdmSessionWorker: queuing setup for user: %s %s", +@@ -3443,60 +3455,68 @@ worker_interface_init (GdmDBusWorkerIface *interface) + interface->handle_start_reauthentication = gdm_session_worker_handle_start_reauthentication; + } + + static void + gdm_session_worker_class_init (GdmSessionWorkerClass *klass) + { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = gdm_session_worker_get_property; + object_class->set_property = gdm_session_worker_set_property; + object_class->constructor = gdm_session_worker_constructor; + object_class->finalize = gdm_session_worker_finalize; + + g_type_class_add_private (klass, sizeof (GdmSessionWorkerPrivate)); + + g_object_class_install_property (object_class, + PROP_SERVER_ADDRESS, + g_param_spec_string ("server-address", + "server address", + "server address", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, + PROP_IS_REAUTH_SESSION, + g_param_spec_boolean ("is-reauth-session", + "is reauth session", + "is reauth session", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); ++ g_object_class_install_property (object_class, ++ PROP_STATE, ++ g_param_spec_enum ("state", ++ "state", ++ "state", ++ GDM_TYPE_SESSION_WORKER_STATE, ++ GDM_SESSION_WORKER_STATE_NONE, ++ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + } + + static void + reauthentication_request_free (ReauthenticationRequest *request) + { + + g_signal_handlers_disconnect_by_func (request->session, + G_CALLBACK (on_reauthentication_client_connected), + request); + g_signal_handlers_disconnect_by_func (request->session, + G_CALLBACK (on_reauthentication_client_disconnected), + request); + g_signal_handlers_disconnect_by_func (request->session, + G_CALLBACK (on_reauthentication_cancelled), + request); + g_signal_handlers_disconnect_by_func (request->session, + G_CALLBACK (on_reauthentication_conversation_started), + request); + g_signal_handlers_disconnect_by_func (request->session, + G_CALLBACK (on_reauthentication_conversation_stopped), + request); + g_signal_handlers_disconnect_by_func (request->session, + G_CALLBACK (on_reauthentication_verification_complete), + request); + g_clear_object (&request->session); + g_slice_free (ReauthenticationRequest, request); + } + + static void + gdm_session_worker_init (GdmSessionWorker *worker) +diff --git a/daemon/session-worker-main.c b/daemon/session-worker-main.c +index 4a3a8ebbe..d96844d2d 100644 +--- a/daemon/session-worker-main.c ++++ b/daemon/session-worker-main.c +@@ -37,104 +37,137 @@ + #include + + #include "gdm-common.h" + #include "gdm-log.h" + #include "gdm-session-worker.h" + + #include "gdm-settings.h" + #include "gdm-settings-direct.h" + #include "gdm-settings-keys.h" + + static GdmSettings *settings = NULL; + + static gboolean + on_sigusr1_cb (gpointer user_data) + { + g_debug ("Got USR1 signal"); + + gdm_log_toggle_debug (); + + return TRUE; + } + + static gboolean + is_debug_set (void) + { + gboolean debug; + gdm_settings_direct_get_boolean (GDM_KEY_DEBUG, &debug); + return debug; + } + ++static gboolean ++on_shutdown_signal_cb (gpointer user_data) ++{ ++ GMainLoop *mainloop = user_data; ++ ++ g_main_loop_quit (mainloop); ++ ++ return FALSE; ++} ++ ++static void ++on_state_changed (GdmSessionWorker *worker, ++ GParamSpec *pspec, ++ GMainLoop *main_loop) ++{ ++ GdmSessionWorkerState state; ++ ++ g_object_get (G_OBJECT (worker), "state", &state, NULL); ++ ++ if (state != GDM_SESSION_WORKER_STATE_SESSION_STARTED) ++ return; ++ ++ g_unix_signal_add (SIGTERM, on_shutdown_signal_cb, main_loop); ++} ++ + static void + on_sigterm_cb (int signal_number) + { + _exit (EXIT_SUCCESS); + } + + int + main (int argc, + char **argv) + { + GMainLoop *main_loop; + GOptionContext *context; + GdmSessionWorker *worker; + const char *address; + gboolean is_for_reauth; + static GOptionEntry entries [] = { + { NULL } + }; + + signal (SIGTERM, on_sigterm_cb); + + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + textdomain (GETTEXT_PACKAGE); + setlocale (LC_ALL, ""); + + /* Translators: worker is a helper process that does the work + of starting up a session */ + context = g_option_context_new (_("GNOME Display Manager Session Worker")); + g_option_context_add_main_entries (context, entries, NULL); + + g_option_context_parse (context, &argc, &argv, NULL); + g_option_context_free (context); + + gdm_log_init (); + + settings = gdm_settings_new (); + if (settings == NULL) { + g_warning ("Unable to initialize settings"); + exit (EXIT_FAILURE); + } + + if (! gdm_settings_direct_init (settings, DATADIR "/gdm/gdm.schemas", "/")) { + g_warning ("Unable to initialize settings"); + exit (EXIT_FAILURE); + } + + gdm_log_set_debug (is_debug_set ()); + + address = g_getenv ("GDM_SESSION_DBUS_ADDRESS"); + if (address == NULL) { + g_warning ("GDM_SESSION_DBUS_ADDRESS not set"); + exit (EXIT_FAILURE); + } + + is_for_reauth = g_getenv ("GDM_SESSION_FOR_REAUTH") != NULL; + + worker = gdm_session_worker_new (address, is_for_reauth); + + main_loop = g_main_loop_new (NULL, FALSE); + ++ g_signal_connect (G_OBJECT (worker), ++ "notify::state", ++ G_CALLBACK (on_state_changed), ++ main_loop); ++ + g_unix_signal_add (SIGUSR1, on_sigusr1_cb, NULL); + + g_main_loop_run (main_loop); + + if (worker != NULL) { ++ g_signal_handlers_disconnect_by_func (worker, ++ G_CALLBACK (on_state_changed), ++ main_loop); + g_object_unref (worker); + } + + g_main_loop_unref (main_loop); + + g_debug ("Worker finished"); + + return 0; + } +-- +2.21.0 + diff --git a/SOURCES/0003-session-worker-uninitialize-pam-if-worker-is-killed.patch b/SOURCES/0003-session-worker-uninitialize-pam-if-worker-is-killed.patch new file mode 100644 index 0000000..cc51497 --- /dev/null +++ b/SOURCES/0003-session-worker-uninitialize-pam-if-worker-is-killed.patch @@ -0,0 +1,85 @@ +From db99c5181950f6f383b75e9956e170d3b2762d15 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Mon, 24 Jun 2019 16:21:59 -0400 +Subject: [PATCH 3/7] session-worker: uninitialize pam if worker is killed + +Right nowe don't uninitialize pam or switch back to the +starting VT if the worker is killed before the session. + +This commit fixes that. +--- + daemon/gdm-session-worker.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c +index e526fa5db..f9bc82177 100644 +--- a/daemon/gdm-session-worker.c ++++ b/daemon/gdm-session-worker.c +@@ -3534,60 +3534,64 @@ gdm_session_worker_init (GdmSessionWorker *worker) + static void + gdm_session_worker_unwatch_child (GdmSessionWorker *worker) + { + if (worker->priv->child_watch_id == 0) + return; + + g_source_remove (worker->priv->child_watch_id); + worker->priv->child_watch_id = 0; + } + + + static void + gdm_session_worker_finalize (GObject *object) + { + GdmSessionWorker *worker; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_SESSION_WORKER (object)); + + worker = GDM_SESSION_WORKER (object); + + g_return_if_fail (worker->priv != NULL); + + gdm_session_worker_unwatch_child (worker); + + if (worker->priv->child_pid > 0) { + gdm_signal_pid (worker->priv->child_pid, SIGTERM); + gdm_wait_on_pid (worker->priv->child_pid); + } + ++ if (worker->priv->pam_handle != NULL) { ++ gdm_session_worker_uninitialize_pam (worker, PAM_SUCCESS); ++ } ++ + g_object_unref (worker->priv->user_settings); + g_free (worker->priv->service); + g_free (worker->priv->x11_display_name); + g_free (worker->priv->x11_authority_file); + g_free (worker->priv->display_device); + g_free (worker->priv->display_seat_id); + g_free (worker->priv->hostname); + g_free (worker->priv->username); + g_free (worker->priv->server_address); + g_strfreev (worker->priv->arguments); + g_strfreev (worker->priv->extensions); + + g_hash_table_unref (worker->priv->reauthentication_requests); + + G_OBJECT_CLASS (gdm_session_worker_parent_class)->finalize (object); + } + + GdmSessionWorker * + gdm_session_worker_new (const char *address, + gboolean is_reauth_session) + { + GObject *object; + + object = g_object_new (GDM_TYPE_SESSION_WORKER, + "server-address", address, + "is-reauth-session", is_reauth_session, + NULL); + + return GDM_SESSION_WORKER (object); + } +-- +2.21.0 + diff --git a/SOURCES/0004-gdm-session-worker-Drop-login_vt-assuming-it-is-GDM_.patch b/SOURCES/0004-gdm-session-worker-Drop-login_vt-assuming-it-is-GDM_.patch new file mode 100644 index 0000000..6802d64 --- /dev/null +++ b/SOURCES/0004-gdm-session-worker-Drop-login_vt-assuming-it-is-GDM_.patch @@ -0,0 +1,363 @@ +From 753da4320f01ec5486371eddc4c98f50d86dbef9 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 25 Sep 2019 14:51:40 +0200 +Subject: [PATCH 4/7] gdm-session-worker: Drop login_vt assuming it is + GDM_INITIAL_VT + +When a session ends, its "session worker" is closed. Since +3e8220921bb608afd06ed677104fd2244b901a28 (3.33.4), we uninitialise PAM +when this happens. As part of this procedure, we jump back to the login +screen, if the screen being killed is not itself the login screen. + +This has broken fast user switching. It goes like this - this +explanation is a bit complicated, bear with us: + +We want to jump back to the login screen when a normal user session +ends, so that people can log in again. We do not want to do this when a +login screen itself ends. When session workers start up, they query for +the *currently active VT* and save this in `login_vt`. Then later on, we +check if our session ID is the same as `login_vt`, and jump to +`login_vt` if they are different - this means that it was a user session +not a login session. Querying the currently active VT is fine for the +first greeter, but when initiating a user switch it's wrong as this +gives the user VT. + +GDM greeters are killed once they have spawned a session. They are +associated with a logind session, and therefore a PAM session. There are +some actions performed when unregistering PAM sessions, including the +previously mentioned VT jump. Before +3e8220921bb608afd06ed677104fd2244b901a28 we only uninitialised PAM when +the session itself exited so the bug was masked, but now (since this +commit), if the login screen's *worker* exits first - as happens in the +normal case when GDM kills it - we also do this uninitialisation. Since +we falsely recorded the login screen as the first user's VT, this means +that checking `login_vt != session_vt` returns `TRUE` and we jump back +to the previous user's session immediately after logging into the new +session: fast user switching is broken. + +Since the work on shutting down the GDM session has been finished, we +can assume that the login_vt is always on GDM_INITIAL_VT (see +example c71bc5d6c3bc2ec448b5c72ce9a811d9c0c7905e +"local-display-factory: Remove initial VT is in use check" and +39fb4ff64e6a0653e70a3bfab31da47b49227d59 "manager: don't run autologin +display on tty1"). So simply replace all usages of login_vt with +GDM_INITIAL_VT to solve the above problem. + +Note that in the case where ENABLE_USER_DISPLAY_SERVER is not enabled, +the login_vt is always the same as the session_vt. We can simply remove +the VT switching magic there and everything should be working as +expected. + +This is a simpler version of the patch by Iain Lane , +taking into account that we can make the assumption about the login_vt. + +Closes #515 +--- + daemon/gdm-session-worker.c | 47 ++++++++++--------------------------- + 1 file changed, 12 insertions(+), 35 deletions(-) + +diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c +index f9bc82177..07117d857 100644 +--- a/daemon/gdm-session-worker.c ++++ b/daemon/gdm-session-worker.c +@@ -119,61 +119,60 @@ typedef struct + + } ReauthenticationRequest; + + struct GdmSessionWorkerPrivate + { + GdmSessionWorkerState state; + + int exit_code; + + pam_handle_t *pam_handle; + + GPid child_pid; + guint child_watch_id; + + /* from Setup */ + char *service; + char *x11_display_name; + char *x11_authority_file; + char *display_device; + char *display_seat_id; + char *hostname; + char *username; + char *log_file; + char *session_id; + uid_t uid; + gid_t gid; + gboolean password_is_required; + char **extensions; + + int cred_flags; +- int login_vt; + int session_vt; + int session_tty_fd; + + char **arguments; + guint32 cancelled : 1; + guint32 timed_out : 1; + guint32 is_program_session : 1; + guint32 is_reauth_session : 1; + guint32 display_is_local : 1; + guint32 display_is_initial : 1; + guint state_change_idle_id; + GdmSessionDisplayMode display_mode; + + char *server_address; + GDBusConnection *connection; + GdmDBusWorkerManager *manager; + + GHashTable *reauthentication_requests; + + GdmSessionAuditor *auditor; + GdmSessionSettings *user_settings; + + GDBusMethodInvocation *pending_invocation; + }; + + #ifdef SUPPORTS_PAM_EXTENSIONS + static char gdm_pam_extension_environment_block[_POSIX_ARG_MAX]; + + static const char * const + gdm_supported_pam_extensions[] = { +@@ -1007,157 +1006,137 @@ gdm_session_worker_set_state (GdmSessionWorker *worker, + + static void + gdm_session_worker_uninitialize_pam (GdmSessionWorker *worker, + int status) + { + g_debug ("GdmSessionWorker: uninitializing PAM"); + + if (worker->priv->pam_handle == NULL) + return; + + gdm_session_worker_get_username (worker, NULL); + + if (worker->priv->state >= GDM_SESSION_WORKER_STATE_SESSION_OPENED) { + pam_close_session (worker->priv->pam_handle, 0); + gdm_session_auditor_report_logout (worker->priv->auditor); + } else { + gdm_session_auditor_report_login_failure (worker->priv->auditor, + status, + pam_strerror (worker->priv->pam_handle, status)); + } + + if (worker->priv->state >= GDM_SESSION_WORKER_STATE_ACCREDITED) { + pam_setcred (worker->priv->pam_handle, PAM_DELETE_CRED); + } + + pam_end (worker->priv->pam_handle, status); + worker->priv->pam_handle = NULL; + + gdm_session_worker_stop_auditor (worker); + ++ /* If user-display-server is not enabled the login_vt is always ++ * identical to the session_vt. So in that case we never need to ++ * do a VT switch. */ ++#ifdef ENABLE_USER_DISPLAY_SERVER + if (g_strcmp0 (worker->priv->display_seat_id, "seat0") == 0) { +- if (worker->priv->login_vt != worker->priv->session_vt) { +- jump_to_vt (worker, worker->priv->login_vt); ++ int initial_vt = atoi (GDM_INITIAL_VT); ++ ++ /* Switch to the login VT if we are not the login screen. */ ++ if (worker->priv->session_vt != initial_vt) { ++ jump_to_vt (worker, initial_vt); + } + } ++#endif + +- worker->priv->login_vt = 0; + worker->priv->session_vt = 0; + + g_debug ("GdmSessionWorker: state NONE"); + gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_NONE); + } + + static char * + _get_tty_for_pam (const char *x11_display_name, + const char *display_device) + { + #ifdef __sun + return g_strdup (display_device); + #else + return g_strdup (x11_display_name); + #endif + } + + #ifdef PAM_XAUTHDATA + static struct pam_xauth_data * + _get_xauth_for_pam (const char *x11_authority_file) + { + FILE *fh; + Xauth *auth = NULL; + struct pam_xauth_data *retval = NULL; + gsize len = sizeof (*retval) + 1; + + fh = fopen (x11_authority_file, "r"); + if (fh) { + auth = XauReadAuth (fh); + fclose (fh); + } + if (auth) { + len += auth->name_length + auth->data_length; + retval = g_malloc0 (len); + } + if (retval) { + retval->namelen = auth->name_length; + retval->name = (char *) (retval + 1); + memcpy (retval->name, auth->name, auth->name_length); + retval->datalen = auth->data_length; + retval->data = retval->name + auth->name_length + 1; + memcpy (retval->data, auth->data, auth->data_length); + } + XauDisposeAuth (auth); + return retval; + } + #endif + +-static gboolean +-ensure_login_vt (GdmSessionWorker *worker) +-{ +- int fd; +- struct vt_stat vt_state = { 0 }; +- gboolean got_login_vt = FALSE; +- +- fd = open ("/dev/tty0", O_RDWR | O_NOCTTY); +- +- if (fd < 0) { +- g_debug ("GdmSessionWorker: couldn't open VT master: %m"); +- return FALSE; +- } +- +- if (ioctl (fd, VT_GETSTATE, &vt_state) < 0) { +- g_debug ("GdmSessionWorker: couldn't get current VT: %m"); +- goto out; +- } +- +- worker->priv->login_vt = vt_state.v_active; +- got_login_vt = TRUE; +-out: +- close (fd); +- return got_login_vt; +-} +- + static gboolean + gdm_session_worker_initialize_pam (GdmSessionWorker *worker, + const char *service, + const char * const *extensions, + const char *username, + const char *hostname, + gboolean display_is_local, + const char *x11_display_name, + const char *x11_authority_file, + const char *display_device, + const char *seat_id, + GError **error) + { + struct pam_conv pam_conversation; + int error_code; +- char tty_string[256]; + + g_assert (worker->priv->pam_handle == NULL); + + g_debug ("GdmSessionWorker: initializing PAM; service=%s username=%s seat=%s", + service ? service : "(null)", + username ? username : "(null)", + seat_id ? seat_id : "(null)"); + + #ifdef SUPPORTS_PAM_EXTENSIONS + if (extensions != NULL) { + GDM_PAM_EXTENSION_ADVERTISE_SUPPORTED_EXTENSIONS (gdm_pam_extension_environment_block, extensions); + } + #endif + + pam_conversation.conv = (GdmSessionWorkerPamNewMessagesFunc) gdm_session_worker_pam_new_messages_handler; + pam_conversation.appdata_ptr = worker; + + gdm_session_worker_start_auditor (worker); + error_code = pam_start (service, + username, + &pam_conversation, + &worker->priv->pam_handle); + if (error_code != PAM_SUCCESS) { + g_debug ("GdmSessionWorker: could not initialize PAM: (error code %d)", error_code); + /* we don't use pam_strerror here because it requires a valid + * pam handle, and if pam_start fails pam_handle is undefined + */ + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE, +@@ -1182,65 +1161,63 @@ gdm_session_worker_initialize_pam (GdmSessionWorker *worker, + } + + /* set RHOST */ + if (hostname != NULL && hostname[0] != '\0') { + error_code = pam_set_item (worker->priv->pam_handle, PAM_RHOST, hostname); + g_debug ("error informing authentication system of user's hostname %s: %s", + hostname, + pam_strerror (worker->priv->pam_handle, error_code)); + + if (error_code != PAM_SUCCESS) { + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_AUTHENTICATING, + "%s", ""); + goto out; + } + } + + /* set seat ID */ + if (seat_id != NULL && seat_id[0] != '\0') { + gdm_session_worker_set_environment_variable (worker, "XDG_SEAT", seat_id); + } + + if (strcmp (service, "gdm-launch-environment") == 0) { + gdm_session_worker_set_environment_variable (worker, "XDG_SESSION_CLASS", "greeter"); + } + + g_debug ("GdmSessionWorker: state SETUP_COMPLETE"); + gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE); + +- /* Temporarily set PAM_TTY with the currently active VT (login screen) ++ /* Temporarily set PAM_TTY with the login VT, + PAM_TTY will be reset with the users VT right before the user session is opened */ +- ensure_login_vt (worker); +- g_snprintf (tty_string, 256, "/dev/tty%d", worker->priv->login_vt); +- pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string); ++ pam_set_item (worker->priv->pam_handle, PAM_TTY, "/dev/tty" GDM_INITIAL_VT); + if (!display_is_local) + worker->priv->password_is_required = TRUE; + + out: + if (error_code != PAM_SUCCESS) { + gdm_session_worker_uninitialize_pam (worker, error_code); + return FALSE; + } + + return TRUE; + } + + static gboolean + gdm_session_worker_authenticate_user (GdmSessionWorker *worker, + gboolean password_is_required, + GError **error) + { + int error_code; + int authentication_flags; + + g_debug ("GdmSessionWorker: authenticating user %s", worker->priv->username); + + authentication_flags = 0; + + if (password_is_required) { + authentication_flags |= PAM_DISALLOW_NULL_AUTHTOK; + } + + /* blocking call, does the actual conversation */ + error_code = pam_authenticate (worker->priv->pam_handle, authentication_flags); +-- +2.21.0 + diff --git a/SOURCES/0005-display-factory-avoid-removing-a-display-from-store-.patch b/SOURCES/0005-display-factory-avoid-removing-a-display-from-store-.patch new file mode 100644 index 0000000..3e64d10 --- /dev/null +++ b/SOURCES/0005-display-factory-avoid-removing-a-display-from-store-.patch @@ -0,0 +1,454 @@ +From b322fd907ef49a77a11ed6e5b9c858a7dd43d064 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Tue, 17 Jul 2018 20:20:55 +0000 +Subject: [PATCH 5/7] display-factory: avoid removing a display from store + while iterating it + +--- + daemon/gdm-display-factory.c | 41 ++++++++++++++++++++++++++++++ + daemon/gdm-display-factory.h | 1 + + daemon/gdm-local-display-factory.c | 7 ++--- + daemon/gdm-xdmcp-display-factory.c | 7 ++--- + 4 files changed, 46 insertions(+), 10 deletions(-) + +diff --git a/daemon/gdm-display-factory.c b/daemon/gdm-display-factory.c +index d86a4c8ad..c520e1088 100644 +--- a/daemon/gdm-display-factory.c ++++ b/daemon/gdm-display-factory.c +@@ -8,84 +8,120 @@ + * (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 "gdm-display-factory.h" + #include "gdm-display-store.h" + + #define GDM_DISPLAY_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DISPLAY_FACTORY, GdmDisplayFactoryPrivate)) + + struct GdmDisplayFactoryPrivate + { + GdmDisplayStore *display_store; ++ guint purge_displays_id; + }; + + enum { + PROP_0, + PROP_DISPLAY_STORE, + }; + + static void gdm_display_factory_class_init (GdmDisplayFactoryClass *klass); + static void gdm_display_factory_init (GdmDisplayFactory *factory); + static void gdm_display_factory_finalize (GObject *object); + + G_DEFINE_ABSTRACT_TYPE (GdmDisplayFactory, gdm_display_factory, G_TYPE_OBJECT) + + GQuark + gdm_display_factory_error_quark (void) + { + static GQuark ret = 0; + if (ret == 0) { + ret = g_quark_from_static_string ("gdm_display_factory_error"); + } + + return ret; + } + ++static gboolean ++purge_display (char *id, ++ GdmDisplay *display, ++ gpointer user_data) ++{ ++ int status; ++ ++ status = gdm_display_get_status (display); ++ ++ switch (status) { ++ case GDM_DISPLAY_FINISHED: ++ case GDM_DISPLAY_FAILED: ++ return TRUE; ++ default: ++ return FALSE; ++ } ++} ++ ++static void ++purge_displays (GdmDisplayFactory *factory) ++{ ++ factory->priv->purge_displays_id = 0; ++ gdm_display_store_foreach_remove (factory->priv->display_store, ++ (GdmDisplayStoreFunc)purge_display, ++ NULL); ++} ++ ++void ++gdm_display_factory_queue_purge_displays (GdmDisplayFactory *factory) ++{ ++ if (factory->priv->purge_displays_id == 0) { ++ factory->priv->purge_displays_id = g_idle_add ((GSourceFunc) purge_displays, factory); ++ } ++} ++ + GdmDisplayStore * + gdm_display_factory_get_display_store (GdmDisplayFactory *factory) + { + g_return_val_if_fail (GDM_IS_DISPLAY_FACTORY (factory), NULL); + + return factory->priv->display_store; + } + + gboolean + gdm_display_factory_start (GdmDisplayFactory *factory) + { + gboolean ret; + + g_return_val_if_fail (GDM_IS_DISPLAY_FACTORY (factory), FALSE); + + g_object_ref (factory); + ret = GDM_DISPLAY_FACTORY_GET_CLASS (factory)->start (factory); + g_object_unref (factory); + + return ret; + } + + gboolean + gdm_display_factory_stop (GdmDisplayFactory *factory) + { + gboolean ret; + + g_return_val_if_fail (GDM_IS_DISPLAY_FACTORY (factory), FALSE); + + g_object_ref (factory); +@@ -160,32 +196,37 @@ gdm_display_factory_class_init (GdmDisplayFactoryClass *klass) + + g_object_class_install_property (object_class, + PROP_DISPLAY_STORE, + g_param_spec_object ("display-store", + "display store", + "display store", + GDM_TYPE_DISPLAY_STORE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_type_class_add_private (klass, sizeof (GdmDisplayFactoryPrivate)); + } + + static void + gdm_display_factory_init (GdmDisplayFactory *factory) + { + factory->priv = GDM_DISPLAY_FACTORY_GET_PRIVATE (factory); + } + + static void + gdm_display_factory_finalize (GObject *object) + { + GdmDisplayFactory *factory; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_DISPLAY_FACTORY (object)); + + factory = GDM_DISPLAY_FACTORY (object); + + g_return_if_fail (factory->priv != NULL); + ++ if (factory->priv->purge_displays_id != 0) { ++ g_source_remove (factory->priv->purge_displays_id); ++ factory->priv->purge_displays_id = 0; ++ } ++ + G_OBJECT_CLASS (gdm_display_factory_parent_class)->finalize (object); + } +diff --git a/daemon/gdm-display-factory.h b/daemon/gdm-display-factory.h +index 6b30f83dc..1cffa1bd5 100644 +--- a/daemon/gdm-display-factory.h ++++ b/daemon/gdm-display-factory.h +@@ -37,34 +37,35 @@ G_BEGIN_DECLS + + typedef struct GdmDisplayFactoryPrivate GdmDisplayFactoryPrivate; + + typedef struct + { + GObject parent; + GdmDisplayFactoryPrivate *priv; + } GdmDisplayFactory; + + typedef struct + { + GObjectClass parent_class; + + gboolean (*start) (GdmDisplayFactory *factory); + gboolean (*stop) (GdmDisplayFactory *factory); + } GdmDisplayFactoryClass; + + typedef enum + { + GDM_DISPLAY_FACTORY_ERROR_GENERAL + } GdmDisplayFactoryError; + + #define GDM_DISPLAY_FACTORY_ERROR gdm_display_factory_error_quark () + + GQuark gdm_display_factory_error_quark (void); + GType gdm_display_factory_get_type (void); + + gboolean gdm_display_factory_start (GdmDisplayFactory *manager); + gboolean gdm_display_factory_stop (GdmDisplayFactory *manager); + GdmDisplayStore * gdm_display_factory_get_display_store (GdmDisplayFactory *manager); ++void gdm_display_factory_queue_purge_displays (GdmDisplayFactory *manager); + + G_END_DECLS + + #endif /* __GDM_DISPLAY_FACTORY_H */ +diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c +index 6856d30d0..1c7daeb14 100644 +--- a/daemon/gdm-local-display-factory.c ++++ b/daemon/gdm-local-display-factory.c +@@ -224,128 +224,125 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact + "seat-id", "seat0", + "allow-timed-login", FALSE, + NULL); + + store_display (factory, display); + + if (! gdm_display_manage (display)) { + display = NULL; + goto out; + } + + if (! gdm_display_get_id (display, id, NULL)) { + display = NULL; + goto out; + } + + ret = TRUE; + out: + /* ref either held by store or not at all */ + g_object_unref (display); + + return ret; + } + + static void + on_display_status_changed (GdmDisplay *display, + GParamSpec *arg1, + GdmLocalDisplayFactory *factory) + { + int status; +- GdmDisplayStore *store; + int num; + char *seat_id = NULL; + char *session_id = NULL; + char *session_type = NULL; + char *session_class = NULL; + gboolean is_initial = TRUE; + gboolean is_local = TRUE; + int ret; + + num = -1; + gdm_display_get_x11_display_number (display, &num, NULL); + +- store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); +- + g_object_get (display, + "seat-id", &seat_id, + "session-id", &session_id, + "is-initial", &is_initial, + "is-local", &is_local, + "session-type", &session_type, + "session-class", &session_class, + NULL); + + status = gdm_display_get_status (display); + + g_debug ("GdmLocalDisplayFactory: display status changed: %d", status); + switch (status) { + case GDM_DISPLAY_FINISHED: + /* remove the display number from factory->priv->used_display_numbers + so that it may be reused */ + if (num != -1) { + g_hash_table_remove (factory->priv->used_display_numbers, GUINT_TO_POINTER (num)); + } +- gdm_display_store_remove (store, display); ++ gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory)); + + /* if this is a local display, recreate the display so + * a new login screen comes up if one is missing. + */ + if (is_local && g_strcmp0 (session_class, "greeter") != 0) { + g_autofree char *active_session = NULL; + + /* reset num failures */ + factory->priv->num_failures = 0; + + ret = sd_seat_get_active (seat_id, &active_session, NULL); + + if (ret == 0) { + g_autofree char *state = NULL; + ret = sd_session_get_state (active_session, &state); + if (ret != 0 || + g_strcmp0 (state, "closing") == 0 || + g_strcmp0 (active_session, session_id) == 0) { + g_clear_pointer (&active_session, free); + } + } + + /* If this died in the foreground leaving us on a blank vt, + start a new login screen */ + if (!sd_seat_can_multi_session (seat_id) || active_session == NULL) { + create_display (factory, seat_id, session_type, is_initial); + } + } + break; + case GDM_DISPLAY_FAILED: + /* leave the display number in factory->priv->used_display_numbers + so that it doesn't get reused */ +- gdm_display_store_remove (store, display); ++ gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory)); + + /* Create a new equivalent display if it was static */ + if (is_local) { + + factory->priv->num_failures++; + + if (factory->priv->num_failures > MAX_DISPLAY_FAILURES) { + /* oh shit */ + g_warning ("GdmLocalDisplayFactory: maximum number of X display failures reached: check X server log for errors"); + } else { + #ifdef ENABLE_WAYLAND_SUPPORT + if (g_strcmp0 (session_type, "wayland") == 0) { + g_free (session_type); + session_type = NULL; + } + + #endif + create_display (factory, seat_id, session_type, is_initial); + } + } + break; + case GDM_DISPLAY_UNMANAGED: + break; + case GDM_DISPLAY_PREPARED: + break; + case GDM_DISPLAY_MANAGED: + break; + default: + g_assert_not_reached (); + break; +diff --git a/daemon/gdm-xdmcp-display-factory.c b/daemon/gdm-xdmcp-display-factory.c +index 46a0d9ffa..5b5786c6f 100644 +--- a/daemon/gdm-xdmcp-display-factory.c ++++ b/daemon/gdm-xdmcp-display-factory.c +@@ -2039,93 +2039,90 @@ on_hostname_selected (GdmXdmcpChooserDisplay *display, + char *ip; + ic->chosen_address = gdm_address_new_from_sockaddr (ai->ai_addr, ai->ai_addrlen); + + ip = NULL; + gdm_address_get_numeric_info (ic->chosen_address, &ip, NULL); + g_debug ("GdmXdmcpDisplayFactory: hostname resolves to %s", + ip ? ip : "(null)"); + g_free (ip); + } + + freeaddrinfo (ai_list); + } + + static void + on_client_disconnected (GdmDisplay *display) + { + if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED) + return; + + gdm_display_stop_greeter_session (display); + gdm_display_unmanage (display); + gdm_display_finish (display); + } + + static void + on_display_status_changed (GdmDisplay *display, + GParamSpec *arg1, + GdmXdmcpDisplayFactory *factory) + { + int status; +- GdmDisplayStore *store; + GdmLaunchEnvironment *launch_environment; + GdmSession *session; + GdmAddress *address; + gint32 session_number; + int display_number; + +- store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); +- + launch_environment = NULL; + g_object_get (display, "launch-environment", &launch_environment, NULL); + + session = NULL; + if (launch_environment != NULL) { + session = gdm_launch_environment_get_session (launch_environment); + } + + status = gdm_display_get_status (display); + + g_debug ("GdmXdmcpDisplayFactory: xdmcp display status changed: %d", status); + switch (status) { + case GDM_DISPLAY_FINISHED: + g_object_get (display, + "remote-address", &address, + "x11-display-number", &display_number, + "session-number", &session_number, + NULL); + gdm_xdmcp_send_alive (factory, address, display_number, session_number); + +- gdm_display_store_remove (store, display); ++ gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory)); + break; + case GDM_DISPLAY_FAILED: +- gdm_display_store_remove (store, display); ++ gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory)); + break; + case GDM_DISPLAY_UNMANAGED: + if (session != NULL) { + g_signal_handlers_disconnect_by_func (G_OBJECT (session), + G_CALLBACK (on_client_disconnected), + display); + } + break; + case GDM_DISPLAY_PREPARED: + break; + case GDM_DISPLAY_MANAGED: + if (session != NULL) { + g_signal_connect_object (G_OBJECT (session), + "client-disconnected", + G_CALLBACK (on_client_disconnected), + display, G_CONNECT_SWAPPED); + g_signal_connect_object (G_OBJECT (session), + "disconnected", + G_CALLBACK (on_client_disconnected), + display, G_CONNECT_SWAPPED); + } + break; + default: + g_assert_not_reached (); + break; + } + } + + static GdmDisplay * + gdm_xdmcp_display_create (GdmXdmcpDisplayFactory *factory, +-- +2.21.0 + diff --git a/SOURCES/0006-manager-ensure-factories-are-stopped-at-shutdown.patch b/SOURCES/0006-manager-ensure-factories-are-stopped-at-shutdown.patch new file mode 100644 index 0000000..7209d55 --- /dev/null +++ b/SOURCES/0006-manager-ensure-factories-are-stopped-at-shutdown.patch @@ -0,0 +1,425 @@ +From 86cff2e65b3d1f1186b378d7b5818531ff6b1d94 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Fri, 25 Oct 2019 09:27:15 -0400 +Subject: [PATCH 6/7] manager: ensure factories are stopped at shutdown + +GDM doesn't currently stop it's display handling logic when it's +asked to shutdown. + +That can lead to X servers attempting to start themsevles as GDM +is tearing itself down. + +This commit addresses the problem adding some stop calls to the +code. +--- + daemon/gdm-local-display-factory.c | 15 +++++++++++++-- + daemon/gdm-manager.c | 5 +++++ + 2 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c +index 1c7daeb14..ad128d2c8 100644 +--- a/daemon/gdm-local-display-factory.c ++++ b/daemon/gdm-local-display-factory.c +@@ -34,60 +34,62 @@ + #include "gdm-manager.h" + #include "gdm-display-factory.h" + #include "gdm-local-display-factory.h" + #include "gdm-local-display-factory-glue.h" + + #include "gdm-settings-keys.h" + #include "gdm-settings-direct.h" + #include "gdm-display-store.h" + #include "gdm-local-display.h" + #include "gdm-legacy-display.h" + + #define GDM_LOCAL_DISPLAY_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_LOCAL_DISPLAY_FACTORY, GdmLocalDisplayFactoryPrivate)) + + #define GDM_DBUS_PATH "/org/gnome/DisplayManager" + #define GDM_LOCAL_DISPLAY_FACTORY_DBUS_PATH GDM_DBUS_PATH "/LocalDisplayFactory" + #define GDM_MANAGER_DBUS_NAME "org.gnome.DisplayManager.LocalDisplayFactory" + + #define MAX_DISPLAY_FAILURES 5 + + struct GdmLocalDisplayFactoryPrivate + { + GdmDBusLocalDisplayFactory *skeleton; + GDBusConnection *connection; + GHashTable *used_display_numbers; + + /* FIXME: this needs to be per seat? */ + guint num_failures; + + guint seat_new_id; + guint seat_removed_id; ++ ++ gboolean started; + }; + + enum { + PROP_0, + }; + + static void gdm_local_display_factory_class_init (GdmLocalDisplayFactoryClass *klass); + static void gdm_local_display_factory_init (GdmLocalDisplayFactory *factory); + static void gdm_local_display_factory_finalize (GObject *object); + + static GdmDisplay *create_display (GdmLocalDisplayFactory *factory, + const char *seat_id, + const char *session_type, + gboolean initial_display); + + static void on_display_status_changed (GdmDisplay *display, + GParamSpec *arg1, + GdmLocalDisplayFactory *factory); + + static gboolean gdm_local_display_factory_sync_seats (GdmLocalDisplayFactory *factory); + static gpointer local_display_factory_object = NULL; + + G_DEFINE_TYPE (GdmLocalDisplayFactory, gdm_local_display_factory, GDM_TYPE_DISPLAY_FACTORY) + + GQuark + gdm_local_display_factory_error_quark (void) + { + static GQuark ret = 0; + if (ret == 0) { + ret = g_quark_from_static_string ("gdm_local_display_factory_error"); +@@ -233,60 +235,63 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact + } + + if (! gdm_display_get_id (display, id, NULL)) { + display = NULL; + goto out; + } + + ret = TRUE; + out: + /* ref either held by store or not at all */ + g_object_unref (display); + + return ret; + } + + static void + on_display_status_changed (GdmDisplay *display, + GParamSpec *arg1, + GdmLocalDisplayFactory *factory) + { + int status; + int num; + char *seat_id = NULL; + char *session_id = NULL; + char *session_type = NULL; + char *session_class = NULL; + gboolean is_initial = TRUE; + gboolean is_local = TRUE; + int ret; + ++ if (!factory->priv->started) ++ return; ++ + num = -1; + gdm_display_get_x11_display_number (display, &num, NULL); + + g_object_get (display, + "seat-id", &seat_id, + "session-id", &session_id, + "is-initial", &is_initial, + "is-local", &is_local, + "session-type", &session_type, + "session-class", &session_class, + NULL); + + status = gdm_display_get_status (display); + + g_debug ("GdmLocalDisplayFactory: display status changed: %d", status); + switch (status) { + case GDM_DISPLAY_FINISHED: + /* remove the display number from factory->priv->used_display_numbers + so that it may be reused */ + if (num != -1) { + g_hash_table_remove (factory->priv->used_display_numbers, GUINT_TO_POINTER (num)); + } + gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory)); + + /* if this is a local display, recreate the display so + * a new login screen comes up if one is missing. + */ + if (is_local && g_strcmp0 (session_class, "greeter") != 0) { + g_autofree char *active_session = NULL; + +@@ -739,82 +744,88 @@ on_display_removed (GdmDisplayStore *display_store, + if (display != NULL) { + g_signal_handlers_disconnect_by_func (display, G_CALLBACK (on_display_status_changed), factory); + g_object_weak_unref (G_OBJECT (display), (GWeakNotify)on_display_disposed, factory); + + } + } + + static gboolean + gdm_local_display_factory_start (GdmDisplayFactory *base_factory) + { + GdmLocalDisplayFactory *factory = GDM_LOCAL_DISPLAY_FACTORY (base_factory); + GdmDisplayStore *store; + + g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE); + + store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); + + g_signal_connect_object (G_OBJECT (store), + "display-added", + G_CALLBACK (on_display_added), + factory, + 0); + + g_signal_connect_object (G_OBJECT (store), + "display-removed", + G_CALLBACK (on_display_removed), + factory, + 0); + + gdm_local_display_factory_start_monitor (factory); +- return gdm_local_display_factory_sync_seats (factory); ++ ++ gdm_local_display_factory_sync_seats (factory); ++ ++ factory->priv->started = TRUE; ++ return TRUE; + } + + static gboolean + gdm_local_display_factory_stop (GdmDisplayFactory *base_factory) + { + GdmLocalDisplayFactory *factory = GDM_LOCAL_DISPLAY_FACTORY (base_factory); + GdmDisplayStore *store; + + g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE); + + gdm_local_display_factory_stop_monitor (factory); + + store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); + + g_signal_handlers_disconnect_by_func (G_OBJECT (store), + G_CALLBACK (on_display_added), + factory); + g_signal_handlers_disconnect_by_func (G_OBJECT (store), + G_CALLBACK (on_display_removed), + factory); + ++ factory->priv->started = FALSE; ++ + return TRUE; + } + + static void + gdm_local_display_factory_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) + { + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } + + static void + gdm_local_display_factory_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) + { + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } + + static gboolean +@@ -906,50 +917,50 @@ gdm_local_display_factory_class_init (GdmLocalDisplayFactoryClass *klass) + factory_class->stop = gdm_local_display_factory_stop; + + g_type_class_add_private (klass, sizeof (GdmLocalDisplayFactoryPrivate)); + } + + static void + gdm_local_display_factory_init (GdmLocalDisplayFactory *factory) + { + factory->priv = GDM_LOCAL_DISPLAY_FACTORY_GET_PRIVATE (factory); + + factory->priv->used_display_numbers = g_hash_table_new (NULL, NULL); + } + + static void + gdm_local_display_factory_finalize (GObject *object) + { + GdmLocalDisplayFactory *factory; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (object)); + + factory = GDM_LOCAL_DISPLAY_FACTORY (object); + + g_return_if_fail (factory->priv != NULL); + + g_clear_object (&factory->priv->connection); + g_clear_object (&factory->priv->skeleton); + + g_hash_table_destroy (factory->priv->used_display_numbers); + +- gdm_local_display_factory_stop_monitor (factory); ++ gdm_local_display_factory_stop (GDM_DISPLAY_FACTORY (factory)); + + G_OBJECT_CLASS (gdm_local_display_factory_parent_class)->finalize (object); + } + + GdmLocalDisplayFactory * + gdm_local_display_factory_new (GdmDisplayStore *store) + { + if (local_display_factory_object != NULL) { + g_object_ref (local_display_factory_object); + } else { + local_display_factory_object = g_object_new (GDM_TYPE_LOCAL_DISPLAY_FACTORY, + "display-store", store, + NULL); + g_object_add_weak_pointer (local_display_factory_object, + (gpointer *) &local_display_factory_object); + } + + return GDM_LOCAL_DISPLAY_FACTORY (local_display_factory_object); + } +diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c +index 1db291587..779b716be 100644 +--- a/daemon/gdm-manager.c ++++ b/daemon/gdm-manager.c +@@ -1621,60 +1621,63 @@ greeter_display_started (GdmManager *manager, + if (manager->priv->ran_once) { + return; + } + + maybe_start_pending_initial_login (manager, display); + } + + static void + on_display_status_changed (GdmDisplay *display, + GParamSpec *arg1, + GdmManager *manager) + { + int status; + int display_number = -1; + char *session_type = NULL; + #ifdef WITH_PLYMOUTH + gboolean display_is_local = FALSE; + gboolean quit_plymouth = FALSE; + + g_object_get (display, + "is-local", &display_is_local, + NULL); + quit_plymouth = display_is_local && manager->priv->plymouth_is_running; + #endif + + g_object_get (display, + "x11-display-number", &display_number, + "session-type", &session_type, + NULL); + ++ if (!manager->priv->started) ++ return; ++ + status = gdm_display_get_status (display); + + switch (status) { + case GDM_DISPLAY_PREPARED: + case GDM_DISPLAY_MANAGED: + if ((display_number == -1 && status == GDM_DISPLAY_PREPARED) || + (display_number != -1 && status == GDM_DISPLAY_MANAGED)) { + char *session_class; + + g_object_get (display, + "session-class", &session_class, + NULL); + if (g_strcmp0 (session_class, "greeter") == 0) + set_up_session (manager, display); + g_free (session_class); + } + + if (status == GDM_DISPLAY_MANAGED) { + greeter_display_started (manager, display); + } + break; + case GDM_DISPLAY_FAILED: + case GDM_DISPLAY_UNMANAGED: + case GDM_DISPLAY_FINISHED: + #ifdef WITH_PLYMOUTH + if (quit_plymouth) { + plymouth_quit_without_transition (); + manager->priv->plymouth_is_running = FALSE; + } + #endif +@@ -2737,60 +2740,62 @@ 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) + { + gdm_display_stop_greeter_session (display); + 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); + ++ gdm_manager_stop (manager); ++ + #ifdef HAVE_LIBXDMCP + g_clear_object (&manager->priv->xdmcp_factory); + #endif + g_clear_object (&manager->priv->local_factory); + g_clear_pointer (&manager->priv->open_reauthentication_requests, + (GDestroyNotify) + g_hash_table_unref); + g_clear_pointer (&manager->priv->transient_sessions, + (GDestroyNotify) + g_hash_table_unref); + + g_list_foreach (manager->priv->user_sessions, + (GFunc) gdm_session_close, + NULL); + 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)); + } +-- +2.21.0 + diff --git a/SOURCES/0007-daemon-run-PostSession-script-from-mnager-not-worker.patch b/SOURCES/0007-daemon-run-PostSession-script-from-mnager-not-worker.patch new file mode 100644 index 0000000..6ae1f09 --- /dev/null +++ b/SOURCES/0007-daemon-run-PostSession-script-from-mnager-not-worker.patch @@ -0,0 +1,282 @@ +From ab06d95076705cdaee9945adb2e22ac75be72952 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 29 Aug 2019 09:34:04 -0400 +Subject: [PATCH 7/7] daemon: run PostSession script from mnager not worker + +After a user logs out, the session worker baby sitting +the session, may optionally run admin provided PostSession +scripts. + +Those scripts aren't getting reliably run on reboots, because +systemd kills the worker prematurely. + +There's no easy way to prevent this... the worker is part of +the user session and user sessions are terminated immediately +at shutdown time. + +This commit moves PostSession handling to the daemon process, +where it can happen unimpeded by session bring down. + +This also makes the scripts more reliable in other potential +cases where the worker is killed explicitly. +--- + daemon/gdm-manager.c | 40 +++++++++++++++++++++++++++++++++++++ + daemon/gdm-session-worker.c | 3 --- + 2 files changed, 40 insertions(+), 3 deletions(-) + +diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c +index 779b716be..d31c9d718 100644 +--- a/daemon/gdm-manager.c ++++ b/daemon/gdm-manager.c +@@ -1933,70 +1933,107 @@ on_user_session_opened (GdmSession *session, + 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_user_session_started (GdmSession *session, + const char *service_name, + GPid pid, + GdmManager *manager) + { + g_debug ("GdmManager: session started %d", pid); + add_session_record (manager, session, pid, SESSION_RECORD_LOGIN); + + #ifdef WITH_PLYMOUTH + if (g_strcmp0 (service_name, "gdm-autologin") == 0) { + if (manager->priv->plymouth_is_running) { + g_timeout_add_seconds (20, (GSourceFunc) plymouth_quit_with_transition, NULL); + manager->priv->plymouth_is_running = FALSE; + } + } + #endif + } + ++static void ++run_post_session_script (GdmSession *session) ++{ ++ GPid pid; ++ GdmDisplay *display; ++ gboolean display_is_local = FALSE; ++ const char *username; ++ g_autofree char *display_name = NULL, *remote_hostname = NULL, *display_auth_file = NULL; ++ ++ display = get_display_for_user_session (session); ++ ++ if (display == NULL) ++ return; ++ ++ pid = gdm_session_get_pid (session); ++ ++ if (pid <= 0) ++ return; ++ ++ username = gdm_session_get_username (session); ++ ++ g_object_get (G_OBJECT (display), ++ "x11-display-name", &display_name, ++ "is-local", &display_is_local, ++ "remote-hostname", &remote_hostname, ++ "x11-authority-file", &display_auth_file, ++ NULL); ++ ++ gdm_run_script (GDMCONFDIR "/PostSession", ++ username, ++ display_name, ++ display_is_local? NULL : remote_hostname, ++ display_auth_file); ++} ++ + static void + remove_user_session (GdmManager *manager, + GdmSession *session) + { + GList *node; + GdmDisplay *display; + + display = get_display_for_user_session (session); + + if (display != NULL) { ++ run_post_session_script (session); ++ + 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_session_start_failed (GdmSession *session, + const char *service_name, + const char *message, + GdmManager *manager) + { + g_debug ("GdmManager: session failed to start: %s", message); + remove_user_session (manager, session); + } + + static void + on_user_session_exited (GdmSession *session, + int code, + GdmManager *manager) + { + GPid pid; + +@@ -2753,60 +2790,63 @@ finish_display (const char *id, + 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); + + gdm_manager_stop (manager); + + #ifdef HAVE_LIBXDMCP + g_clear_object (&manager->priv->xdmcp_factory); + #endif + g_clear_object (&manager->priv->local_factory); + g_clear_pointer (&manager->priv->open_reauthentication_requests, + (GDestroyNotify) + g_hash_table_unref); + g_clear_pointer (&manager->priv->transient_sessions, + (GDestroyNotify) + g_hash_table_unref); + ++ g_list_foreach (manager->priv->user_sessions, ++ (GFunc) run_post_session_script, ++ NULL); + g_list_foreach (manager->priv->user_sessions, + (GFunc) gdm_session_close, + NULL); + 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); +diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c +index 07117d857..b0861b971 100644 +--- a/daemon/gdm-session-worker.c ++++ b/daemon/gdm-session-worker.c +@@ -1743,72 +1743,69 @@ gdm_session_worker_get_environment (GdmSessionWorker *worker) + static gboolean + run_script (GdmSessionWorker *worker, + const char *dir) + { + /* scripts are for non-program sessions only */ + if (worker->priv->is_program_session) { + return TRUE; + } + + return gdm_run_script (dir, + worker->priv->username, + worker->priv->x11_display_name, + worker->priv->display_is_local? NULL : worker->priv->hostname, + worker->priv->x11_authority_file); + } + + static void + session_worker_child_watch (GPid pid, + int status, + GdmSessionWorker *worker) + { + g_debug ("GdmSessionWorker: child (pid:%d) done (%s:%d)", + (int) pid, + WIFEXITED (status) ? "status" + : WIFSIGNALED (status) ? "signal" + : "unknown", + WIFEXITED (status) ? WEXITSTATUS (status) + : WIFSIGNALED (status) ? WTERMSIG (status) + : -1); + +- + gdm_session_worker_uninitialize_pam (worker, PAM_SUCCESS); + + gdm_dbus_worker_emit_session_exited (GDM_DBUS_WORKER (worker), + worker->priv->service, + status); +- + killpg (pid, SIGHUP); + + worker->priv->child_pid = -1; + worker->priv->child_watch_id = 0; +- run_script (worker, GDMCONFDIR "/PostSession"); + } + + static void + gdm_session_worker_watch_child (GdmSessionWorker *worker) + { + g_debug ("GdmSession worker: watching pid %d", worker->priv->child_pid); + worker->priv->child_watch_id = g_child_watch_add (worker->priv->child_pid, + (GChildWatchFunc)session_worker_child_watch, + worker); + + } + + static gboolean + _is_loggable_file (const char* filename) + { + struct stat file_info; + + if (g_lstat (filename, &file_info) < 0) { + return FALSE; + } + + return S_ISREG (file_info.st_mode) && g_access (filename, R_OK | W_OK) == 0; + } + + static void + rotate_logs (const char *path, + guint n_copies) + { + int i; + +-- +2.21.0 + diff --git a/SOURCES/clear-screen.patch b/SOURCES/clear-screen.patch index 0d3a595..2bf2504 100644 --- a/SOURCES/clear-screen.patch +++ b/SOURCES/clear-screen.patch @@ -1,7 +1,7 @@ -From 5337f1094ecedf50bcfb9a000ac6b99bd95ffea2 Mon Sep 17 00:00:00 2001 +From 4d5866dad65d096598dd260fcb158d4d1c355e22 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 14 Mar 2014 11:04:49 -0400 -Subject: [PATCH 5/8] systemd: clear terminal after starting +Subject: [PATCH] systemd: clear terminal after starting This helps with flicker when the X server shuts down. --- @@ -9,30 +9,10 @@ This helps with flicker when the X server shuts down. 1 file changed, 1 insertion(+) diff --git a/data/gdm.service.in b/data/gdm.service.in -index 72201c1f..b58f4c61 100644 +index 72201c1..b58f4c6 100644 --- a/data/gdm.service.in +++ b/data/gdm.service.in -@@ -1,34 +1,35 @@ - [Unit] - Description=GNOME Display Manager - - # replaces the getty - Conflicts=getty@tty@GDM_INITIAL_VT@.service - After=getty@tty@GDM_INITIAL_VT@.service - - # replaces plymouth-quit since it quits plymouth on its own - Conflicts=@PLYMOUTH_QUIT_SERVICE@ - After=@PLYMOUTH_QUIT_SERVICE@ - - # Needs all the dependencies of the services it's replacing - # pulled from getty@.service and @PLYMOUTH_QUIT_SERVICE@ - # (except for plymouth-quit-wait.service since it waits until - # plymouth is quit, which we do) - After=rc-local.service plymouth-start.service systemd-user-sessions.service - - # GDM takes responsibility for stopping plymouth, so if it fails - # for any reason, make sure plymouth still stops - OnFailure=plymouth-quit.service +@@ -21,6 +21,7 @@ OnFailure=plymouth-quit.service [Service] ExecStart=@sbindir@/gdm @@ -40,14 +20,6 @@ index 72201c1f..b58f4c61 100644 KillMode=mixed Restart=always IgnoreSIGPIPE=no - BusName=org.gnome.DisplayManager - StandardOutput=syslog - StandardError=inherit - EnvironmentFile=-@LANG_CONFIG_FILE@ - ExecReload=/bin/kill -SIGHUP $MAINPID - - [Install] - Alias=display-manager.service -- -2.14.2 +1.8.3.1 diff --git a/SPECS/gdm.spec b/SPECS/gdm.spec index ea02213..53655bb 100644 --- a/SPECS/gdm.spec +++ b/SPECS/gdm.spec @@ -10,7 +10,7 @@ Name: gdm Epoch: 1 Version: 3.28.2 -Release: 16%{?dist} +Release: 22%{?dist} Summary: The GNOME Display Manager License: GPLv2+ @@ -47,6 +47,14 @@ Patch90001: 0001-manager-allow-multiple-xdmcp-logins-for-the-same-use.patch Patch100001: 0001-local-display-factory-don-t-spawn-login-screen-if-ba.patch +Patch110001: 0001-session-worker-expose-worker-state-enum-to-type-syst.patch +Patch110002: 0002-session-worker-kill-user-sessions-when-stopping-gdm-.patch +Patch110003: 0003-session-worker-uninitialize-pam-if-worker-is-killed.patch +Patch110004: 0004-gdm-session-worker-Drop-login_vt-assuming-it-is-GDM_.patch +Patch110005: 0005-display-factory-avoid-removing-a-display-from-store-.patch +Patch110006: 0006-manager-ensure-factories-are-stopped-at-shutdown.patch +Patch110007: 0007-daemon-run-PostSession-script-from-mnager-not-worker.patch + Patch900000: audit-4.patch Patch900001: clear-screen.patch Patch900002: 0001-gdm.conf-custom.in-strip-out-reference-to-wayland.patch @@ -55,6 +63,8 @@ Patch900004: classic-session.patch Patch900005: 0001-data-drop-pam_gdm-reintroduce-pam_env-postlogin.patch Patch900006: 0001-configure-don-t-assume-x-server-defaults-to-local-on.patch +Patch990000: 0001-utils-add-new-gdm-disable-wayland-binary.patch + BuildRequires: pam-devel >= 0:%{pam_version} BuildRequires: desktop-file-utils >= %{desktop_file_utils_version} BuildRequires: libtool automake autoconf @@ -322,6 +332,7 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor >&/dev/null || : %{_datadir}/pixmaps/*.png %{_datadir}/glib-2.0/schemas/org.gnome.login-screen.gschema.xml %{_datadir}/glib-2.0/schemas/org.gnome.login-screen.gschema.override +%{_libexecdir}/gdm-disable-wayland %{_libexecdir}/gdm-host-chooser %{_libexecdir}/gdm-session-worker %{_libexecdir}/gdm-simple-chooser @@ -371,6 +382,19 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor >&/dev/null || : %{_libdir}/pkgconfig/gdm-pam-extensions.pc %changelog +* Tue Oct 29 2019 Ray Strode - 3.28.2-22 +- Fix PostSession on reboot too +- Fix spew in log on shutdown + Related: #1547158 + +* Tue Sep 17 2019 Jonas Ã…dahl - 3.28.2-18 +- Include gdm-disable-wayland binary + Resolves: #1749325 + +* Thu Aug 29 2019 Ray Strode - 3.28.2-17 +- Fix PostSession + Resolves: #1547158 + * Wed May 22 2019 Ray Strode - 3.28.2-16 - Don't bring up login screen if background session gets killed Related: #1680120