import gdm-3.28.3-39.el8

This commit is contained in:
CentOS Sources 2021-03-30 09:05:38 -04:00 committed by Stepan Oksanichenko
parent e563a6593a
commit 10d480e908
61 changed files with 14456 additions and 219 deletions

View File

@ -1,4 +1,4 @@
From 29d374ce6781df6f3b168a8c57163ddb582c998a Mon Sep 17 00:00:00 2001
From 53c549876bcb7363d1d6dca70f2e1d3889741a06 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 31 Jul 2013 17:32:55 -0400
Subject: [PATCH] data: add system dconf databases to gdm profile
@ -9,14 +9,16 @@ This way system settings can affect the login screen.
1 file changed, 4 insertions(+)
diff --git a/data/dconf/gdm.in b/data/dconf/gdm.in
index 4d8bf174..9694078f 100644
index 4d8bf1748..606e0b863 100644
--- a/data/dconf/gdm.in
+++ b/data/dconf/gdm.in
@@ -1,2 +1,5 @@
@@ -1,2 +1,6 @@
user-db:user
+system-db:gdm
+system-db:local
+system-db:site
+system-db:distro
file-db:@DATADIR@/@PACKAGE@/greeter-dconf-defaults
--
2.11.1
--
2.26.0

View File

@ -0,0 +1,140 @@
From e339ad74ca408c665a62bb4bd98dd1ef6caedd20 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
Date: Tue, 27 Oct 2020 15:14:27 +0100
Subject: [PATCH] display: Exit with failure if loading existing users fails
Given not having users may make GDM to launch initial setup, that
allows to create new users (potentially with sudo capabilities), it's
better to make look_for_existing_users() to return its status and only
if it didn't fail continue the gdm execution.
GHSL-2020-202
CVE-2020-16125
Fixes #642
---
daemon/gdm-display.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c
index 929fa13bd..1b60eb621 100644
--- a/daemon/gdm-display.c
+++ b/daemon/gdm-display.c
@@ -436,106 +436,110 @@ finish_idle (GdmDisplay *self)
static void
queue_finish (GdmDisplay *self)
{
if (self->priv->finish_idle_id == 0) {
self->priv->finish_idle_id = g_idle_add ((GSourceFunc)finish_idle, self);
}
}
static void
_gdm_display_set_status (GdmDisplay *self,
int status)
{
if (status != self->priv->status) {
self->priv->status = status;
g_object_notify (G_OBJECT (self), "status");
}
}
static gboolean
gdm_display_real_prepare (GdmDisplay *self)
{
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
g_debug ("GdmDisplay: prepare display");
_gdm_display_set_status (self, GDM_DISPLAY_PREPARED);
return TRUE;
}
-static void
+static gboolean
look_for_existing_users_sync (GdmDisplay *self)
{
g_autoptr (GVariant) result = NULL;
g_autoptr (GVariant) result_child = NULL;
g_autoptr (GError) error = NULL;
gboolean has_no_users = FALSE;
result = g_dbus_connection_call_sync (self->priv->connection,
"org.freedesktop.Accounts",
"/org/freedesktop/Accounts",
"org.freedesktop.DBus.Properties",
"Get",
g_variant_new ("(ss)", "org.freedesktop.Accounts", "HasNoUsers"),
G_VARIANT_TYPE ("(v)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if (result == NULL) {
- g_warning ("Failed to contact accountsservice: %s", error->message);
- return;
+ g_critical ("Failed to contact accountsservice: %s", error->message);
+ goto out;
}
g_variant_get (result, "(v)", &result_child);
has_no_users = g_variant_get_boolean (result_child);
self->priv->have_existing_user_accounts = !has_no_users;
g_debug ("GdmDisplay: machine does %shave existing user accounts",
has_no_users? "not " : "");
+out:
+ return result != NULL;
}
gboolean
gdm_display_prepare (GdmDisplay *self)
{
gboolean ret;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
g_debug ("GdmDisplay: Preparing display: %s", self->priv->id);
/* FIXME: we should probably do this in a more global place,
* asynchronously
*/
- look_for_existing_users_sync (self);
+ if (!look_for_existing_users_sync (self)) {
+ exit (EXIT_FAILURE);
+ }
self->priv->doing_initial_setup = wants_initial_setup (self);
g_object_ref (self);
ret = GDM_DISPLAY_GET_CLASS (self)->prepare (self);
g_object_unref (self);
return ret;
}
gboolean
gdm_display_manage (GdmDisplay *self)
{
gboolean res;
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
g_debug ("GdmDisplay: Managing display: %s", self->priv->id);
/* If not explicitly prepared, do it now */
if (self->priv->status == GDM_DISPLAY_UNMANAGED) {
res = gdm_display_prepare (self);
if (! res) {
return FALSE;
}
}
if (g_strcmp0 (self->priv->session_class, "greeter") == 0) {
if (GDM_DISPLAY_GET_CLASS (self)->manage != NULL) {
GDM_DISPLAY_GET_CLASS (self)->manage (self);
--
2.28.0

View File

@ -0,0 +1,433 @@
From a9422c7b5f4200ad36300bb06134d545bb9d48d2 Mon Sep 17 00:00:00 2001
From: Lubomir Rintel <lkundrak@v3.sk>
Date: Tue, 17 Jul 2018 20:20:55 +0000
Subject: [PATCH 01/51] 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 <stdlib.h>
#include <stdio.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#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 ab7e12e91..1a9196ee1 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -222,107 +222,104 @@ 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_type = NULL;
gboolean is_initial = TRUE;
gboolean is_local = TRUE;
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,
"is-initial", &is_initial,
"is-local", &is_local,
"session-type", &session_type,
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, do a full resync. Only
* seats without displays will get created anyway. This
* ensures we get a new login screen when the user logs out,
* if there isn't one.
*/
if (is_local) {
/* reset num failures */
factory->priv->num_failures = 0;
gdm_local_display_factory_sync_seats (factory);
}
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;
/* workaround logind race for now
* bug 1643874
*/
g_usleep (2 * G_USEC_PER_SEC);
}
#endif
create_display (factory, seat_id, session_type, is_initial);
}
}
break;
case GDM_DISPLAY_UNMANAGED:
break;
case GDM_DISPLAY_PREPARED:
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.27.0

View File

@ -54,7 +54,7 @@ index 403921d32..ab7e12e91 100644
+ /* workaround logind race for now
+ * bug 1643874
+ */
+ sleep (2);
+ g_usleep (2 * G_USEC_PER_SEC);
}
#endif

View File

@ -0,0 +1,353 @@
From de229615d80fd7c8a38ab5d5d7b30aa98f43721d Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 14 Sep 2020 16:20:09 -0400
Subject: [PATCH 1/3] manager: Don't leak session objects
The first is from create_user_session_for display. Most callers don't
check the return value, so it should just be void.
The user data associated with the session also isn't unlinked from the
display when the display is finishing up, preventing the display and
session object from getting freed.
This commit makes both changes.
---
daemon/gdm-manager.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index bff602a07..738671679 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -94,63 +94,63 @@ struct GdmManagerPrivate
#ifdef WITH_PLYMOUTH
guint plymouth_is_running : 1;
#endif
guint did_automatic_login : 1;
};
enum {
PROP_0,
PROP_XDMCP_ENABLED,
PROP_SHOW_LOCAL_GREETER
};
enum {
DISPLAY_ADDED,
DISPLAY_REMOVED,
LAST_SIGNAL
};
typedef enum {
SESSION_RECORD_LOGIN,
SESSION_RECORD_LOGOUT,
SESSION_RECORD_FAILED,
} SessionRecord;
static guint signals [LAST_SIGNAL] = { 0, };
static void gdm_manager_class_init (GdmManagerClass *klass);
static void gdm_manager_init (GdmManager *manager);
static void gdm_manager_dispose (GObject *object);
-static GdmSession *create_user_session_for_display (GdmManager *manager,
- GdmDisplay *display,
- uid_t allowed_user);
+static void create_user_session_for_display (GdmManager *manager,
+ GdmDisplay *display,
+ uid_t allowed_user);
static void start_user_session (GdmManager *manager,
StartUserSessionOperation *operation);
static void clean_user_session (GdmSession *session);
static gpointer manager_object = NULL;
static void manager_interface_init (GdmDBusManagerIface *interface);
G_DEFINE_TYPE_WITH_CODE (GdmManager,
gdm_manager,
GDM_DBUS_TYPE_MANAGER_SKELETON,
G_IMPLEMENT_INTERFACE (GDM_DBUS_TYPE_MANAGER,
manager_interface_init));
#ifdef WITH_PLYMOUTH
static gboolean
plymouth_is_running (void)
{
int status;
gboolean res;
GError *error;
error = NULL;
res = g_spawn_command_line_sync ("/bin/plymouth --ping",
NULL, NULL, &status, &error);
if (! res) {
g_debug ("Could not ping plymouth: %s", error->message);
g_error_free (error);
return FALSE;
}
@@ -1343,61 +1343,62 @@ get_automatic_login_details (GdmManager *manager,
return enabled;
}
static const char *
get_username_for_greeter_display (GdmManager *manager,
GdmDisplay *display)
{
gboolean doing_initial_setup = FALSE;
g_object_get (G_OBJECT (display),
"doing-initial-setup", &doing_initial_setup,
NULL);
if (doing_initial_setup) {
return INITIAL_SETUP_USERNAME;
} else {
return GDM_USERNAME;
}
}
static void
set_up_automatic_login_session (GdmManager *manager,
GdmDisplay *display)
{
GdmSession *session;
char *display_session_type = NULL;
/* 0 is root user; since the daemon talks to the session object
* directly, itself, for automatic login
*/
- session = create_user_session_for_display (manager, display, 0);
+ create_user_session_for_display (manager, display, 0);
+ session = get_user_session_for_display (display);
g_object_get (G_OBJECT (display),
"session-type", &display_session_type,
NULL);
g_object_set (G_OBJECT (session),
"display-is-initial", FALSE,
NULL);
g_debug ("GdmManager: Starting automatic login conversation");
gdm_session_start_conversation (session, "gdm-autologin");
}
static void
set_up_chooser_session (GdmManager *manager,
GdmDisplay *display)
{
const char *allowed_user;
struct passwd *passwd_entry;
allowed_user = get_username_for_greeter_display (manager, display);
if (!gdm_get_pwent_for_name (allowed_user, &passwd_entry)) {
g_warning ("GdmManager: couldn't look up username %s",
allowed_user);
gdm_display_unmanage (display);
gdm_display_finish (display);
return;
}
@@ -1549,60 +1550,62 @@ on_display_status_changed (GdmDisplay *display,
"session-type", &session_type,
NULL);
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);
}
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
+ g_object_set_data (G_OBJECT (display), "gdm-user-session", NULL);
+
if (display == manager->priv->automatic_login_display) {
g_clear_weak_pointer (&manager->priv->automatic_login_display);
manager->priv->did_automatic_login = TRUE;
#ifdef ENABLE_WAYLAND_SUPPORT
if (g_strcmp0 (session_type, "wayland") != 0 && status == GDM_DISPLAY_FAILED) {
/* we're going to fall back to X11, so try to autologin again
*/
manager->priv->did_automatic_login = FALSE;
}
#endif
}
break;
default:
break;
}
}
static void
on_display_removed (GdmDisplayStore *display_store,
GdmDisplay *display,
GdmManager *manager)
{
char *id;
gdm_display_get_id (display, &id, NULL);
g_dbus_object_manager_server_unexport (manager->priv->object_manager, id);
g_free (id);
@@ -2292,61 +2295,61 @@ on_session_reauthentication_started (GdmSession *session,
int pid_of_caller,
const char *address,
GdmManager *manager)
{
GDBusMethodInvocation *invocation;
gpointer source_tag;
g_debug ("GdmManager: reauthentication started");
source_tag = GINT_TO_POINTER (pid_of_caller);
invocation = g_hash_table_lookup (manager->priv->open_reauthentication_requests,
source_tag);
if (invocation != NULL) {
g_hash_table_steal (manager->priv->open_reauthentication_requests,
source_tag);
gdm_dbus_manager_complete_open_reauthentication_channel (GDM_DBUS_MANAGER (manager),
invocation,
address);
}
}
static void
clean_user_session (GdmSession *session)
{
g_object_set_data (G_OBJECT (session), "gdm-display", NULL);
g_object_unref (session);
}
-static GdmSession *
+static void
create_user_session_for_display (GdmManager *manager,
GdmDisplay *display,
uid_t allowed_user)
{
GdmSession *session;
gboolean display_is_local = FALSE;
char *display_name = NULL;
char *display_device = NULL;
char *remote_hostname = NULL;
char *display_auth_file = NULL;
char *display_seat_id = NULL;
char *display_id = NULL;
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
char *display_session_type = NULL;
gboolean greeter_is_wayland;
#endif
g_object_get (G_OBJECT (display),
"id", &display_id,
"x11-display-name", &display_name,
"is-local", &display_is_local,
"remote-hostname", &remote_hostname,
"x11-authority-file", &display_auth_file,
"seat-id", &display_seat_id,
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
"session-type", &display_session_type,
#endif
NULL);
display_device = get_display_device (manager, display);
@@ -2402,70 +2405,68 @@ create_user_session_for_display (GdmManager *manager,
"conversation-stopped",
G_CALLBACK (on_session_conversation_stopped),
manager);
g_signal_connect (session,
"authentication-failed",
G_CALLBACK (on_session_authentication_failed),
manager);
g_signal_connect (session,
"session-opened",
G_CALLBACK (on_user_session_opened),
manager);
g_signal_connect (session,
"session-started",
G_CALLBACK (on_user_session_started),
manager);
g_signal_connect (session,
"session-start-failed",
G_CALLBACK (on_session_start_failed),
manager);
g_signal_connect (session,
"session-exited",
G_CALLBACK (on_user_session_exited),
manager);
g_signal_connect (session,
"session-died",
G_CALLBACK (on_user_session_died),
manager);
g_object_set_data (G_OBJECT (session), "gdm-display", display);
g_object_set_data_full (G_OBJECT (display),
"gdm-user-session",
- g_object_ref (session),
+ session,
(GDestroyNotify)
clean_user_session);
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
greeter_is_wayland = g_strcmp0 (display_session_type, "wayland") == 0;
g_object_set (G_OBJECT (session), "ignore-wayland", !greeter_is_wayland, NULL);
#endif
-
- return session;
}
static void
on_display_added (GdmDisplayStore *display_store,
const char *id,
GdmManager *manager)
{
GdmDisplay *display;
display = gdm_display_store_lookup (display_store, id);
if (display != NULL) {
g_dbus_object_manager_server_export (manager->priv->object_manager,
gdm_display_get_object_skeleton (display));
g_signal_connect (display, "notify::status",
G_CALLBACK (on_display_status_changed),
manager);
g_signal_emit (manager, signals[DISPLAY_ADDED], 0, id);
}
}
GQuark
gdm_manager_error_quark (void)
{
static GQuark ret = 0;
if (ret == 0) {
ret = g_quark_from_static_string ("gdm_manager_error");
}
--
2.26.2

View File

@ -15,10 +15,10 @@ treated as autologin sessions.
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 2118c5834..b2d0578f5 100644
index 1943d89e4..72d44b006 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1841,61 +1841,62 @@ on_start_user_session (StartUserSessionOperation *operation)
@@ -1838,61 +1838,62 @@ on_start_user_session (StartUserSessionOperation *operation)
NULL);
} else {
uid_t allowed_uid;
@ -52,23 +52,16 @@ index 2118c5834..b2d0578f5 100644
- if (g_strcmp0 (operation->service_name, "gdm-autologin") == 0) {
+ if ((g_strcmp0 (operation->service_name, "gdm-autologin") == 0) &&
+ !gdm_session_client_is_connected (operation->session)) {
gboolean was_initial = FALSE;
g_object_get (G_OBJECT (display), "is-initial", &was_initial, NULL);
/* remove the unused prepared greeter display since we're not going
* to have a greeter */
gdm_display_store_remove (self->priv->display_store, display);
g_object_unref (display);
should_be_initial = was_initial;
}
/* Give the user session a new display object for bookkeeping purposes */
create_display_for_user_session (operation->manager,
operation->session,
session_id,
should_be_initial);
session_id);
}
if (starting_user_session_right_away) {
@ -82,6 +75,13 @@ index 2118c5834..b2d0578f5 100644
static void
queue_start_user_session (GdmManager *manager,
GdmSession *session,
const char *service_name)
{
StartUserSessionOperation *operation;
operation = g_slice_new0 (StartUserSessionOperation);
operation->manager = manager;
operation->session = g_object_ref (session);
--
2.21.0
2.26.0

View File

@ -1,198 +0,0 @@
From 4b2db2cf52be75e2eec4aa29f8ee082392ded410 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 1 Nov 2018 13:03:37 -0400
Subject: [PATCH] manager: ensure is-initial is transfered to autologin display
At the moment, we don't handle transferring the is-initial property to
the autologin display.
That prevents autologin from working if wayland fails and X falls back,
since autologin currently requires an initial display.
This commit makes sure we properly transfer is-initial from greeter to
user display.
---
daemon/gdm-manager.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 1943d89e4..2118c5834 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1740,90 +1740,93 @@ start_user_session (GdmManager *manager,
g_object_get (G_OBJECT (display), "is-connected", &is_connected, NULL);
if (is_connected) {
auth_file = NULL;
username = gdm_session_get_username (operation->session);
gdm_display_add_user_authorization (display,
username,
&auth_file,
NULL);
g_assert (auth_file != NULL);
g_object_set (operation->session,
"user-x11-authority-file", auth_file,
NULL);
g_free (auth_file);
}
}
gdm_session_start_session (operation->session,
operation->service_name);
destroy_start_user_session_operation (operation);
}
static void
create_display_for_user_session (GdmManager *self,
GdmSession *session,
- const char *session_id)
+ const char *session_id,
+ gboolean is_initial)
{
GdmDisplay *display;
/* at the moment we only create GdmLocalDisplay objects on seat0 */
const char *seat_id = "seat0";
display = gdm_local_display_new ();
g_object_set (G_OBJECT (display),
"session-class", "user",
"seat-id", seat_id,
"session-id", session_id,
+ "is-initial", is_initial,
NULL);
gdm_display_store_add (self->priv->display_store,
display);
g_object_set_data (G_OBJECT (session), "gdm-display", display);
g_object_set_data_full (G_OBJECT (display),
"gdm-user-session",
g_object_ref (session),
(GDestroyNotify)
clean_user_session);
}
static gboolean
on_start_user_session (StartUserSessionOperation *operation)
{
GdmManager *self = operation->manager;
gboolean migrated;
gboolean fail_if_already_switched = TRUE;
gboolean doing_initial_setup = FALSE;
+ gboolean should_be_initial = FALSE;
gboolean starting_user_session_right_away = TRUE;
GdmDisplay *display;
const char *session_id;
g_debug ("GdmManager: start or jump to session");
/* If there's already a session running, jump to it.
* If the only session running is the one we just opened,
* start a session on it.
*/
migrated = switch_to_compatible_user_session (operation->manager, operation->session, fail_if_already_switched);
g_debug ("GdmManager: migrated: %d", migrated);
if (migrated) {
/* We don't stop the manager here because
when Xorg exits it switches to the VT it was
started from. That interferes with fast
user switching. */
gdm_session_reset (operation->session);
destroy_start_user_session_operation (operation);
goto out;
}
display = get_display_for_user_session (operation->session);
g_object_get (G_OBJECT (display), "doing-initial-setup", &doing_initial_setup, NULL);
session_id = gdm_session_get_conversation_session_id (operation->session,
operation->service_name);
@@ -1839,70 +1842,77 @@ on_start_user_session (StartUserSessionOperation *operation)
} else {
uid_t allowed_uid;
g_object_ref (display);
if (doing_initial_setup) {
g_debug ("GdmManager: closing down initial setup display");
gdm_display_stop_greeter_session (display);
gdm_display_unmanage (display);
gdm_display_finish (display);
/* We can't start the user session until the finished display
* starts to respawn (since starting an X server and bringing
* one down at the same time is a no go)
*/
g_assert (self->priv->initial_login_operation == NULL);
self->priv->initial_login_operation = operation;
starting_user_session_right_away = FALSE;
} else {
g_debug ("GdmManager: session has its display server, reusing our server for another login screen");
}
/* The user session is going to follow the session worker
* into the new display. Untie it from this display and
* create a new session for a future user login. */
allowed_uid = gdm_session_get_allowed_user (operation->session);
g_object_set_data (G_OBJECT (display), "gdm-user-session", NULL);
g_object_set_data (G_OBJECT (operation->session), "gdm-display", NULL);
create_user_session_for_display (operation->manager, display, allowed_uid);
if (g_strcmp0 (operation->service_name, "gdm-autologin") == 0) {
+ gboolean was_initial = FALSE;
+
+ g_object_get (G_OBJECT (display), "is-initial", &was_initial, NULL);
+
/* remove the unused prepared greeter display since we're not going
* to have a greeter */
gdm_display_store_remove (self->priv->display_store, display);
g_object_unref (display);
+
+ should_be_initial = was_initial;
}
/* Give the user session a new display object for bookkeeping purposes */
create_display_for_user_session (operation->manager,
operation->session,
- session_id);
+ session_id,
+ should_be_initial);
}
if (starting_user_session_right_away) {
start_user_session (operation->manager, operation);
}
out:
return G_SOURCE_REMOVE;
}
static void
queue_start_user_session (GdmManager *manager,
GdmSession *session,
const char *service_name)
{
StartUserSessionOperation *operation;
operation = g_slice_new0 (StartUserSessionOperation);
operation->manager = manager;
operation->session = g_object_ref (session);
operation->service_name = g_strdup (service_name);
operation->idle_id = g_idle_add ((GSourceFunc) on_start_user_session, operation);
g_object_set_data (G_OBJECT (session), "start-user-session-operation", operation);
}
static void
start_user_session_if_ready (GdmManager *manager,
GdmSession *session,
const char *service_name)
--
2.19.1

View File

@ -0,0 +1,683 @@
From 3864af1ea06d2125c1b1f5afa6fc12caa833980a Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 10 Dec 2020 15:14:20 -0500
Subject: [PATCH] session-worker: Don't switch back VTs until session is fully
exited
There's a race condition on shutdown where the session worker is
switching VTs back to the initial VT at the same time as the session
exit is being processed.
This means that manager may try to start a login screen (because of
the VT switch) when autologin is enabled when there shouldn't be a
login screen.
This commit makes sure both the PostSession script, and session-exited
signal emission are complete before initiating the VT switch back
to the initial VT.
https://gitlab.gnome.org/GNOME/gdm/-/issues/660
---
daemon/Makefile.am | 12 +++++
daemon/gdm-session-worker.c | 93 +++++++++++++++++++++++++++------
daemon/org.freedesktop.DBus.xml | 12 +++++
3 files changed, 101 insertions(+), 16 deletions(-)
create mode 100644 daemon/org.freedesktop.DBus.xml
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 86a8ee32f..b323f6455 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -7,83 +7,92 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/pam-extensions \
-I$(top_builddir)/common \
-DBINDIR=\"$(bindir)\" \
-DDATADIR=\"$(datadir)\" \
-DDMCONFDIR=\"$(dmconfdir)\" \
-DGDMCONFDIR=\"$(gdmconfdir)\" \
-DLIBDIR=\"$(libdir)\" \
-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-dbus-glue.h \
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 \
com.redhat.AccountsServiceUser.System.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-dbus-glue.c gdm-dbus-glue.h: org.freedesktop.DBus.xml Makefile.am
+ $(AM_V_GEN)gdbus-codegen \
+ --c-namespace=GdmDBus \
+ --interface-prefix=org.freedesktop.DBus \
+ --generate-c-code=gdm-dbus-glue \
+ --c-generate-autocleanup=all \
+ $(srcdir)/org.freedesktop.DBus.xml
+
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 \
@@ -130,60 +139,62 @@ libexec_PROGRAMS = \
gdm-wayland-session \
gdm-x-session \
$(NULL)
gdm_session_worker_SOURCES = \
session-worker-main.c \
com.redhat.AccountsServiceUser.System.h \
com.redhat.AccountsServiceUser.System.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-dbus-glue.h \
+ gdm-dbus-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-worker-enum-types.c \
gdm-session-enum-types.h \
$(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)
@@ -271,50 +282,51 @@ nodist_gdm_SOURCES = \
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-dbus-glue.c \
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-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 \
$(NULL)
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 42c415837..c1b2c1765 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -39,60 +39,61 @@
#ifdef HAVE_LOGINCAP
#include <login_cap.h>
#endif
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <glib-object.h>
#include <gio/gio.h>
#include <X11/Xauth.h>
#include <systemd/sd-daemon.h>
#ifdef ENABLE_SYSTEMD_JOURNAL
#include <systemd/sd-journal.h>
#endif
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#endif /* HAVE_SELINUX */
#include "gdm-common.h"
#include "gdm-log.h"
#ifdef SUPPORTS_PAM_EXTENSIONS
#include "gdm-pam-extensions.h"
#endif
+#include "gdm-dbus-glue.h"
#include "gdm-session-worker.h"
#include "gdm-session-glue.h"
#include "gdm-session.h"
#if defined (HAVE_ADT)
#include "gdm-session-solaris-auditor.h"
#elif defined (HAVE_LIBAUDIT)
#include "gdm-session-linux-auditor.h"
#else
#include "gdm-session-auditor.h"
#endif
#include "gdm-session-settings.h"
#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
@@ -1028,72 +1029,60 @@ 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) {
- /* Switch to the login VT if we are not the login screen. */
- if (worker->priv->session_vt != GDM_INITIAL_VT) {
- jump_to_vt (worker, GDM_INITIAL_VT);
- }
- }
-#endif
-
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);
@@ -1752,86 +1741,155 @@ gdm_session_worker_accredit_user (GdmSessionWorker *worker,
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
+wait_until_dbus_signal_emission_to_manager_finishes (GdmSessionWorker *worker)
+{
+ g_autoptr (GdmDBusPeer) peer_proxy = NULL;
+ g_autoptr (GError) error = NULL;
+ gboolean pinged;
+
+ peer_proxy = gdm_dbus_peer_proxy_new_sync (worker->priv->connection,
+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+ NULL,
+ "/org/freedesktop/DBus",
+ NULL,
+ &error);
+
+ if (peer_proxy == NULL) {
+ g_debug ("GdmSessionWorker: could not create peer proxy to daemon: %s",
+ error->message);
+ return;
+ }
+
+ pinged = gdm_dbus_peer_call_ping_sync (peer_proxy, NULL, &error);
+
+ if (!pinged) {
+ g_debug ("GdmSessionWorker: could not ping daemon: %s",
+ error->message);
+ return;
+ }
+}
+
+static void
+jump_back_to_initial_vt (GdmSessionWorker *worker)
+{
+ if (worker->priv->session_vt == 0)
+ return;
+
+ if (worker->priv->session_vt == GDM_INITIAL_VT)
+ return;
+
+ if (g_strcmp0 (worker->priv->display_seat_id, "seat0") != 0)
+ return;
+
+#ifdef ENABLE_USER_DISPLAY_SERVER
+ jump_to_vt (worker, GDM_INITIAL_VT);
+ worker->priv->session_vt = 0;
+#endif
+}
+
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);
+ worker->priv->child_pid = -1;
+ worker->priv->child_watch_id = 0;
+ run_script (worker, GDMCONFDIR "/PostSession");
+
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");
+ /* FIXME: It's important to give the manager an opportunity to process the
+ * session-exited emission above before switching VTs.
+ *
+ * This is because switching VTs makes the manager try to put a login screen
+ * up on VT 1, but it may actually want to try to auto login again in response
+ * to session-exited.
+ *
+ * This function just does a manager roundtrip over the bus to make sure the
+ * signal has been dispatched before jumping.
+ *
+ * Ultimately, we may want to improve the manager<->worker interface.
+ *
+ * See:
+ *
+ * https://gitlab.gnome.org/GNOME/gdm/-/merge_requests/123
+ *
+ * for some ideas and more discussion.
+ *
+ */
+ wait_until_dbus_signal_emission_to_manager_finishes (worker);
+
+ jump_back_to_initial_vt (worker);
}
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;
@@ -2401,60 +2459,61 @@ gdm_session_worker_open_session (GdmSessionWorker *worker,
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");
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);
+ worker->priv->session_vt = 0;
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,
gboolean is_reauth_session)
{
worker->priv->is_reauth_session = is_reauth_session;
}
static void
gdm_session_worker_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
@@ -3565,60 +3624,62 @@ gdm_session_worker_unwatch_child (GdmSessionWorker *worker)
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);
}
+ jump_back_to_initial_vt (worker);
+
g_clear_object (&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);
}
diff --git a/daemon/org.freedesktop.DBus.xml b/daemon/org.freedesktop.DBus.xml
new file mode 100644
index 000000000..5e0814bde
--- /dev/null
+++ b/daemon/org.freedesktop.DBus.xml
@@ -0,0 +1,12 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.freedesktop.DBus.Peer">
+ <method name="GetMachineId">
+ <arg direction="out" type="s"/>
+ </method>
+ <method name="Ping">
+ </method>
+ </interface>
+</node>
+
--
2.28.0

View File

@ -0,0 +1,164 @@
From 417f0aed42959719c40f0f8ec65050dcf2510bd1 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Wed, 16 May 2018 14:10:34 +0100
Subject: [PATCH 02/51] local-display-factory: Add
gdm_local_display_factory_use_wayland() helper
Factor out the code which decides if Xorg or Wayland should be used into
a helper function.
---
daemon/gdm-local-display-factory.c | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 1a9196ee1..b21e3aee0 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -158,60 +158,73 @@ take_next_display_number (GdmLocalDisplayFactory *factory)
ret = num + 1;
break;
}
}
out:
/* now reserve this number */
g_debug ("GdmLocalDisplayFactory: Reserving X display: %u", ret);
g_hash_table_insert (factory->priv->used_display_numbers, GUINT_TO_POINTER (ret), NULL);
return ret;
}
static void
on_display_disposed (GdmLocalDisplayFactory *factory,
GdmDisplay *display)
{
g_debug ("GdmLocalDisplayFactory: Display %p disposed", display);
}
static void
store_display (GdmLocalDisplayFactory *factory,
GdmDisplay *display)
{
GdmDisplayStore *store;
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
gdm_display_store_add (store, display);
}
+static gboolean
+gdm_local_display_factory_use_wayland (void)
+{
+#ifdef ENABLE_WAYLAND_SUPPORT
+ gboolean wayland_enabled = FALSE;
+ if (gdm_settings_direct_get_boolean (GDM_KEY_WAYLAND_ENABLE, &wayland_enabled)) {
+ if (wayland_enabled && g_file_test ("/usr/bin/Xwayland", G_FILE_TEST_IS_EXECUTABLE) )
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
/*
Example:
dbus-send --system --dest=org.gnome.DisplayManager \
--type=method_call --print-reply --reply-timeout=2000 \
/org/gnome/DisplayManager/Manager \
org.gnome.DisplayManager.Manager.GetDisplays
*/
gboolean
gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *factory,
char **id,
GError **error)
{
gboolean ret;
GdmDisplay *display = NULL;
g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
ret = FALSE;
g_debug ("GdmLocalDisplayFactory: Creating transient display");
#ifdef ENABLE_USER_DISPLAY_SERVER
display = gdm_local_display_new ();
#else
if (display == NULL) {
guint32 num;
num = take_next_display_number (factory);
display = gdm_legacy_display_new (num);
@@ -422,68 +435,62 @@ gdm_local_display_factory_sync_seats (GdmLocalDisplayFactory *factory)
GVariant *array;
GVariantIter iter;
const char *seat;
result = g_dbus_connection_call_sync (factory->priv->connection,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"ListSeats",
NULL,
G_VARIANT_TYPE ("(a(so))"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, &error);
if (!result) {
g_warning ("GdmLocalDisplayFactory: Failed to issue method call: %s", error->message);
g_clear_error (&error);
return FALSE;
}
array = g_variant_get_child_value (result, 0);
g_variant_iter_init (&iter, array);
while (g_variant_iter_loop (&iter, "(&so)", &seat, NULL)) {
gboolean is_initial;
const char *session_type = NULL;
if (g_strcmp0 (seat, "seat0") == 0) {
is_initial = TRUE;
-#ifdef ENABLE_WAYLAND_SUPPORT
- gboolean wayland_enabled = FALSE;
- if (gdm_settings_direct_get_boolean (GDM_KEY_WAYLAND_ENABLE, &wayland_enabled)) {
- if (wayland_enabled && g_file_test ("/usr/bin/Xwayland", G_FILE_TEST_IS_EXECUTABLE) ) {
- session_type = "wayland";
- }
- }
-#endif
+ if (gdm_local_display_factory_use_wayland ())
+ session_type = "wayland";
} else {
is_initial = FALSE;
}
create_display (factory, seat, session_type, is_initial);
}
g_variant_unref (result);
g_variant_unref (array);
return TRUE;
}
static void
on_seat_new (GDBusConnection *connection,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
const char *seat;
g_variant_get (parameters, "(&s&o)", &seat, NULL);
create_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat, NULL, FALSE);
}
static void
on_seat_removed (GDBusConnection *connection,
const gchar *sender_name,
--
2.27.0

View File

@ -0,0 +1,87 @@
From aeb88313c2110389ec530c8c7d5d816bac24d254 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 15 Sep 2020 00:41:00 -0400
Subject: [PATCH 2/3] session: Don't leak remote greeter interface
XDMCP login screens get a "Remote Geeter Interface" exported over
the bus connection (so the login window can provide a Disconnect
button).
This interface is getting leaked when the session object is disposed,
leaving the bus connection itself undisposed, which causes an fd
leak.
This commit plugs the interface leak, and thus the fd leak.
---
daemon/gdm-session.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
index 540a2534d..d6d8f128a 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -3602,60 +3602,61 @@ gdm_session_get_property (GObject *object,
break;
#ifdef ENABLE_WAYLAND_SUPPORT
case PROP_IGNORE_WAYLAND:
g_value_set_boolean (value, self->priv->ignore_wayland);
break;
#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_session_dispose (GObject *object)
{
GdmSession *self;
self = GDM_SESSION (object);
g_debug ("GdmSession: Disposing session");
gdm_session_close (self);
g_clear_pointer (&self->priv->conversations,
g_hash_table_unref);
g_clear_object (&self->priv->user_verifier_interface);
g_clear_pointer (&self->priv->user_verifier_extensions,
g_hash_table_unref);
g_clear_object (&self->priv->greeter_interface);
+ g_clear_object (&self->priv->remote_greeter_interface);
g_clear_object (&self->priv->chooser_interface);
g_free (self->priv->display_name);
self->priv->display_name = NULL;
g_free (self->priv->display_hostname);
self->priv->display_hostname = NULL;
g_free (self->priv->display_device);
self->priv->display_device = NULL;
g_free (self->priv->display_seat_id);
self->priv->display_seat_id = NULL;
g_free (self->priv->display_x11_authority_file);
self->priv->display_x11_authority_file = NULL;
g_strfreev (self->priv->conversation_environment);
self->priv->conversation_environment = NULL;
if (self->priv->worker_server != NULL) {
g_dbus_server_stop (self->priv->worker_server);
g_clear_object (&self->priv->worker_server);
}
if (self->priv->outside_server != NULL) {
g_dbus_server_stop (self->priv->outside_server);
g_clear_object (&self->priv->outside_server);
}
--
2.26.2

View File

@ -0,0 +1,83 @@
From db47f4de3aab9f4cd6b381ecd9341c94add59bf9 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Wed, 16 May 2018 18:36:50 +0100
Subject: [PATCH 03/51] local-display-factory: Use correct session-type for new
transient displays
Use the new gdm_local_display_factory_use_wayland() helper to correctly
set the session-type properties for displays created through
gdm_local_display_factory_create_transient_display().
---
daemon/gdm-local-display-factory.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index b21e3aee0..e52360a56 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -194,60 +194,62 @@ gdm_local_display_factory_use_wayland (void)
if (wayland_enabled && g_file_test ("/usr/bin/Xwayland", G_FILE_TEST_IS_EXECUTABLE) )
return TRUE;
}
#endif
return FALSE;
}
/*
Example:
dbus-send --system --dest=org.gnome.DisplayManager \
--type=method_call --print-reply --reply-timeout=2000 \
/org/gnome/DisplayManager/Manager \
org.gnome.DisplayManager.Manager.GetDisplays
*/
gboolean
gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *factory,
char **id,
GError **error)
{
gboolean ret;
GdmDisplay *display = NULL;
g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
ret = FALSE;
g_debug ("GdmLocalDisplayFactory: Creating transient display");
#ifdef ENABLE_USER_DISPLAY_SERVER
display = gdm_local_display_new ();
+ if (gdm_local_display_factory_use_wayland ())
+ g_object_set (G_OBJECT (display), "session-type", "wayland", NULL);
#else
if (display == NULL) {
guint32 num;
num = take_next_display_number (factory);
display = gdm_legacy_display_new (num);
}
#endif
g_object_set (display,
"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 */
--
2.27.0

View File

@ -0,0 +1,87 @@
From 7c9e236f9015aae2ea5868b67ff8036766cb7099 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 15 Sep 2020 11:28:48 -0400
Subject: [PATCH 3/3] xdmcp-display-factory: Clear launch environment when done
with it
The XDMCP disply factory examines the sessions of its displays'
launch environments when the displays change status.
Unfortunately it leaks a reference to the launch environment when
doing that.
This commit fixes the reference leak which leads to an fd leak.
---
daemon/gdm-xdmcp-display-factory.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/daemon/gdm-xdmcp-display-factory.c b/daemon/gdm-xdmcp-display-factory.c
index 2e14beab4..98232113f 100644
--- a/daemon/gdm-xdmcp-display-factory.c
+++ b/daemon/gdm-xdmcp-display-factory.c
@@ -2091,60 +2091,62 @@ on_display_status_changed (GdmDisplay *display,
gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory));
break;
case GDM_DISPLAY_FAILED:
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;
}
+
+ g_clear_object (&launch_environment);
}
static GdmDisplay *
gdm_xdmcp_display_create (GdmXdmcpDisplayFactory *factory,
const char *hostname,
GdmAddress *address,
int displaynum)
{
GdmDisplay *display;
GdmDisplayStore *store;
gboolean use_chooser;
g_debug ("GdmXdmcpDisplayFactory: Creating xdmcp display for %s:%d",
hostname ? hostname : "(null)", displaynum);
use_chooser = FALSE;
if (factory->priv->honor_indirect) {
IndirectClient *ic;
ic = indirect_client_lookup (factory, address);
/* This was an indirect thingie and nothing was yet chosen,
* use a chooser */
if (ic != NULL && ic->chosen_address == NULL) {
use_chooser = TRUE;
}
}
if (use_chooser) {
display = gdm_xdmcp_chooser_display_new (hostname,
--
2.26.2

View File

@ -0,0 +1,137 @@
From e2e5d2a7d73baa7c24d1f14b276cb653c06dd82f Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 1 Aug 2018 15:46:11 -0400
Subject: [PATCH 04/51] manager: make get_login_window_session_id fail if no
login screen
Right now we oddly succeed from get_login_window_session_id
if we can't find a login window.
None of the caller expect that, so fail instead.
---
daemon/gdm-manager.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index e44b94373..a9d5628ea 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1372,113 +1372,113 @@ maybe_start_pending_initial_login (GdmManager *manager,
NULL);
if (g_strcmp0 (greeter_seat_id, user_session_seat_id) == 0) {
start_user_session (manager, operation);
manager->priv->initial_login_operation = NULL;
}
g_free (greeter_seat_id);
g_free (user_session_seat_id);
}
static gboolean
get_login_window_session_id (const char *seat_id,
char **session_id)
{
gboolean ret;
int res, i;
char **sessions;
char *service_id;
char *service_class;
char *state;
res = sd_seat_get_sessions (seat_id, &sessions, NULL, NULL);
if (res < 0) {
g_debug ("Failed to determine sessions: %s", strerror (-res));
return FALSE;
}
if (sessions == NULL || sessions[0] == NULL) {
*session_id = NULL;
- ret = TRUE;
+ ret = FALSE;
goto out;
}
for (i = 0; sessions[i]; i ++) {
res = sd_session_get_class (sessions[i], &service_class);
if (res < 0) {
g_debug ("failed to determine class of session %s: %s", sessions[i], strerror (-res));
ret = FALSE;
goto out;
}
if (strcmp (service_class, "greeter") != 0) {
free (service_class);
continue;
}
free (service_class);
ret = sd_session_get_state (sessions[i], &state);
if (ret < 0) {
g_debug ("failed to determine state of session %s: %s", sessions[i], strerror (-res));
ret = FALSE;
goto out;
}
if (g_strcmp0 (state, "closing") == 0) {
free (state);
continue;
}
free (state);
res = sd_session_get_service (sessions[i], &service_id);
if (res < 0) {
g_debug ("failed to determine service of session %s: %s", sessions[i], strerror (-res));
ret = FALSE;
goto out;
}
if (strcmp (service_id, "gdm-launch-environment") == 0) {
*session_id = g_strdup (sessions[i]);
ret = TRUE;
free (service_id);
goto out;
}
free (service_id);
}
*session_id = NULL;
- ret = TRUE;
+ ret = FALSE;
out:
if (sessions) {
for (i = 0; sessions[i]; i ++) {
free (sessions[i]);
}
free (sessions);
}
return ret;
}
static void
activate_login_window_session_on_seat (GdmManager *self,
const char *seat_id)
{
char *session_id;
if (!get_login_window_session_id (seat_id, &session_id)) {
return;
}
activate_session_id (self, seat_id, session_id);
}
static void
maybe_activate_other_session (GdmManager *self,
GdmDisplay *old_display)
{
--
2.27.0

View File

@ -0,0 +1,79 @@
From 34238a9e845455ae2b92159c71b75b7abedc2eb9 Mon Sep 17 00:00:00 2001
From: Lubomir Rintel <lkundrak@v3.sk>
Date: Mon, 18 Jun 2018 12:33:42 +0200
Subject: [PATCH 05/51] manager: avoid leaking session_id
get_login_window_session_id() duplicates the session id.
---
daemon/gdm-manager.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index a9d5628ea..71f55ec65 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1449,60 +1449,61 @@ get_login_window_session_id (const char *seat_id,
free (service_id);
}
*session_id = NULL;
ret = FALSE;
out:
if (sessions) {
for (i = 0; sessions[i]; i ++) {
free (sessions[i]);
}
free (sessions);
}
return ret;
}
static void
activate_login_window_session_on_seat (GdmManager *self,
const char *seat_id)
{
char *session_id;
if (!get_login_window_session_id (seat_id, &session_id)) {
return;
}
activate_session_id (self, seat_id, session_id);
+ g_free (session_id);
}
static void
maybe_activate_other_session (GdmManager *self,
GdmDisplay *old_display)
{
char *seat_id = NULL;
char *session_id;
int ret;
g_object_get (G_OBJECT (old_display),
"seat-id", &seat_id,
NULL);
ret = sd_seat_get_active (seat_id, &session_id, NULL);
if (ret == 0) {
GdmDisplay *display;
display = gdm_display_store_find (self->priv->display_store,
lookup_by_session_id,
(gpointer) session_id);
if (display == NULL) {
activate_login_window_session_on_seat (self, seat_id);
}
}
g_free (seat_id);
}
--
2.27.0

View File

@ -0,0 +1,89 @@
From 454a3daad5148a8ef30cb298af82aa0713e73af7 Mon Sep 17 00:00:00 2001
From: Lubomir Rintel <lkundrak@v3.sk>
Date: Mon, 18 Jun 2018 12:33:51 +0200
Subject: [PATCH 06/51] manager: gracefully handle the case of no session for
login window
get_login_window_session_id() will return TRUE with session_id=NULL when
there's no session. This restults in an assertion failure on
constructing the o.fd.login1.Manager.ActivateSessionOnSeat() arguments:
GLib: g_variant_new_string: assertion 'string != NULL' failed
---
daemon/gdm-manager.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 71f55ec65..7a5554e9d 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1448,62 +1448,64 @@ get_login_window_session_id (const char *seat_id,
}
free (service_id);
}
*session_id = NULL;
ret = FALSE;
out:
if (sessions) {
for (i = 0; sessions[i]; i ++) {
free (sessions[i]);
}
free (sessions);
}
return ret;
}
static void
activate_login_window_session_on_seat (GdmManager *self,
const char *seat_id)
{
char *session_id;
if (!get_login_window_session_id (seat_id, &session_id)) {
return;
}
- activate_session_id (self, seat_id, session_id);
- g_free (session_id);
+ if (session_id) {
+ activate_session_id (self, seat_id, session_id);
+ g_free (session_id);
+ }
}
static void
maybe_activate_other_session (GdmManager *self,
GdmDisplay *old_display)
{
char *seat_id = NULL;
char *session_id;
int ret;
g_object_get (G_OBJECT (old_display),
"seat-id", &seat_id,
NULL);
ret = sd_seat_get_active (seat_id, &session_id, NULL);
if (ret == 0) {
GdmDisplay *display;
display = gdm_display_store_find (self->priv->display_store,
lookup_by_session_id,
(gpointer) session_id);
if (display == NULL) {
activate_login_window_session_on_seat (self, seat_id);
}
}
g_free (seat_id);
}
--
2.27.0

View File

@ -0,0 +1,432 @@
From 2fc9a5f9db7c9d2ab828bcff4ee5dec9c3cf3d3c Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 1 Aug 2018 16:34:30 -0400
Subject: [PATCH 07/51] common: dedupe gdm_get_login_window_session_id
Right now there are two slightly different cut-and-pastes of
the function to get the session id of the login session in
the code.
This commit deduplicates them.
---
common/gdm-common.c | 47 ++++++++++++++++++++++++++++++++------------
common/gdm-common.h | 2 ++
daemon/gdm-manager.c | 4 ++--
3 files changed, 38 insertions(+), 15 deletions(-)
diff --git a/common/gdm-common.c b/common/gdm-common.c
index c44fa998d..00daf0df8 100644
--- a/common/gdm-common.c
+++ b/common/gdm-common.c
@@ -364,186 +364,207 @@ create_transient_display (GDBusConnection *connection,
static gboolean
activate_session_id (GDBusConnection *connection,
const char *seat_id,
const char *session_id)
{
GError *local_error = NULL;
GVariant *reply;
reply = g_dbus_connection_call_sync (connection,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"ActivateSessionOnSeat",
g_variant_new ("(ss)", session_id, seat_id),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, &local_error);
if (reply == NULL) {
g_warning ("Unable to activate session: %s", local_error->message);
g_error_free (local_error);
return FALSE;
}
g_variant_unref (reply);
return TRUE;
}
-static gboolean
-get_login_window_session_id (const char *seat_id,
- char **session_id)
+gboolean
+gdm_get_login_window_session_id (const char *seat_id,
+ char **session_id)
{
gboolean ret;
int res, i;
char **sessions;
+ char *service_id;
char *service_class;
char *state;
res = sd_seat_get_sessions (seat_id, &sessions, NULL, NULL);
if (res < 0) {
g_debug ("Failed to determine sessions: %s", strerror (-res));
return FALSE;
}
if (sessions == NULL || sessions[0] == NULL) {
*session_id = NULL;
- ret = TRUE;
+ ret = FALSE;
goto out;
}
for (i = 0; sessions[i]; i ++) {
+
res = sd_session_get_class (sessions[i], &service_class);
if (res < 0) {
+ if (res == -ENOENT) {
+ free (service_class);
+ continue;
+ }
+
g_debug ("failed to determine class of session %s: %s", sessions[i], strerror (-res));
ret = FALSE;
goto out;
}
if (strcmp (service_class, "greeter") != 0) {
free (service_class);
continue;
}
free (service_class);
ret = sd_session_get_state (sessions[i], &state);
if (ret < 0) {
g_debug ("failed to determine state of session %s: %s", sessions[i], strerror (-res));
ret = FALSE;
goto out;
}
if (g_strcmp0 (state, "closing") == 0) {
free (state);
continue;
}
free (state);
- *session_id = g_strdup (sessions[i]);
- ret = TRUE;
- break;
+ res = sd_session_get_service (sessions[i], &service_id);
+ if (res < 0) {
+ g_debug ("failed to determine service of session %s: %s", sessions[i], strerror (-res));
+ ret = FALSE;
+ goto out;
+ }
+ if (strcmp (service_id, "gdm-launch-environment") == 0) {
+ *session_id = g_strdup (sessions[i]);
+ ret = TRUE;
+
+ free (service_id);
+ goto out;
+ }
+
+ free (service_id);
}
*session_id = NULL;
- ret = TRUE;
+ ret = FALSE;
out:
- for (i = 0; sessions[i]; i ++) {
- free (sessions[i]);
- }
+ if (sessions) {
+ for (i = 0; sessions[i]; i ++) {
+ free (sessions[i]);
+ }
- free (sessions);
+ free (sessions);
+ }
return ret;
}
static gboolean
goto_login_session (GDBusConnection *connection,
GError **error)
{
gboolean ret;
int res;
char *our_session;
char *session_id;
char *seat_id;
ret = FALSE;
session_id = NULL;
seat_id = NULL;
/* First look for any existing LoginWindow sessions on the seat.
If none are found, create a new one. */
/* Note that we mostly use free () here, instead of g_free ()
* since the data allocated is from libsystemd-logind, which
* does not use GLib's g_malloc (). */
res = sd_pid_get_session (0, &our_session);
if (res < 0) {
g_debug ("failed to determine own session: %s", strerror (-res));
g_set_error (error, GDM_COMMON_ERROR, 0, _("Could not identify the current session."));
return FALSE;
}
res = sd_session_get_seat (our_session, &seat_id);
free (our_session);
if (res < 0) {
g_debug ("failed to determine own seat: %s", strerror (-res));
g_set_error (error, GDM_COMMON_ERROR, 0, _("Could not identify the current seat."));
return FALSE;
}
res = sd_seat_can_multi_session (seat_id);
if (res < 0) {
free (seat_id);
g_debug ("failed to determine whether seat can do multi session: %s", strerror (-res));
g_set_error (error, GDM_COMMON_ERROR, 0, _("The system is unable to determine whether to switch to an existing login screen or start up a new login screen."));
return FALSE;
}
if (res == 0) {
free (seat_id);
g_set_error (error, GDM_COMMON_ERROR, 0, _("The system is unable to start up a new login screen."));
return FALSE;
}
- res = get_login_window_session_id (seat_id, &session_id);
+ res = gdm_get_login_window_session_id (seat_id, &session_id);
if (res && session_id != NULL) {
res = activate_session_id (connection, seat_id, session_id);
if (res) {
ret = TRUE;
}
}
if (! ret && g_strcmp0 (seat_id, "seat0") == 0) {
res = create_transient_display (connection, error);
if (res) {
ret = TRUE;
}
}
free (seat_id);
g_free (session_id);
return ret;
}
gboolean
gdm_goto_login_session (GError **error)
{
GError *local_error;
GDBusConnection *connection;
local_error = NULL;
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &local_error);
if (connection == NULL) {
diff --git a/common/gdm-common.h b/common/gdm-common.h
index 8d83a1246..c9cbd9c48 100644
--- a/common/gdm-common.h
+++ b/common/gdm-common.h
@@ -26,51 +26,53 @@
#include <errno.h>
#define VE_IGNORE_EINTR(expr) \
do { \
errno = 0; \
expr; \
} while G_UNLIKELY (errno == EINTR);
GQuark gdm_common_error_quark (void);
#define GDM_COMMON_ERROR gdm_common_error_quark()
typedef char * (*GdmExpandVarFunc) (const char *var,
gpointer user_data);
G_BEGIN_DECLS
int gdm_wait_on_pid (int pid);
int gdm_wait_on_and_disown_pid (int pid,
int timeout);
int gdm_signal_pid (int pid,
int signal);
gboolean gdm_get_pwent_for_name (const char *name,
struct passwd **pwentp);
gboolean gdm_clear_close_on_exec_flag (int fd);
const char * gdm_make_temp_dir (char *template);
char *gdm_generate_random_bytes (gsize size,
GError **error);
+gboolean gdm_get_login_window_session_id (const char *seat_id,
+ char **session_id);
gboolean gdm_goto_login_session (GError **error);
GPtrArray *gdm_get_script_environment (const char *username,
const char *display_name,
const char *display_hostname,
const char *display_x11_authority_file);
gboolean gdm_run_script (const char *dir,
const char *username,
const char *display_name,
const char *display_hostname,
const char *display_x11_authority_file);
gboolean gdm_shell_var_is_valid_char (char c,
gboolean first);
char * gdm_shell_expand (const char *str,
GdmExpandVarFunc expand_func,
gpointer user_data);
G_END_DECLS
#endif /* _GDM_COMMON_H */
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 7a5554e9d..375ef6f80 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1444,61 +1444,61 @@ get_login_window_session_id (const char *seat_id,
ret = TRUE;
free (service_id);
goto out;
}
free (service_id);
}
*session_id = NULL;
ret = FALSE;
out:
if (sessions) {
for (i = 0; sessions[i]; i ++) {
free (sessions[i]);
}
free (sessions);
}
return ret;
}
static void
activate_login_window_session_on_seat (GdmManager *self,
const char *seat_id)
{
char *session_id;
- if (!get_login_window_session_id (seat_id, &session_id)) {
+ if (!gdm_get_login_window_session_id (seat_id, &session_id)) {
return;
}
if (session_id) {
activate_session_id (self, seat_id, session_id);
g_free (session_id);
}
}
static void
maybe_activate_other_session (GdmManager *self,
GdmDisplay *old_display)
{
char *seat_id = NULL;
char *session_id;
int ret;
g_object_get (G_OBJECT (old_display),
"seat-id", &seat_id,
NULL);
ret = sd_seat_get_active (seat_id, &session_id, NULL);
if (ret == 0) {
GdmDisplay *display;
display = gdm_display_store_find (self->priv->display_store,
lookup_by_session_id,
(gpointer) session_id);
@@ -2082,61 +2082,61 @@ on_user_session_exited (GdmSession *session,
static void
on_user_session_died (GdmSession *session,
int signal_number,
GdmManager *manager)
{
g_debug ("GdmManager: session died with signal %s", strsignal (signal_number));
remove_user_session (manager, session);
}
static char *
get_display_device (GdmManager *manager,
GdmDisplay *display)
{
/* systemd finds the display device out on its own based on the display */
return NULL;
}
static void
on_session_reauthenticated (GdmSession *session,
const char *service_name,
GdmManager *manager)
{
gboolean fail_if_already_switched = FALSE;
if (gdm_session_get_display_mode (session) == GDM_SESSION_DISPLAY_MODE_REUSE_VT) {
const char *seat_id;
char *session_id;
seat_id = gdm_session_get_display_seat_id (session);
- if (get_login_window_session_id (seat_id, &session_id)) {
+ if (gdm_get_login_window_session_id (seat_id, &session_id)) {
GdmDisplay *display = gdm_display_store_find (manager->priv->display_store,
lookup_by_session_id,
(gpointer) session_id);
if (display != NULL) {
gdm_display_stop_greeter_session (display);
gdm_display_unmanage (display);
gdm_display_finish (display);
}
g_free (session_id);
}
}
/* There should already be a session running, so jump to its
* VT. In the event we're already on the right VT, (i.e. user
* used an unlock screen instead of a user switched login screen),
* then silently succeed and unlock the session.
*/
switch_to_compatible_user_session (manager, session, fail_if_already_switched);
}
static void
on_session_client_ready_for_session_to_start (GdmSession *session,
const char *service_name,
gboolean client_is_ready,
GdmManager *manager)
{
gboolean waiting_to_start_user_session;
if (client_is_ready) {
--
2.27.0

View File

@ -0,0 +1,401 @@
From 9d8e72ea9171566e9d74caaf28c8b5933ef34874 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 2 Aug 2018 14:00:46 -0400
Subject: [PATCH 08/51] common: dedupe activate_session_id
Right now there are three copies of activate_session_id.
This commit consolidates the code to gdm-common.c
---
common/gdm-common.c | 10 +++++-----
common/gdm-common.h | 6 ++++++
daemon/gdm-manager.c | 33 +--------------------------------
3 files changed, 12 insertions(+), 37 deletions(-)
diff --git a/common/gdm-common.c b/common/gdm-common.c
index 00daf0df8..59317a889 100644
--- a/common/gdm-common.c
+++ b/common/gdm-common.c
@@ -335,64 +335,64 @@ static gboolean
create_transient_display (GDBusConnection *connection,
GError **error)
{
GError *local_error = NULL;
GVariant *reply;
const char *value;
reply = g_dbus_connection_call_sync (connection,
GDM_DBUS_NAME,
GDM_DBUS_LOCAL_DISPLAY_FACTORY_PATH,
GDM_DBUS_LOCAL_DISPLAY_FACTORY_INTERFACE,
"CreateTransientDisplay",
NULL, /* parameters */
G_VARIANT_TYPE ("(o)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, &local_error);
if (reply == NULL) {
g_warning ("Unable to create transient display: %s", local_error->message);
g_propagate_error (error, local_error);
return FALSE;
}
g_variant_get (reply, "(&o)", &value);
g_debug ("Started %s", value);
g_variant_unref (reply);
return TRUE;
}
-static gboolean
-activate_session_id (GDBusConnection *connection,
- const char *seat_id,
- const char *session_id)
+gboolean
+gdm_activate_session_by_id (GDBusConnection *connection,
+ const char *seat_id,
+ const char *session_id)
{
GError *local_error = NULL;
GVariant *reply;
reply = g_dbus_connection_call_sync (connection,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"ActivateSessionOnSeat",
g_variant_new ("(ss)", session_id, seat_id),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, &local_error);
if (reply == NULL) {
g_warning ("Unable to activate session: %s", local_error->message);
g_error_free (local_error);
return FALSE;
}
g_variant_unref (reply);
return TRUE;
}
gboolean
gdm_get_login_window_session_id (const char *seat_id,
char **session_id)
{
gboolean ret;
@@ -512,61 +512,61 @@ goto_login_session (GDBusConnection *connection,
res = sd_session_get_seat (our_session, &seat_id);
free (our_session);
if (res < 0) {
g_debug ("failed to determine own seat: %s", strerror (-res));
g_set_error (error, GDM_COMMON_ERROR, 0, _("Could not identify the current seat."));
return FALSE;
}
res = sd_seat_can_multi_session (seat_id);
if (res < 0) {
free (seat_id);
g_debug ("failed to determine whether seat can do multi session: %s", strerror (-res));
g_set_error (error, GDM_COMMON_ERROR, 0, _("The system is unable to determine whether to switch to an existing login screen or start up a new login screen."));
return FALSE;
}
if (res == 0) {
free (seat_id);
g_set_error (error, GDM_COMMON_ERROR, 0, _("The system is unable to start up a new login screen."));
return FALSE;
}
res = gdm_get_login_window_session_id (seat_id, &session_id);
if (res && session_id != NULL) {
- res = activate_session_id (connection, seat_id, session_id);
+ res = gdm_activate_session_by_id (connection, seat_id, session_id);
if (res) {
ret = TRUE;
}
}
if (! ret && g_strcmp0 (seat_id, "seat0") == 0) {
res = create_transient_display (connection, error);
if (res) {
ret = TRUE;
}
}
free (seat_id);
g_free (session_id);
return ret;
}
gboolean
gdm_goto_login_session (GError **error)
{
GError *local_error;
GDBusConnection *connection;
local_error = NULL;
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &local_error);
if (connection == NULL) {
g_debug ("Failed to connect to the D-Bus daemon: %s", local_error->message);
g_propagate_error (error, local_error);
diff --git a/common/gdm-common.h b/common/gdm-common.h
index c9cbd9c48..3fbf07653 100644
--- a/common/gdm-common.h
+++ b/common/gdm-common.h
@@ -1,78 +1,84 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GDM_COMMON_H
#define _GDM_COMMON_H
#include <glib-unix.h>
+#include <gio/gio.h>
+
#include <pwd.h>
#include <errno.h>
#define VE_IGNORE_EINTR(expr) \
do { \
errno = 0; \
expr; \
} while G_UNLIKELY (errno == EINTR);
GQuark gdm_common_error_quark (void);
#define GDM_COMMON_ERROR gdm_common_error_quark()
typedef char * (*GdmExpandVarFunc) (const char *var,
gpointer user_data);
G_BEGIN_DECLS
int gdm_wait_on_pid (int pid);
int gdm_wait_on_and_disown_pid (int pid,
int timeout);
int gdm_signal_pid (int pid,
int signal);
gboolean gdm_get_pwent_for_name (const char *name,
struct passwd **pwentp);
gboolean gdm_clear_close_on_exec_flag (int fd);
const char * gdm_make_temp_dir (char *template);
char *gdm_generate_random_bytes (gsize size,
GError **error);
gboolean gdm_get_login_window_session_id (const char *seat_id,
char **session_id);
gboolean gdm_goto_login_session (GError **error);
GPtrArray *gdm_get_script_environment (const char *username,
const char *display_name,
const char *display_hostname,
const char *display_x11_authority_file);
gboolean gdm_run_script (const char *dir,
const char *username,
const char *display_name,
const char *display_hostname,
const char *display_x11_authority_file);
gboolean gdm_shell_var_is_valid_char (char c,
gboolean first);
char * gdm_shell_expand (const char *str,
GdmExpandVarFunc expand_func,
gpointer user_data);
+gboolean gdm_activate_session_by_id (GDBusConnection *connection,
+ const char *seat_id,
+ const char *session_id);
+
G_END_DECLS
#endif /* _GDM_COMMON_H */
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 375ef6f80..617ee36f0 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -267,91 +267,60 @@ lookup_by_session_id (const char *id,
static gboolean
is_login_session (GdmManager *self,
const char *session_id,
GError **error)
{
char *session_class = NULL;
int ret;
ret = sd_session_get_class (session_id, &session_class);
if (ret < 0) {
g_set_error (error,
GDM_DISPLAY_ERROR,
GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
"Error getting class for session id %s from systemd: %s",
session_id,
g_strerror (-ret));
return FALSE;
}
if (g_strcmp0 (session_class, "greeter") != 0) {
g_free (session_class);
return FALSE;
}
g_free (session_class);
return TRUE;
}
-static gboolean
-activate_session_id (GdmManager *manager,
- const char *seat_id,
- const char *session_id)
-{
- GError *error = NULL;
- GVariant *reply;
-
- reply = g_dbus_connection_call_sync (manager->priv->connection,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "ActivateSessionOnSeat",
- g_variant_new ("(ss)", session_id, seat_id),
- NULL, /* expected reply */
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL,
- &error);
- if (reply == NULL) {
- g_debug ("GdmManager: logind 'ActivateSessionOnSeat' %s raised:\n %s\n\n",
- g_dbus_error_get_remote_error (error), error->message);
- g_error_free (error);
- return FALSE;
- }
-
- g_variant_unref (reply);
-
- return TRUE;
-}
-
static gboolean
session_unlock (GdmManager *manager,
const char *ssid)
{
GError *error = NULL;
GVariant *reply;
g_debug ("Unlocking session %s", ssid);
reply = g_dbus_connection_call_sync (manager->priv->connection,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"UnlockSession",
g_variant_new ("(s)", ssid),
NULL, /* expected reply */
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if (reply == NULL) {
g_debug ("GdmManager: logind 'UnlockSession' %s raised:\n %s\n\n",
g_dbus_error_get_remote_error (error), error->message);
g_error_free (error);
return FALSE;
}
g_variant_unref (reply);
return TRUE;
@@ -627,61 +596,61 @@ switch_to_compatible_user_session (GdmManager *manager,
ret = FALSE;
username = gdm_session_get_username (session);
seat_id = gdm_session_get_display_seat_id (session);
if (!fail_if_already_switched)
ssid_to_activate = gdm_session_get_session_id (session);
if (ssid_to_activate == NULL) {
if (!seat_id || !sd_seat_can_multi_session (seat_id)) {
g_debug ("GdmManager: unable to activate existing sessions from login screen unless on seat0");
goto out;
}
if (!fail_if_already_switched) {
session = NULL;
}
existing_session = find_session_for_user_on_seat (manager, username, seat_id, session);
if (existing_session != NULL) {
ssid_to_activate = gdm_session_get_session_id (existing_session);
}
}
if (ssid_to_activate == NULL) {
goto out;
}
if (seat_id != NULL) {
- res = activate_session_id (manager, seat_id, ssid_to_activate);
+ res = gdm_activate_session_by_id (manager->priv->connection, seat_id, ssid_to_activate);
if (! res) {
g_debug ("GdmManager: unable to activate session: %s", ssid_to_activate);
goto out;
}
}
res = session_unlock (manager, ssid_to_activate);
if (!res) {
/* this isn't fatal */
g_debug ("GdmManager: unable to unlock session: %s", ssid_to_activate);
}
ret = TRUE;
out:
return ret;
}
static GdmDisplay *
get_display_for_user_session (GdmSession *session)
{
return g_object_get_data (G_OBJECT (session), "gdm-display");
}
static GdmSession *
get_user_session_for_display (GdmDisplay *display)
{
if (display == NULL) {
return NULL;
}
--
2.27.0

View File

@ -0,0 +1,103 @@
From 5bc19a4eb6de02ba549252026911dcce86e0fc21 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 22 Jun 2018 14:44:11 -0400
Subject: [PATCH 09/51] manager: plug leak in maybe_activate_other_session
The function asks logind what the currently active session is on the
given seat. It then leaks the response.
This commit plugs the leak.
---
daemon/gdm-manager.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 617ee36f0..a4dad92ee 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1428,79 +1428,81 @@ out:
free (sessions[i]);
}
free (sessions);
}
return ret;
}
static void
activate_login_window_session_on_seat (GdmManager *self,
const char *seat_id)
{
char *session_id;
if (!gdm_get_login_window_session_id (seat_id, &session_id)) {
return;
}
if (session_id) {
activate_session_id (self, seat_id, session_id);
g_free (session_id);
}
}
static void
maybe_activate_other_session (GdmManager *self,
GdmDisplay *old_display)
{
char *seat_id = NULL;
- char *session_id;
+ char *session_id = NULL;
int ret;
g_object_get (G_OBJECT (old_display),
"seat-id", &seat_id,
NULL);
ret = sd_seat_get_active (seat_id, &session_id, NULL);
if (ret == 0) {
GdmDisplay *display;
display = gdm_display_store_find (self->priv->display_store,
lookup_by_session_id,
(gpointer) session_id);
if (display == NULL) {
activate_login_window_session_on_seat (self, seat_id);
}
+
+ g_free (session_id);
}
g_free (seat_id);
}
static const char *
get_username_for_greeter_display (GdmManager *manager,
GdmDisplay *display)
{
gboolean doing_initial_setup = FALSE;
g_object_get (G_OBJECT (display),
"doing-initial-setup", &doing_initial_setup,
NULL);
if (doing_initial_setup) {
return INITIAL_SETUP_USERNAME;
} else {
return GDM_USERNAME;
}
}
static void
set_up_automatic_login_session (GdmManager *manager,
GdmDisplay *display)
{
GdmSession *session;
char *display_session_type = NULL;
gboolean is_initial;
--
2.27.0

View File

@ -0,0 +1,92 @@
From 2ec1b65c7bc2cefeabbd9a7a3a50436e1233804c Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 22 Jun 2018 14:55:39 -0400
Subject: [PATCH 10/51] manager: start login screen if old one is finished
Since commit 22c332ba we try to start a login screen if we end up
on an empty VT and there isn't one running.
Unfortunately the check for "is on an empty VT" is a little busted.
It counts the VT has non-empty if there's a display associated with
it, even if that display is in the FINISHED state about to be
reaped.
That means, in some cases, we'll still leave the user on an empty
VT with no login screen.
This commit addresses the problem by explicitly checking for
FINISHED displays, and proceeding even in their presense.
---
daemon/gdm-manager.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index a4dad92ee..a6f13dec7 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1444,61 +1444,61 @@ activate_login_window_session_on_seat (GdmManager *self,
return;
}
if (session_id) {
activate_session_id (self, seat_id, session_id);
g_free (session_id);
}
}
static void
maybe_activate_other_session (GdmManager *self,
GdmDisplay *old_display)
{
char *seat_id = NULL;
char *session_id = NULL;
int ret;
g_object_get (G_OBJECT (old_display),
"seat-id", &seat_id,
NULL);
ret = sd_seat_get_active (seat_id, &session_id, NULL);
if (ret == 0) {
GdmDisplay *display;
display = gdm_display_store_find (self->priv->display_store,
lookup_by_session_id,
(gpointer) session_id);
- if (display == NULL) {
+ if (display == NULL || gdm_display_get_status (display) == GDM_DISPLAY_FINISHED) {
activate_login_window_session_on_seat (self, seat_id);
}
g_free (session_id);
}
g_free (seat_id);
}
static const char *
get_username_for_greeter_display (GdmManager *manager,
GdmDisplay *display)
{
gboolean doing_initial_setup = FALSE;
g_object_get (G_OBJECT (display),
"doing-initial-setup", &doing_initial_setup,
NULL);
if (doing_initial_setup) {
return INITIAL_SETUP_USERNAME;
} else {
return GDM_USERNAME;
}
}
static void
set_up_automatic_login_session (GdmManager *manager,
GdmDisplay *display)
{
--
2.27.0

View File

@ -0,0 +1,127 @@
From 67d29b19ff4e53d58879b14c2e79a3bda419576f Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 22 Jun 2018 15:26:03 -0400
Subject: [PATCH 11/51] manager: don't bail if session disappears out from
under us
It's entirely possible for a session returned by
sd_seat_get_sessions to disappear immediately after the
sd_seat_get_sessions call returns. This is especially
likely at logout time where the session will briefly be
in the "closing" state before getting reaped.
If that happens when we're looking for a greeter session, we
stop looking for a greeter session and bail out all confused.
This commit fixes the confusion by gracefully handling the
session disappearing by just proceeding to the next session
in the list.
---
daemon/gdm-manager.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index a6f13dec7..ede22e771 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1349,87 +1349,97 @@ maybe_start_pending_initial_login (GdmManager *manager,
g_free (user_session_seat_id);
}
static gboolean
get_login_window_session_id (const char *seat_id,
char **session_id)
{
gboolean ret;
int res, i;
char **sessions;
char *service_id;
char *service_class;
char *state;
res = sd_seat_get_sessions (seat_id, &sessions, NULL, NULL);
if (res < 0) {
g_debug ("Failed to determine sessions: %s", strerror (-res));
return FALSE;
}
if (sessions == NULL || sessions[0] == NULL) {
*session_id = NULL;
ret = FALSE;
goto out;
}
for (i = 0; sessions[i]; i ++) {
res = sd_session_get_class (sessions[i], &service_class);
if (res < 0) {
+ if (res == -ENOENT) {
+ free (service_class);
+ continue;
+ }
+
g_debug ("failed to determine class of session %s: %s", sessions[i], strerror (-res));
ret = FALSE;
goto out;
}
if (strcmp (service_class, "greeter") != 0) {
free (service_class);
continue;
}
free (service_class);
ret = sd_session_get_state (sessions[i], &state);
if (ret < 0) {
+ if (res == -ENOENT)
+ continue;
+
g_debug ("failed to determine state of session %s: %s", sessions[i], strerror (-res));
ret = FALSE;
goto out;
}
if (g_strcmp0 (state, "closing") == 0) {
free (state);
continue;
}
free (state);
res = sd_session_get_service (sessions[i], &service_id);
if (res < 0) {
+ if (res == -ENOENT)
+ continue;
g_debug ("failed to determine service of session %s: %s", sessions[i], strerror (-res));
ret = FALSE;
goto out;
}
if (strcmp (service_id, "gdm-launch-environment") == 0) {
*session_id = g_strdup (sessions[i]);
ret = TRUE;
free (service_id);
goto out;
}
free (service_id);
}
*session_id = NULL;
ret = FALSE;
out:
if (sessions) {
for (i = 0; sessions[i]; i ++) {
free (sessions[i]);
}
free (sessions);
}
return ret;
}
--
2.27.0

View File

@ -0,0 +1,563 @@
From 9a3e9cb9a6bbf68ed6eb9f13d143a63af940f3ae Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 30 Jul 2018 16:21:29 -0400
Subject: [PATCH 12/51] daemon: try harder to get to a login screen at logout
commit 22c332ba and some follow up commits try to ensure the
user never stays on a blank VT by jumping to a login screen in
the event they'd end up on one.
Unfortunately, that part of the code can't start a login screen
if there's not one running at all.
This commit moves the code to GdmLocalDisplyFactory where the
login screens are created, so users won't end up on a blank
VT even if no login screen is yet running.
---
daemon/gdm-local-display-factory.c | 36 +++++++-
daemon/gdm-manager.c | 143 -----------------------------
2 files changed, 31 insertions(+), 148 deletions(-)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index e52360a56..0e454c880 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -1,60 +1,62 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include <gio/gio.h>
+#include <systemd/sd-login.h>
+
#include "gdm-common.h"
#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;
@@ -240,174 +242,198 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact
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;
int num;
char *seat_id = NULL;
char *session_type = NULL;
+ char *session_class = NULL;
gboolean is_initial = TRUE;
gboolean is_local = TRUE;
num = -1;
gdm_display_get_x11_display_number (display, &num, NULL);
g_object_get (display,
"seat-id", &seat_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, do a full resync. Only
* seats without displays will get created anyway. This
* ensures we get a new login screen when the user logs out,
* if there isn't one.
*/
- if (is_local) {
+ if (is_local && g_strcmp0 (session_class, "greeter") != 0) {
/* reset num failures */
factory->priv->num_failures = 0;
gdm_local_display_factory_sync_seats (factory);
}
break;
case GDM_DISPLAY_FAILED:
/* leave the display number in factory->priv->used_display_numbers
so that it doesn't get reused */
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;
/* workaround logind race for now
* bug 1643874
*/
g_usleep (2 * G_USEC_PER_SEC);
}
#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;
}
g_free (seat_id);
g_free (session_type);
+ g_free (session_class);
}
static gboolean
lookup_by_seat_id (const char *id,
GdmDisplay *display,
gpointer user_data)
{
const char *looking_for = user_data;
char *current;
gboolean res;
g_object_get (G_OBJECT (display), "seat-id", &current, NULL);
res = g_strcmp0 (current, looking_for) == 0;
g_free(current);
return res;
}
static GdmDisplay *
create_display (GdmLocalDisplayFactory *factory,
const char *seat_id,
const char *session_type,
gboolean initial)
{
GdmDisplayStore *store;
GdmDisplay *display = NULL;
+ char *active_session_id = NULL;
+ int ret;
- /* Ensure we don't create the same display more than once */
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
- display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id);
- if (display != NULL) {
- return NULL;
+
+ ret = sd_seat_get_active (seat_id, &active_session_id, NULL);
+
+ if (ret == 0) {
+ char *login_session_id = NULL;
+
+ /* If we already have a login window, switch to it */
+ if (gdm_get_login_window_session_id (seat_id, &login_session_id)) {
+ if (g_strcmp0 (active_session_id, login_session_id) != 0) {
+ gdm_activate_session_by_id (factory->priv->connection, seat_id, login_session_id);
+ }
+ g_clear_pointer (&login_session_id, g_free);
+ g_clear_pointer (&active_session_id, g_free);
+ return NULL;
+ }
+ g_clear_pointer (&active_session_id, g_free);
+ } else {
+ /* Ensure we don't create the same display more than once */
+ display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id);
+
+ if (display != NULL) {
+ return NULL;
+ }
}
g_debug ("GdmLocalDisplayFactory: Adding display on seat %s", seat_id);
#ifdef ENABLE_USER_DISPLAY_SERVER
if (g_strcmp0 (seat_id, "seat0") == 0) {
display = gdm_local_display_new ();
if (session_type != NULL) {
g_object_set (G_OBJECT (display), "session-type", session_type, NULL);
}
}
#endif
if (display == NULL) {
guint32 num;
num = take_next_display_number (factory);
display = gdm_legacy_display_new (num);
}
g_object_set (display, "seat-id", seat_id, NULL);
g_object_set (display, "is-initial", initial, NULL);
store_display (factory, display);
/* let store own the ref */
g_object_unref (display);
if (! gdm_display_manage (display)) {
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index ede22e771..80f60d24c 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1322,202 +1322,60 @@ maybe_start_pending_initial_login (GdmManager *manager,
char *user_session_seat_id = NULL;
/* There may be a user session waiting to be started.
* This would happen if we couldn't start it earlier because
* the login screen X server was coming up and two X servers
* can't be started on the same seat at the same time.
*/
if (manager->priv->initial_login_operation == NULL) {
return;
}
operation = manager->priv->initial_login_operation;
g_object_get (G_OBJECT (greeter_display),
"seat-id", &greeter_seat_id,
NULL);
g_object_get (G_OBJECT (operation->session),
"display-seat-id", &user_session_seat_id,
NULL);
if (g_strcmp0 (greeter_seat_id, user_session_seat_id) == 0) {
start_user_session (manager, operation);
manager->priv->initial_login_operation = NULL;
}
g_free (greeter_seat_id);
g_free (user_session_seat_id);
}
-static gboolean
-get_login_window_session_id (const char *seat_id,
- char **session_id)
-{
- gboolean ret;
- int res, i;
- char **sessions;
- char *service_id;
- char *service_class;
- char *state;
-
- res = sd_seat_get_sessions (seat_id, &sessions, NULL, NULL);
- if (res < 0) {
- g_debug ("Failed to determine sessions: %s", strerror (-res));
- return FALSE;
- }
-
- if (sessions == NULL || sessions[0] == NULL) {
- *session_id = NULL;
- ret = FALSE;
- goto out;
- }
-
- for (i = 0; sessions[i]; i ++) {
-
- res = sd_session_get_class (sessions[i], &service_class);
- if (res < 0) {
- if (res == -ENOENT) {
- free (service_class);
- continue;
- }
-
- g_debug ("failed to determine class of session %s: %s", sessions[i], strerror (-res));
- ret = FALSE;
- goto out;
- }
-
- if (strcmp (service_class, "greeter") != 0) {
- free (service_class);
- continue;
- }
-
- free (service_class);
-
- ret = sd_session_get_state (sessions[i], &state);
- if (ret < 0) {
- if (res == -ENOENT)
- continue;
-
- g_debug ("failed to determine state of session %s: %s", sessions[i], strerror (-res));
- ret = FALSE;
- goto out;
- }
-
- if (g_strcmp0 (state, "closing") == 0) {
- free (state);
- continue;
- }
- free (state);
-
- res = sd_session_get_service (sessions[i], &service_id);
- if (res < 0) {
- if (res == -ENOENT)
- continue;
- g_debug ("failed to determine service of session %s: %s", sessions[i], strerror (-res));
- ret = FALSE;
- goto out;
- }
-
- if (strcmp (service_id, "gdm-launch-environment") == 0) {
- *session_id = g_strdup (sessions[i]);
- ret = TRUE;
-
- free (service_id);
- goto out;
- }
-
- free (service_id);
- }
-
- *session_id = NULL;
- ret = FALSE;
-
-out:
- if (sessions) {
- for (i = 0; sessions[i]; i ++) {
- free (sessions[i]);
- }
-
- free (sessions);
- }
-
- return ret;
-}
-
-static void
-activate_login_window_session_on_seat (GdmManager *self,
- const char *seat_id)
-{
- char *session_id;
-
- if (!gdm_get_login_window_session_id (seat_id, &session_id)) {
- return;
- }
-
- if (session_id) {
- activate_session_id (self, seat_id, session_id);
- g_free (session_id);
- }
-}
-
-static void
-maybe_activate_other_session (GdmManager *self,
- GdmDisplay *old_display)
-{
- char *seat_id = NULL;
- char *session_id = NULL;
- int ret;
-
- g_object_get (G_OBJECT (old_display),
- "seat-id", &seat_id,
- NULL);
-
- ret = sd_seat_get_active (seat_id, &session_id, NULL);
-
- if (ret == 0) {
- GdmDisplay *display;
-
- display = gdm_display_store_find (self->priv->display_store,
- lookup_by_session_id,
- (gpointer) session_id);
-
- if (display == NULL || gdm_display_get_status (display) == GDM_DISPLAY_FINISHED) {
- activate_login_window_session_on_seat (self, seat_id);
- }
-
- g_free (session_id);
- }
-
- g_free (seat_id);
-}
-
static const char *
get_username_for_greeter_display (GdmManager *manager,
GdmDisplay *display)
{
gboolean doing_initial_setup = FALSE;
g_object_get (G_OBJECT (display),
"doing-initial-setup", &doing_initial_setup,
NULL);
if (doing_initial_setup) {
return INITIAL_SETUP_USERNAME;
} else {
return GDM_USERNAME;
}
}
static void
set_up_automatic_login_session (GdmManager *manager,
GdmDisplay *display)
{
GdmSession *session;
char *display_session_type = NULL;
gboolean is_initial;
/* 0 is root user; since the daemon talks to the session object
* directly, itself, for automatic login
*/
session = create_user_session_for_display (manager, display, 0);
@@ -1709,61 +1567,60 @@ on_display_status_changed (GdmDisplay *display,
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
if (status == GDM_DISPLAY_FINISHED || g_strcmp0 (session_type, "x11") == 0) {
manager->priv->ran_once = TRUE;
}
maybe_start_pending_initial_login (manager, display);
- maybe_activate_other_session (manager, display);
break;
default:
break;
}
}
static void
on_display_removed (GdmDisplayStore *display_store,
GdmDisplay *display,
GdmManager *manager)
{
char *id;
gdm_display_get_id (display, &id, NULL);
g_dbus_object_manager_server_unexport (manager->priv->object_manager, id);
g_free (id);
g_signal_handlers_disconnect_by_func (display, G_CALLBACK (on_display_status_changed), manager);
g_signal_emit (manager, signals[DISPLAY_REMOVED], 0, display);
}
static void
destroy_start_user_session_operation (StartUserSessionOperation *operation)
{
g_object_set_data (G_OBJECT (operation->session),
"start-user-session-operation",
NULL);
g_object_unref (operation->session);
--
2.27.0

View File

@ -0,0 +1,87 @@
From 299a0981f4e9fc02716d64abf5e5e692e2ad2951 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 3 Aug 2018 16:50:36 -0400
Subject: [PATCH 13/51] local-display-factory: ensure non-seat0 codepath
doesn't affect seat0
create_display currently bails in some cases if any display is running
on the seat. That's the right thing to do on seats other than seat0,
but wrong for seat0 (which an have multiple sessions at the same
time).
To ensure we never hit the case for seat0, add a call to check if
the passed seat is multi-session capable.
---
daemon/gdm-local-display-factory.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 0e454c880..7f7735ca1 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -373,61 +373,61 @@ lookup_by_seat_id (const char *id,
}
static GdmDisplay *
create_display (GdmLocalDisplayFactory *factory,
const char *seat_id,
const char *session_type,
gboolean initial)
{
GdmDisplayStore *store;
GdmDisplay *display = NULL;
char *active_session_id = NULL;
int ret;
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
ret = sd_seat_get_active (seat_id, &active_session_id, NULL);
if (ret == 0) {
char *login_session_id = NULL;
/* If we already have a login window, switch to it */
if (gdm_get_login_window_session_id (seat_id, &login_session_id)) {
if (g_strcmp0 (active_session_id, login_session_id) != 0) {
gdm_activate_session_by_id (factory->priv->connection, seat_id, login_session_id);
}
g_clear_pointer (&login_session_id, g_free);
g_clear_pointer (&active_session_id, g_free);
return NULL;
}
g_clear_pointer (&active_session_id, g_free);
- } else {
+ } else if (!sd_seat_can_multi_session (seat_id)) {
/* Ensure we don't create the same display more than once */
display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id);
if (display != NULL) {
return NULL;
}
}
g_debug ("GdmLocalDisplayFactory: Adding display on seat %s", seat_id);
#ifdef ENABLE_USER_DISPLAY_SERVER
if (g_strcmp0 (seat_id, "seat0") == 0) {
display = gdm_local_display_new ();
if (session_type != NULL) {
g_object_set (G_OBJECT (display), "session-type", session_type, NULL);
}
}
#endif
if (display == NULL) {
guint32 num;
num = take_next_display_number (factory);
display = gdm_legacy_display_new (num);
}
g_object_set (display, "seat-id", seat_id, NULL);
g_object_set (display, "is-initial", initial, NULL);
--
2.27.0

View File

@ -0,0 +1,369 @@
From 08f5f88ca6fb0edfc94af4c85912484b6048691b Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 2 Aug 2018 15:06:09 -0400
Subject: [PATCH 14/51] daemon: kill and restart greeter on demand under
wayland
Right now we leave the greeter alive after the user logs in.
This is for two reasons:
1) When the greeter is running Xorg, there's no way to kill
it when it's running on an inactive VT (X jumps to the foreground
when being killed)
2) The greeter, in a way, provides a securepath for unlock.
Users in theory could know that by hitting ctrl-alt-f1 to secure
attention, the login screen presented is not spoofed.
Since we use wayland by default, 1 isn't that much of a concern,
and 2 is a bit of niche feature that most users probably haven't
considered.
And there's a huge downside to keeping the greeter alive: it uses
a very large amount of memory.
This commit changes GDM to kill the login screen when switching
away from the login screen's VT and restarting it when switching
back.
Based heavily on work by Hans de Goede <hdegoede@redhat.com>
Closes: https://gitlab.gnome.org/GNOME/gdm/issues/222
---
daemon/gdm-local-display-factory.c | 167 +++++++++++++++++++++++++++++
1 file changed, 167 insertions(+)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 7f7735ca1..4ae656ab3 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -34,60 +34,65 @@
#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;
+
+#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
+ char *tty_of_active_vt;
+ guint active_vt_watch_id;
+#endif
};
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");
@@ -507,98 +512,260 @@ gdm_local_display_factory_sync_seats (GdmLocalDisplayFactory *factory)
static void
on_seat_new (GDBusConnection *connection,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
const char *seat;
g_variant_get (parameters, "(&s&o)", &seat, NULL);
create_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat, NULL, FALSE);
}
static void
on_seat_removed (GDBusConnection *connection,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
const char *seat;
g_variant_get (parameters, "(&s&o)", &seat, NULL);
delete_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat);
}
+#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
+static gboolean
+lookup_by_session_id (const char *id,
+ GdmDisplay *display,
+ gpointer user_data)
+{
+ const char *looking_for = user_data;
+ const char *current;
+
+ current = gdm_display_get_session_id (display);
+ return g_strcmp0 (current, looking_for) == 0;
+}
+
+static void
+maybe_stop_greeter_display (GdmDisplay *display)
+{
+ g_autofree char *display_session_type = NULL;
+
+ if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED)
+ return;
+
+ g_object_get (G_OBJECT (display),
+ "session-type", &display_session_type,
+ NULL);
+
+ /* we can only stop greeter for wayland sessions, since
+ * X server would jump back on exit */
+ if (g_strcmp0 (display_session_type, "wayland") != 0)
+ return;
+
+ gdm_display_stop_greeter_session (display);
+ gdm_display_unmanage (display);
+ gdm_display_finish (display);
+}
+
+static gboolean
+on_vt_changed (GIOChannel *source,
+ GIOCondition condition,
+ GdmLocalDisplayFactory *factory)
+{
+ GIOStatus status;
+ static const char *tty_of_initial_vt = "tty" GDM_INITIAL_VT;
+ g_autofree char *tty_of_previous_vt = NULL;
+ g_autofree char *tty_of_active_vt = NULL;
+ g_autofree char *login_session_id = NULL;
+ g_autofree char *active_session_id = NULL;
+ const char *session_type = NULL;
+ int ret;
+
+ g_io_channel_seek_position (source, 0, G_SEEK_SET, NULL);
+
+ if (condition & G_IO_PRI) {
+ g_autoptr (GError) error = NULL;
+ status = g_io_channel_read_line (source, &tty_of_active_vt, NULL, NULL, &error);
+
+ if (error != NULL) {
+ g_warning ("could not read active VT from kernel: %s", error->message);
+ }
+ switch (status) {
+ case G_IO_STATUS_ERROR:
+ return G_SOURCE_REMOVE;
+ case G_IO_STATUS_EOF:
+ return G_SOURCE_REMOVE;
+ case G_IO_STATUS_AGAIN:
+ return G_SOURCE_CONTINUE;
+ case G_IO_STATUS_NORMAL:
+ break;
+ }
+ }
+
+ if ((condition & G_IO_ERR) || (condition & G_IO_HUP))
+ return G_SOURCE_REMOVE;
+
+ if (tty_of_active_vt == NULL)
+ return G_SOURCE_CONTINUE;
+
+ g_strchomp (tty_of_active_vt);
+
+ /* don't do anything if we're on the same VT we were before */
+ if (g_strcmp0 (tty_of_active_vt, factory->priv->tty_of_active_vt) == 0)
+ return G_SOURCE_CONTINUE;
+
+ tty_of_previous_vt = g_steal_pointer (&factory->priv->tty_of_active_vt);
+ factory->priv->tty_of_active_vt = g_steal_pointer (&tty_of_active_vt);
+
+ /* if the old VT was running a wayland login screen kill it
+ */
+ if (gdm_get_login_window_session_id ("seat0", &login_session_id)) {
+ unsigned int vt;
+
+ ret = sd_session_get_vt (login_session_id, &vt);
+ if (ret == 0 && vt != 0) {
+ g_autofree char *tty_of_login_window_vt = NULL;
+
+ tty_of_login_window_vt = g_strdup_printf ("tty%u", vt);
+
+ if (g_strcmp0 (tty_of_login_window_vt, tty_of_previous_vt) == 0) {
+ GdmDisplayStore *store;
+ GdmDisplay *display;
+
+ store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
+ display = gdm_display_store_find (store,
+ lookup_by_session_id,
+ (gpointer) login_session_id);
+
+ if (display != NULL)
+ maybe_stop_greeter_display (display);
+ }
+ }
+ }
+
+ /* if user jumped back to initial vt and it's empty put a login screen
+ * on it (unless a login screen is already running elsewhere, then
+ * jump to that login screen)
+ */
+ if (strcmp (factory->priv->tty_of_active_vt, tty_of_initial_vt) != 0) {
+ return G_SOURCE_CONTINUE;
+ }
+
+ ret = sd_seat_get_active ("seat0", &active_session_id, NULL);
+
+ if (ret == 0) {
+ g_autofree char *state = NULL;
+ ret = sd_session_get_state (active_session_id, &state);
+
+ /* if there's something already running on the active VT then bail */
+ if (ret == 0 && g_strcmp0 (state, "closing") != 0)
+ return G_SOURCE_CONTINUE;
+ }
+
+ if (gdm_local_display_factory_use_wayland ())
+ session_type = "wayland";
+
+ create_display (factory, "seat0", session_type, TRUE);
+
+ return G_SOURCE_CONTINUE;
+}
+#endif
+
static void
gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory)
{
+ g_autoptr (GIOChannel) io_channel = NULL;
+
factory->priv->seat_new_id = g_dbus_connection_signal_subscribe (factory->priv->connection,
"org.freedesktop.login1",
"org.freedesktop.login1.Manager",
"SeatNew",
"/org/freedesktop/login1",
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
on_seat_new,
g_object_ref (factory),
g_object_unref);
factory->priv->seat_removed_id = g_dbus_connection_signal_subscribe (factory->priv->connection,
"org.freedesktop.login1",
"org.freedesktop.login1.Manager",
"SeatRemoved",
"/org/freedesktop/login1",
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
on_seat_removed,
g_object_ref (factory),
g_object_unref);
+
+#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
+ io_channel = g_io_channel_new_file ("/sys/class/tty/tty0/active", "r", NULL);
+
+ if (io_channel != NULL) {
+ factory->priv->active_vt_watch_id =
+ g_io_add_watch (io_channel,
+ G_IO_PRI,
+ (GIOFunc)
+ on_vt_changed,
+ factory);
+ }
+#endif
}
static void
gdm_local_display_factory_stop_monitor (GdmLocalDisplayFactory *factory)
{
if (factory->priv->seat_new_id) {
g_dbus_connection_signal_unsubscribe (factory->priv->connection,
factory->priv->seat_new_id);
factory->priv->seat_new_id = 0;
}
if (factory->priv->seat_removed_id) {
g_dbus_connection_signal_unsubscribe (factory->priv->connection,
factory->priv->seat_removed_id);
factory->priv->seat_removed_id = 0;
}
+#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
+ if (factory->priv->active_vt_watch_id) {
+ g_source_remove (factory->priv->active_vt_watch_id);
+ factory->priv->active_vt_watch_id = 0;
+ }
+
+ g_clear_pointer (&factory->priv->tty_of_active_vt, g_free);
+#endif
}
static void
on_display_added (GdmDisplayStore *display_store,
const char *id,
GdmLocalDisplayFactory *factory)
{
GdmDisplay *display;
display = gdm_display_store_lookup (display_store, id);
if (display != NULL) {
g_signal_connect_object (display, "notify::status",
G_CALLBACK (on_display_status_changed),
factory,
0);
g_object_weak_ref (G_OBJECT (display), (GWeakNotify)on_display_disposed, factory);
}
}
static void
on_display_removed (GdmDisplayStore *display_store,
GdmDisplay *display,
GdmLocalDisplayFactory *factory)
{
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);
}
--
2.27.0

View File

@ -0,0 +1,235 @@
From 59533722f1749d4e71360c5d717a18006c1f64c0 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 7 Aug 2018 13:55:06 -0400
Subject: [PATCH 15/51] local-display-factory: add more debug messages to new
vt handling code
commit c0188a7030 added some complex code for starting and stopping
the login screen based on VT changes.
That code currently has zero debug statements in it making it trickier
than necessary to debug.
This commit sprinkles some g_debug's throughout the function.
---
daemon/gdm-local-display-factory.c | 44 ++++++++++++++++++++++++------
1 file changed, 35 insertions(+), 9 deletions(-)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 4ae656ab3..2a2259f2a 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -530,175 +530,201 @@ on_seat_removed (GDBusConnection *connection,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
const char *seat;
g_variant_get (parameters, "(&s&o)", &seat, NULL);
delete_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat);
}
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
static gboolean
lookup_by_session_id (const char *id,
GdmDisplay *display,
gpointer user_data)
{
const char *looking_for = user_data;
const char *current;
current = gdm_display_get_session_id (display);
return g_strcmp0 (current, looking_for) == 0;
}
static void
maybe_stop_greeter_display (GdmDisplay *display)
{
g_autofree char *display_session_type = NULL;
- if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED)
+ if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED) {
+ g_debug ("GdmLocalDisplayFactory: login window not in managed state, so ignoring");
return;
+ }
g_object_get (G_OBJECT (display),
"session-type", &display_session_type,
NULL);
/* we can only stop greeter for wayland sessions, since
* X server would jump back on exit */
- if (g_strcmp0 (display_session_type, "wayland") != 0)
+ if (g_strcmp0 (display_session_type, "wayland") != 0) {
+ g_debug ("GdmLocalDisplayFactory: login window is running on Xorg, so ignoring");
return;
+ }
+ g_debug ("GdmLocalDisplayFactory: killing login window since its now unused");
gdm_display_stop_greeter_session (display);
gdm_display_unmanage (display);
gdm_display_finish (display);
}
static gboolean
on_vt_changed (GIOChannel *source,
GIOCondition condition,
GdmLocalDisplayFactory *factory)
{
GIOStatus status;
static const char *tty_of_initial_vt = "tty" GDM_INITIAL_VT;
g_autofree char *tty_of_previous_vt = NULL;
g_autofree char *tty_of_active_vt = NULL;
g_autofree char *login_session_id = NULL;
g_autofree char *active_session_id = NULL;
const char *session_type = NULL;
int ret;
+ g_debug ("GdmLocalDisplayFactory: received VT change event");
g_io_channel_seek_position (source, 0, G_SEEK_SET, NULL);
if (condition & G_IO_PRI) {
g_autoptr (GError) error = NULL;
status = g_io_channel_read_line (source, &tty_of_active_vt, NULL, NULL, &error);
if (error != NULL) {
g_warning ("could not read active VT from kernel: %s", error->message);
}
switch (status) {
case G_IO_STATUS_ERROR:
return G_SOURCE_REMOVE;
case G_IO_STATUS_EOF:
return G_SOURCE_REMOVE;
case G_IO_STATUS_AGAIN:
return G_SOURCE_CONTINUE;
case G_IO_STATUS_NORMAL:
break;
}
}
- if ((condition & G_IO_ERR) || (condition & G_IO_HUP))
+ if ((condition & G_IO_ERR) || (condition & G_IO_HUP)) {
+ g_debug ("GdmLocalDisplayFactory: kernel hung up active vt watch");
return G_SOURCE_REMOVE;
+ }
- if (tty_of_active_vt == NULL)
+ if (tty_of_active_vt == NULL) {
+ g_debug ("GdmLocalDisplayFactory: unable to read active VT from kernel");
return G_SOURCE_CONTINUE;
+ }
g_strchomp (tty_of_active_vt);
- /* don't do anything if we're on the same VT we were before */
- if (g_strcmp0 (tty_of_active_vt, factory->priv->tty_of_active_vt) == 0)
- return G_SOURCE_CONTINUE;
-
tty_of_previous_vt = g_steal_pointer (&factory->priv->tty_of_active_vt);
factory->priv->tty_of_active_vt = g_steal_pointer (&tty_of_active_vt);
+ /* don't do anything at start up */
+ if (tty_of_previous_vt == NULL) {
+ g_debug ("GdmLocalDisplayFactory: VT is %s at startup",
+ factory->priv->tty_of_active_vt);
+ return G_SOURCE_CONTINUE;
+ }
+
+ g_debug ("GdmLocalDisplayFactory: VT changed from %s to %s",
+ tty_of_previous_vt, factory->priv->tty_of_active_vt);
+
/* if the old VT was running a wayland login screen kill it
*/
if (gdm_get_login_window_session_id ("seat0", &login_session_id)) {
unsigned int vt;
ret = sd_session_get_vt (login_session_id, &vt);
if (ret == 0 && vt != 0) {
g_autofree char *tty_of_login_window_vt = NULL;
tty_of_login_window_vt = g_strdup_printf ("tty%u", vt);
+ g_debug ("GdmLocalDisplayFactory: tty of login window is %s", tty_of_login_window_vt);
if (g_strcmp0 (tty_of_login_window_vt, tty_of_previous_vt) == 0) {
GdmDisplayStore *store;
GdmDisplay *display;
+ g_debug ("GdmLocalDisplayFactory: VT switched from login window");
+
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
display = gdm_display_store_find (store,
lookup_by_session_id,
(gpointer) login_session_id);
if (display != NULL)
maybe_stop_greeter_display (display);
+ } else {
+ g_debug ("GdmLocalDisplayFactory: VT not switched from login window");
}
}
}
/* if user jumped back to initial vt and it's empty put a login screen
* on it (unless a login screen is already running elsewhere, then
* jump to that login screen)
*/
if (strcmp (factory->priv->tty_of_active_vt, tty_of_initial_vt) != 0) {
+ g_debug ("GdmLocalDisplayFactory: active VT is not initial VT, so ignoring");
return G_SOURCE_CONTINUE;
}
ret = sd_seat_get_active ("seat0", &active_session_id, NULL);
if (ret == 0) {
g_autofree char *state = NULL;
ret = sd_session_get_state (active_session_id, &state);
/* if there's something already running on the active VT then bail */
- if (ret == 0 && g_strcmp0 (state, "closing") != 0)
+ if (ret == 0 && g_strcmp0 (state, "closing") != 0) {
+ g_debug ("GdmLocalDisplayFactory: initial VT is in use, so ignoring");
return G_SOURCE_CONTINUE;
+ }
}
if (gdm_local_display_factory_use_wayland ())
session_type = "wayland";
+ g_debug ("GdmLocalDisplayFactory: creating new display on seat0 because of VT change");
+
create_display (factory, "seat0", session_type, TRUE);
return G_SOURCE_CONTINUE;
}
#endif
static void
gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory)
{
g_autoptr (GIOChannel) io_channel = NULL;
factory->priv->seat_new_id = g_dbus_connection_signal_subscribe (factory->priv->connection,
"org.freedesktop.login1",
"org.freedesktop.login1.Manager",
"SeatNew",
"/org/freedesktop/login1",
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
on_seat_new,
g_object_ref (factory),
g_object_unref);
factory->priv->seat_removed_id = g_dbus_connection_signal_subscribe (factory->priv->connection,
"org.freedesktop.login1",
"org.freedesktop.login1.Manager",
"SeatRemoved",
"/org/freedesktop/login1",
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
on_seat_removed,
g_object_ref (factory),
--
2.27.0

View File

@ -0,0 +1,97 @@
From e5bf6d78ff8f54bbb74e572f05ccbf1c0df24017 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 7 Aug 2018 13:55:06 -0400
Subject: [PATCH 16/51] local-display-factory: don't start two greeters at
startup
commit c0188a7030 added some complex code for starting
the login screen when the user switches to the initial
VT if nothing is running on that VT.
The problem is, we get a VT change event on that VT as
part of the start up process.
This leads to an additional greeter getting started.
This commit adds a check to side step the new code during
startup.
Closes: https://gitlab.gnome.org/GNOME/gdm/issues/409
---
daemon/gdm-local-display-factory.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 2a2259f2a..9f377ba9a 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -600,60 +600,66 @@ on_vt_changed (GIOChannel *source,
g_autoptr (GError) error = NULL;
status = g_io_channel_read_line (source, &tty_of_active_vt, NULL, NULL, &error);
if (error != NULL) {
g_warning ("could not read active VT from kernel: %s", error->message);
}
switch (status) {
case G_IO_STATUS_ERROR:
return G_SOURCE_REMOVE;
case G_IO_STATUS_EOF:
return G_SOURCE_REMOVE;
case G_IO_STATUS_AGAIN:
return G_SOURCE_CONTINUE;
case G_IO_STATUS_NORMAL:
break;
}
}
if ((condition & G_IO_ERR) || (condition & G_IO_HUP)) {
g_debug ("GdmLocalDisplayFactory: kernel hung up active vt watch");
return G_SOURCE_REMOVE;
}
if (tty_of_active_vt == NULL) {
g_debug ("GdmLocalDisplayFactory: unable to read active VT from kernel");
return G_SOURCE_CONTINUE;
}
g_strchomp (tty_of_active_vt);
+ /* don't do anything if we're on the same VT we were before */
+ if (g_strcmp0 (tty_of_active_vt, factory->priv->tty_of_active_vt) == 0) {
+ g_debug ("GdmLocalDisplayFactory: VT changed to the same VT, ignoring");
+ return G_SOURCE_CONTINUE;
+ }
+
tty_of_previous_vt = g_steal_pointer (&factory->priv->tty_of_active_vt);
factory->priv->tty_of_active_vt = g_steal_pointer (&tty_of_active_vt);
/* don't do anything at start up */
if (tty_of_previous_vt == NULL) {
g_debug ("GdmLocalDisplayFactory: VT is %s at startup",
factory->priv->tty_of_active_vt);
return G_SOURCE_CONTINUE;
}
g_debug ("GdmLocalDisplayFactory: VT changed from %s to %s",
tty_of_previous_vt, factory->priv->tty_of_active_vt);
/* if the old VT was running a wayland login screen kill it
*/
if (gdm_get_login_window_session_id ("seat0", &login_session_id)) {
unsigned int vt;
ret = sd_session_get_vt (login_session_id, &vt);
if (ret == 0 && vt != 0) {
g_autofree char *tty_of_login_window_vt = NULL;
tty_of_login_window_vt = g_strdup_printf ("tty%u", vt);
g_debug ("GdmLocalDisplayFactory: tty of login window is %s", tty_of_login_window_vt);
if (g_strcmp0 (tty_of_login_window_vt, tty_of_previous_vt) == 0) {
GdmDisplayStore *store;
GdmDisplay *display;
g_debug ("GdmLocalDisplayFactory: VT switched from login window");
--
2.27.0

View File

@ -0,0 +1,128 @@
From de4b24f63e62a39b2cb10a8c58c54d86559f7f26 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 7 Aug 2018 14:04:44 -0400
Subject: [PATCH 17/51] session-worker: don't switch VTs if we're already on
the right VT
commit 5b5dccbd shows that switching VTs to the same VT isn't
exactly a no-op. In order to prevent unnecessary wakeups, avoid
switching VTs if the worker is already on the correct VT.
---
daemon/gdm-session-worker.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 0322037e0..fd6470bab 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -936,91 +936,101 @@ fix_terminal_vt_mode (GdmSessionWorker *worker,
if (ioctl (tty_fd, KDGETMODE, &kernel_display_mode) < 0) {
g_debug ("GdmSessionWorker: couldn't query kernel display mode: %m");
succeeded = FALSE;
}
if (kernel_display_mode == KD_TEXT) {
goto out;
}
/* VT is in the anti-social state of VT_AUTO + KD_GRAPHICS,
* fix it.
*/
succeeded = handle_terminal_vt_switches (worker, tty_fd);
mode_fixed = TRUE;
out:
if (!succeeded) {
g_error ("GdmSessionWorker: couldn't set up terminal, aborting...");
return;
}
g_debug ("GdmSessionWorker: VT mode did %sneed to be fixed",
mode_fixed? "" : "not ");
}
static void
jump_to_vt (GdmSessionWorker *worker,
int vt_number)
{
int fd;
int active_vt_tty_fd;
+ int active_vt = -1;
+ struct vt_stat vt_state = { 0 };
g_debug ("GdmSessionWorker: jumping to VT %d", vt_number);
active_vt_tty_fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
if (worker->priv->session_tty_fd != -1) {
fd = worker->priv->session_tty_fd;
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);
+ if (ioctl (fd, VT_GETSTATE, &vt_state) <= 0) {
+ g_debug ("GdmSessionWorker: couldn't get current VT: %m");
+ } else {
+ active_vt = vt_state.v_active;
+ }
+
+ if (active_vt != vt_number) {
+ 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);
--
2.27.0

View File

@ -0,0 +1,87 @@
From b9e5a2879a410b6a85be6c01c6f49cd7eb24c800 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 31 Aug 2018 15:20:39 -0400
Subject: [PATCH 18/51] session-worker: fix current vt detection short-circuit
logic
commit 8169cd4 attempts to avoid changing VTs if the active VT
is the same as the VT getting jumped to.
It fails to work, however, because accidentally treats a 0 return
code to the VT_GETSTATE ioctl as failure.
this commit fixes that.
---
daemon/gdm-session-worker.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index fd6470bab..391969d96 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -963,61 +963,61 @@ jump_to_vt (GdmSessionWorker *worker,
{
int fd;
int active_vt_tty_fd;
int active_vt = -1;
struct vt_stat vt_state = { 0 };
g_debug ("GdmSessionWorker: jumping to VT %d", vt_number);
active_vt_tty_fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
if (worker->priv->session_tty_fd != -1) {
fd = worker->priv->session_tty_fd;
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_GETSTATE, &vt_state) <= 0) {
+ if (ioctl (fd, VT_GETSTATE, &vt_state) < 0) {
g_debug ("GdmSessionWorker: couldn't get current VT: %m");
} else {
active_vt = vt_state.v_active;
}
if (active_vt != vt_number) {
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
--
2.27.0

View File

@ -0,0 +1,168 @@
From fe680d77cff9272843cb171c7e590c239f7afe5a Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 9 Aug 2018 12:32:31 -0400
Subject: [PATCH 19/51] local-display-factory: don't jump to failed display
Since commit 5e737a57 `create_display` will jump to any
already running login screen if it can find one.
Right now if a display fails we call `create_display` to
create a new one. It will look for any already running
login screen and find the recently failed display.
This commit make sure we never jump to a display that isn't
in good working order.
---
daemon/gdm-local-display-factory.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 9f377ba9a..c58de9c17 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -60,60 +60,63 @@ struct GdmLocalDisplayFactoryPrivate
guint num_failures;
guint seat_new_id;
guint seat_removed_id;
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
char *tty_of_active_vt;
guint active_vt_watch_id;
#endif
};
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;
+static gboolean lookup_by_session_id (const char *id,
+ GdmDisplay *display,
+ gpointer user_data);
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");
}
return ret;
}
static void
listify_hash (gpointer key,
GdmDisplay *display,
GList **list)
{
*list = g_list_prepend (*list, key);
}
static int
sort_nums (gpointer a,
gpointer b)
{
guint32 num_a;
guint32 num_b;
num_a = GPOINTER_TO_UINT (a);
@@ -370,66 +373,74 @@ lookup_by_seat_id (const char *id,
g_object_get (G_OBJECT (display), "seat-id", &current, NULL);
res = g_strcmp0 (current, looking_for) == 0;
g_free(current);
return res;
}
static GdmDisplay *
create_display (GdmLocalDisplayFactory *factory,
const char *seat_id,
const char *session_type,
gboolean initial)
{
GdmDisplayStore *store;
GdmDisplay *display = NULL;
char *active_session_id = NULL;
int ret;
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
ret = sd_seat_get_active (seat_id, &active_session_id, NULL);
if (ret == 0) {
char *login_session_id = NULL;
/* If we already have a login window, switch to it */
if (gdm_get_login_window_session_id (seat_id, &login_session_id)) {
- if (g_strcmp0 (active_session_id, login_session_id) != 0) {
- gdm_activate_session_by_id (factory->priv->connection, seat_id, login_session_id);
+ GdmDisplay *display;
+
+ display = gdm_display_store_find (store,
+ lookup_by_session_id,
+ (gpointer) login_session_id);
+ if (display != NULL && gdm_display_get_status (display) == GDM_DISPLAY_MANAGED) {
+ if (g_strcmp0 (active_session_id, login_session_id) != 0) {
+ gdm_activate_session_by_id (factory->priv->connection, seat_id, login_session_id);
+ }
+ g_clear_pointer (&login_session_id, g_free);
+ g_clear_pointer (&active_session_id, g_free);
+ return NULL;
}
g_clear_pointer (&login_session_id, g_free);
- g_clear_pointer (&active_session_id, g_free);
- return NULL;
}
g_clear_pointer (&active_session_id, g_free);
} else if (!sd_seat_can_multi_session (seat_id)) {
/* Ensure we don't create the same display more than once */
display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id);
if (display != NULL) {
return NULL;
}
}
g_debug ("GdmLocalDisplayFactory: Adding display on seat %s", seat_id);
#ifdef ENABLE_USER_DISPLAY_SERVER
if (g_strcmp0 (seat_id, "seat0") == 0) {
display = gdm_local_display_new ();
if (session_type != NULL) {
g_object_set (G_OBJECT (display), "session-type", session_type, NULL);
}
}
#endif
if (display == NULL) {
guint32 num;
num = take_next_display_number (factory);
display = gdm_legacy_display_new (num);
}
--
2.27.0

View File

@ -0,0 +1,161 @@
From 94207dd5699f1cd2fe7d516c20e1de2b2e2778fb Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 9 Aug 2018 12:48:25 -0400
Subject: [PATCH 20/51] local-display-factory: add some more debug statements
This commit just sprinkles in a few more `g_debug`'s for
log file clarity.
---
daemon/gdm-local-display-factory.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index c58de9c17..6f3a4c391 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -364,76 +364,80 @@ on_display_status_changed (GdmDisplay *display,
static gboolean
lookup_by_seat_id (const char *id,
GdmDisplay *display,
gpointer user_data)
{
const char *looking_for = user_data;
char *current;
gboolean res;
g_object_get (G_OBJECT (display), "seat-id", &current, NULL);
res = g_strcmp0 (current, looking_for) == 0;
g_free(current);
return res;
}
static GdmDisplay *
create_display (GdmLocalDisplayFactory *factory,
const char *seat_id,
const char *session_type,
gboolean initial)
{
GdmDisplayStore *store;
GdmDisplay *display = NULL;
char *active_session_id = NULL;
int ret;
+ g_debug ("GdmLocalDisplayFactory: %s login display for seat %s requested",
+ session_type? : "X11", seat_id);
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
ret = sd_seat_get_active (seat_id, &active_session_id, NULL);
if (ret == 0) {
char *login_session_id = NULL;
/* If we already have a login window, switch to it */
if (gdm_get_login_window_session_id (seat_id, &login_session_id)) {
GdmDisplay *display;
display = gdm_display_store_find (store,
lookup_by_session_id,
(gpointer) login_session_id);
if (display != NULL && gdm_display_get_status (display) == GDM_DISPLAY_MANAGED) {
if (g_strcmp0 (active_session_id, login_session_id) != 0) {
+ g_debug ("GdmLocalDisplayFactory: session %s found, activating.",
+ login_session_id);
gdm_activate_session_by_id (factory->priv->connection, seat_id, login_session_id);
}
g_clear_pointer (&login_session_id, g_free);
g_clear_pointer (&active_session_id, g_free);
return NULL;
}
g_clear_pointer (&login_session_id, g_free);
}
g_clear_pointer (&active_session_id, g_free);
} else if (!sd_seat_can_multi_session (seat_id)) {
/* Ensure we don't create the same display more than once */
display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id);
if (display != NULL) {
return NULL;
}
}
g_debug ("GdmLocalDisplayFactory: Adding display on seat %s", seat_id);
#ifdef ENABLE_USER_DISPLAY_SERVER
if (g_strcmp0 (seat_id, "seat0") == 0) {
display = gdm_local_display_new ();
if (session_type != NULL) {
g_object_set (G_OBJECT (display), "session-type", session_type, NULL);
}
}
#endif
if (display == NULL) {
@@ -453,60 +457,61 @@ create_display (GdmLocalDisplayFactory *factory,
g_object_unref (display);
if (! gdm_display_manage (display)) {
gdm_display_unmanage (display);
}
return display;
}
static void
delete_display (GdmLocalDisplayFactory *factory,
const char *seat_id) {
GdmDisplayStore *store;
g_debug ("GdmLocalDisplayFactory: Removing used_display_numbers on seat %s", seat_id);
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
gdm_display_store_foreach_remove (store, lookup_by_seat_id, (gpointer) seat_id);
}
static gboolean
gdm_local_display_factory_sync_seats (GdmLocalDisplayFactory *factory)
{
GError *error = NULL;
GVariant *result;
GVariant *array;
GVariantIter iter;
const char *seat;
+ g_debug ("GdmLocalDisplayFactory: enumerating seats from logind");
result = g_dbus_connection_call_sync (factory->priv->connection,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"ListSeats",
NULL,
G_VARIANT_TYPE ("(a(so))"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, &error);
if (!result) {
g_warning ("GdmLocalDisplayFactory: Failed to issue method call: %s", error->message);
g_clear_error (&error);
return FALSE;
}
array = g_variant_get_child_value (result, 0);
g_variant_iter_init (&iter, array);
while (g_variant_iter_loop (&iter, "(&so)", &seat, NULL)) {
gboolean is_initial;
const char *session_type = NULL;
if (g_strcmp0 (seat, "seat0") == 0) {
is_initial = TRUE;
if (gdm_local_display_factory_use_wayland ())
session_type = "wayland";
} else {
is_initial = FALSE;
--
2.27.0

View File

@ -0,0 +1,162 @@
From abd8e1ef71d093a3ab5c110aea5fa2012d59d5e2 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 14 Aug 2018 10:21:17 -0400
Subject: [PATCH 21/51] local-display-factory: ignore spurios SeatNew signal at
start up
Sometimes during startup, logind will send a `SeatNew` signal for
seat0 after GDM has already called `ListSeats` and processed `seat0`.
That `SeatNew` signal leads to GDM calling `create_display` twice in
quick succession.
This commit changes GDM to avoid such double processing, by ignoring
the `create_display` requests for seats that already have a prepared
display ("prepared" means "starting up").
Closes: https://gitlab.gnome.org/GNOME/gdm/issues/410
---
daemon/gdm-local-display-factory.c | 33 +++++++++++++++++++++++-------
1 file changed, 26 insertions(+), 7 deletions(-)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 6f3a4c391..127127005 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -353,107 +353,126 @@ on_display_status_changed (GdmDisplay *display,
case GDM_DISPLAY_MANAGED:
break;
default:
g_assert_not_reached ();
break;
}
g_free (seat_id);
g_free (session_type);
g_free (session_class);
}
static gboolean
lookup_by_seat_id (const char *id,
GdmDisplay *display,
gpointer user_data)
{
const char *looking_for = user_data;
char *current;
gboolean res;
g_object_get (G_OBJECT (display), "seat-id", &current, NULL);
res = g_strcmp0 (current, looking_for) == 0;
g_free(current);
return res;
}
+static gboolean
+lookup_prepared_display_by_seat_id (const char *id,
+ GdmDisplay *display,
+ gpointer user_data)
+{
+ int status;
+
+ status = gdm_display_get_status (display);
+
+ if (status != GDM_DISPLAY_PREPARED)
+ return FALSE;
+
+ return lookup_by_seat_id (id, display, user_data);
+}
+
static GdmDisplay *
create_display (GdmLocalDisplayFactory *factory,
const char *seat_id,
const char *session_type,
gboolean initial)
{
GdmDisplayStore *store;
GdmDisplay *display = NULL;
char *active_session_id = NULL;
int ret;
g_debug ("GdmLocalDisplayFactory: %s login display for seat %s requested",
session_type? : "X11", seat_id);
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
+ if (sd_seat_can_multi_session (seat_id))
+ display = gdm_display_store_find (store, lookup_prepared_display_by_seat_id, (gpointer) seat_id);
+ else
+ display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id);
+
+ /* Ensure we don't create the same display more than once */
+ if (display != NULL) {
+ g_debug ("GdmLocalDisplayFactory: display already created");
+ return NULL;
+ }
+
ret = sd_seat_get_active (seat_id, &active_session_id, NULL);
if (ret == 0) {
char *login_session_id = NULL;
/* If we already have a login window, switch to it */
if (gdm_get_login_window_session_id (seat_id, &login_session_id)) {
GdmDisplay *display;
display = gdm_display_store_find (store,
lookup_by_session_id,
(gpointer) login_session_id);
if (display != NULL && gdm_display_get_status (display) == GDM_DISPLAY_MANAGED) {
if (g_strcmp0 (active_session_id, login_session_id) != 0) {
g_debug ("GdmLocalDisplayFactory: session %s found, activating.",
login_session_id);
gdm_activate_session_by_id (factory->priv->connection, seat_id, login_session_id);
}
g_clear_pointer (&login_session_id, g_free);
g_clear_pointer (&active_session_id, g_free);
return NULL;
}
g_clear_pointer (&login_session_id, g_free);
}
g_clear_pointer (&active_session_id, g_free);
- } else if (!sd_seat_can_multi_session (seat_id)) {
- /* Ensure we don't create the same display more than once */
- display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id);
-
- if (display != NULL) {
- return NULL;
- }
}
g_debug ("GdmLocalDisplayFactory: Adding display on seat %s", seat_id);
#ifdef ENABLE_USER_DISPLAY_SERVER
if (g_strcmp0 (seat_id, "seat0") == 0) {
display = gdm_local_display_new ();
if (session_type != NULL) {
g_object_set (G_OBJECT (display), "session-type", session_type, NULL);
}
}
#endif
if (display == NULL) {
guint32 num;
num = take_next_display_number (factory);
display = gdm_legacy_display_new (num);
}
g_object_set (display, "seat-id", seat_id, NULL);
g_object_set (display, "is-initial", initial, NULL);
store_display (factory, display);
/* let store own the ref */
g_object_unref (display);
if (! gdm_display_manage (display)) {
--
2.27.0

View File

@ -0,0 +1,91 @@
From 9b8c21080286f943d0a19431bc8c0061f4833443 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 30 Aug 2018 13:04:56 -0400
Subject: [PATCH 22/51] common: remove unnecessary free
This commit drops an erroneous free call, that would
potentially free a dangling pointer.
Luckily the error condition can never occur because the
error code checked is never returned, so the free call
is dead code.
This commit removes the free call. A subsequent commit
will fix the error code checking.
---
common/gdm-common.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/common/gdm-common.c b/common/gdm-common.c
index 59317a889..c909aceee 100644
--- a/common/gdm-common.c
+++ b/common/gdm-common.c
@@ -391,64 +391,62 @@ gdm_activate_session_by_id (GDBusConnection *connection,
return TRUE;
}
gboolean
gdm_get_login_window_session_id (const char *seat_id,
char **session_id)
{
gboolean ret;
int res, i;
char **sessions;
char *service_id;
char *service_class;
char *state;
res = sd_seat_get_sessions (seat_id, &sessions, NULL, NULL);
if (res < 0) {
g_debug ("Failed to determine sessions: %s", strerror (-res));
return FALSE;
}
if (sessions == NULL || sessions[0] == NULL) {
*session_id = NULL;
ret = FALSE;
goto out;
}
for (i = 0; sessions[i]; i ++) {
res = sd_session_get_class (sessions[i], &service_class);
if (res < 0) {
- if (res == -ENOENT) {
- free (service_class);
+ if (res == -ENOENT)
continue;
- }
g_debug ("failed to determine class of session %s: %s", sessions[i], strerror (-res));
ret = FALSE;
goto out;
}
if (strcmp (service_class, "greeter") != 0) {
free (service_class);
continue;
}
free (service_class);
ret = sd_session_get_state (sessions[i], &state);
if (ret < 0) {
g_debug ("failed to determine state of session %s: %s", sessions[i], strerror (-res));
ret = FALSE;
goto out;
}
if (g_strcmp0 (state, "closing") == 0) {
free (state);
continue;
}
free (state);
res = sd_session_get_service (sessions[i], &service_id);
if (res < 0) {
g_debug ("failed to determine service of session %s: %s", sessions[i], strerror (-res));
ret = FALSE;
--
2.27.0

View File

@ -0,0 +1,133 @@
From 4a948e4b203fdf5fcd9b5e53dd4a80ef2786c0cd Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 30 Aug 2018 13:06:54 -0400
Subject: [PATCH 23/51] common: don't bail if session disappears out from under
us
It's entirely possible for a session returned by
sd_seat_get_sessions to disappear immediately after the
sd_seat_get_sessions call returns. This is especially
likely at logout time where the session will briefly be
in the "closing" state before getting reaped.
If that happens when we're looking for a greeter session, we
stop looking for a greeter session and bail out all confused.
This commit fixes the confusion by gracefully handling the
session disappearing by just proceeding to the next session
in the list.
This commit is very similar to commit 155ee7eca which got
accidentally reverted during code consolidation. The main
difference is this commit checks the correct error code
of -ENXIO instead of -ENOENT, so it might actually fix
what it's ostensibly supposed to fix.
---
common/gdm-common.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/common/gdm-common.c b/common/gdm-common.c
index c909aceee..59b8dfc44 100644
--- a/common/gdm-common.c
+++ b/common/gdm-common.c
@@ -391,90 +391,96 @@ gdm_activate_session_by_id (GDBusConnection *connection,
return TRUE;
}
gboolean
gdm_get_login_window_session_id (const char *seat_id,
char **session_id)
{
gboolean ret;
int res, i;
char **sessions;
char *service_id;
char *service_class;
char *state;
res = sd_seat_get_sessions (seat_id, &sessions, NULL, NULL);
if (res < 0) {
g_debug ("Failed to determine sessions: %s", strerror (-res));
return FALSE;
}
if (sessions == NULL || sessions[0] == NULL) {
*session_id = NULL;
ret = FALSE;
goto out;
}
for (i = 0; sessions[i]; i ++) {
res = sd_session_get_class (sessions[i], &service_class);
if (res < 0) {
- if (res == -ENOENT)
+ if (res == -ENXIO)
continue;
g_debug ("failed to determine class of session %s: %s", sessions[i], strerror (-res));
ret = FALSE;
goto out;
}
if (strcmp (service_class, "greeter") != 0) {
free (service_class);
continue;
}
free (service_class);
ret = sd_session_get_state (sessions[i], &state);
if (ret < 0) {
+ if (res == -ENXIO)
+ continue;
+
g_debug ("failed to determine state of session %s: %s", sessions[i], strerror (-res));
ret = FALSE;
goto out;
}
if (g_strcmp0 (state, "closing") == 0) {
free (state);
continue;
}
free (state);
res = sd_session_get_service (sessions[i], &service_id);
if (res < 0) {
+ if (res == -ENXIO)
+ continue;
+
g_debug ("failed to determine service of session %s: %s", sessions[i], strerror (-res));
ret = FALSE;
goto out;
}
if (strcmp (service_id, "gdm-launch-environment") == 0) {
*session_id = g_strdup (sessions[i]);
ret = TRUE;
free (service_id);
goto out;
}
free (service_id);
}
*session_id = NULL;
ret = FALSE;
out:
if (sessions) {
for (i = 0; sessions[i]; i ++) {
free (sessions[i]);
}
free (sessions);
}
return ret;
}
--
2.27.0

View File

@ -0,0 +1,138 @@
From fac23cfa3e8e9fe21563733c0c1b739ddecead8a Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 30 Aug 2018 14:01:55 -0400
Subject: [PATCH 24/51] manager: better logind handling
commit 9ee68d5c8 highlights we've incorrectly
used ENOENT instead of ENXIO when checking for
non-existing sessions/seats with logind.
This commit mops up all the other cases.
---
daemon/gdm-manager.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 80f60d24c..367a731cc 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -361,113 +361,113 @@ find_session_for_user_on_seat (GdmManager *manager,
candidate_username);
if (g_strcmp0 (candidate_username, username) == 0 &&
g_strcmp0 (candidate_seat_id, seat_id) == 0) {
g_debug ("GdmManager: yes, found session %s", candidate_session_id);
return candidate_session;
}
g_debug ("GdmManager: no, will not use session %s", candidate_session_id);
}
g_debug ("GdmManager: no matching sessions found");
return NULL;
}
static gboolean
is_remote_session (GdmManager *self,
const char *session_id,
GError **error)
{
char *seat;
int ret;
gboolean is_remote;
/* FIXME: The next release of logind is going to have explicit api for
* checking remoteness.
*/
seat = NULL;
ret = sd_session_get_seat (session_id, &seat);
- if (ret < 0 && ret != -ENOENT) {
+ if (ret < 0 && ret != -ENXIO) {
g_debug ("GdmManager: Error while retrieving seat for session %s: %s",
session_id, strerror (-ret));
}
if (seat != NULL) {
is_remote = FALSE;
free (seat);
} else {
is_remote = TRUE;
}
return is_remote;
}
static char *
get_seat_id_for_session_id (const char *session_id,
GError **error)
{
int ret;
char *seat, *out_seat;
seat = NULL;
ret = sd_session_get_seat (session_id, &seat);
- if (ret == -ENOENT) {
+ if (ret == -ENXIO) {
out_seat = NULL;
} else if (ret < 0) {
g_set_error (error,
GDM_DISPLAY_ERROR,
GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
"Error getting uid for session id %s from systemd: %s",
session_id,
g_strerror (-ret));
out_seat = NULL;
} else {
out_seat = g_strdup (seat);
free (seat);
}
return out_seat;
}
static char *
get_tty_for_session_id (const char *session_id,
GError **error)
{
int ret;
char *tty, *out_tty;
ret = sd_session_get_tty (session_id, &tty);
- if (ret == -ENOENT) {
+ if (ret == -ENXIO) {
out_tty = NULL;
} else if (ret < 0) {
g_set_error (error,
GDM_DISPLAY_ERROR,
GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
"Error getting tty for session id %s from systemd: %s",
session_id,
g_strerror (-ret));
out_tty = NULL;
} else {
out_tty = g_strdup (tty);
free (tty);
}
return out_tty;
}
static void
get_display_and_details_for_bus_sender (GdmManager *self,
GDBusConnection *connection,
const char *sender,
GdmDisplay **out_display,
char **out_seat_id,
char **out_session_id,
char **out_tty,
GPid *out_pid,
uid_t *out_uid,
gboolean *out_is_login_screen,
gboolean *out_is_remote)
{
--
2.27.0

View File

@ -0,0 +1,90 @@
From cabcd21c17ca98e517a3eea7c9d5ce269445e3e0 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 31 Aug 2018 15:46:55 -0400
Subject: [PATCH 25/51] session-worker: clear VT before jumping to it
If we're going to jump to a new VT we should make sure it's free
of residual console text. That way if there's flicker the user
will be less likely to notice it.
This commit sends a clear screen escape sequence to the tty
before jumping to it.
---
daemon/gdm-session-worker.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 391969d96..7ed2789da 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -943,60 +943,67 @@ fix_terminal_vt_mode (GdmSessionWorker *worker,
}
/* VT is in the anti-social state of VT_AUTO + KD_GRAPHICS,
* fix it.
*/
succeeded = handle_terminal_vt_switches (worker, tty_fd);
mode_fixed = TRUE;
out:
if (!succeeded) {
g_error ("GdmSessionWorker: couldn't set up terminal, aborting...");
return;
}
g_debug ("GdmSessionWorker: VT mode did %sneed to be fixed",
mode_fixed? "" : "not ");
}
static void
jump_to_vt (GdmSessionWorker *worker,
int vt_number)
{
int fd;
int active_vt_tty_fd;
int active_vt = -1;
struct vt_stat vt_state = { 0 };
g_debug ("GdmSessionWorker: jumping to VT %d", vt_number);
active_vt_tty_fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
if (worker->priv->session_tty_fd != -1) {
+ static const char *clear_screen_escape_sequence = "\33[H\33[2J";
+
+ /* let's make sure the new VT is clear */
+ write (worker->priv->session_tty_fd,
+ clear_screen_escape_sequence,
+ sizeof (clear_screen_escape_sequence));
+
fd = worker->priv->session_tty_fd;
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_GETSTATE, &vt_state) < 0) {
g_debug ("GdmSessionWorker: couldn't get current VT: %m");
} else {
active_vt = vt_state.v_active;
}
if (active_vt != vt_number) {
if (ioctl (fd, VT_ACTIVATE, vt_number) < 0) {
g_debug ("GdmSessionWorker: couldn't initiate jump to VT %d: %m",
vt_number);
--
2.27.0

View File

@ -0,0 +1,133 @@
From b773eb570d8c5f9d2222ee39eecbc6a622d108d8 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 30 Aug 2018 16:04:41 -0400
Subject: [PATCH 26/51] manager: don't set ran_once after running initial-setup
GdmManager tracks whether or not the user session has ran
once, so it won't autologin a user again after logout.
Unfortunately the initial-setup session was counting toward the
ran_once count preventing initial-setup from logging the user
in afterward.
This commit prevents ran_once from getting set in that case.
---
daemon/gdm-manager.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 367a731cc..c8197a043 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1519,105 +1519,107 @@ set_up_session (GdmManager *manager,
operation->username = username;
g_signal_connect (user,
"notify::is-loaded",
G_CALLBACK (on_user_is_loaded_changed),
operation);
}
}
static void
greeter_display_started (GdmManager *manager,
GdmDisplay *display)
{
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 doing_initial_setup = FALSE;
gboolean quit_plymouth = FALSE;
g_object_get (display,
"is-local", &display_is_local,
+ "doing-initial-setup", &doing_initial_setup,
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);
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
- if (status == GDM_DISPLAY_FINISHED || g_strcmp0 (session_type, "x11") == 0) {
+ if (!doing_initial_setup && (status == GDM_DISPLAY_FINISHED || g_strcmp0 (session_type, "x11") == 0)) {
manager->priv->ran_once = TRUE;
}
maybe_start_pending_initial_login (manager, display);
break;
default:
break;
}
}
static void
on_display_removed (GdmDisplayStore *display_store,
GdmDisplay *display,
GdmManager *manager)
{
char *id;
gdm_display_get_id (display, &id, NULL);
g_dbus_object_manager_server_unexport (manager->priv->object_manager, id);
g_free (id);
g_signal_handlers_disconnect_by_func (display, G_CALLBACK (on_display_status_changed), manager);
g_signal_emit (manager, signals[DISPLAY_REMOVED], 0, display);
}
static void
destroy_start_user_session_operation (StartUserSessionOperation *operation)
{
g_object_set_data (G_OBJECT (operation->session),
--
2.27.0

View File

@ -0,0 +1,418 @@
From 3d4199f82136e7046b5b08fc7c583e3fce2d04a2 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 31 Aug 2018 14:33:58 -0400
Subject: [PATCH 27/51] manager: start initial setup right away
We no longer restart the greeter as soon as it dies, since we
start the greeter on demand. This means, we no longer need to
defer starting initial setup until after the greeter respawns.
Furthermore, it doesn't work anymore since it relied on the
respawn to trigger.
This commit removes that code and scaffolding and just starts
initial setup directly.
https://gitlab.gnome.org/GNOME/gdm/issues/415
---
daemon/gdm-manager.c | 66 +-------------------------------------------
1 file changed, 1 insertion(+), 65 deletions(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index c8197a043..fb7b1ec4b 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -62,62 +62,60 @@
#define GDM_MANAGER_DISPLAYS_PATH GDM_DBUS_PATH "/Displays"
#define INITIAL_SETUP_USERNAME "gnome-initial-setup"
typedef struct
{
GdmManager *manager;
GdmSession *session;
char *service_name;
guint idle_id;
} StartUserSessionOperation;
struct GdmManagerPrivate
{
GdmDisplayStore *display_store;
GdmLocalDisplayFactory *local_factory;
#ifdef HAVE_LIBXDMCP
GdmXdmcpDisplayFactory *xdmcp_factory;
#endif
GList *user_sessions;
GHashTable *transient_sessions;
GHashTable *open_reauthentication_requests;
gboolean xdmcp_enabled;
gboolean started;
gboolean show_local_greeter;
GDBusConnection *connection;
GDBusObjectManagerServer *object_manager;
- StartUserSessionOperation *initial_login_operation;
-
#ifdef WITH_PLYMOUTH
guint plymouth_is_running : 1;
#endif
guint ran_once : 1;
};
enum {
PROP_0,
PROP_XDMCP_ENABLED,
PROP_SHOW_LOCAL_GREETER
};
enum {
DISPLAY_ADDED,
DISPLAY_REMOVED,
LAST_SIGNAL
};
typedef enum {
SESSION_RECORD_LOGIN,
SESSION_RECORD_LOGOUT,
SESSION_RECORD_FAILED,
} SessionRecord;
static guint signals [LAST_SIGNAL] = { 0, };
static void gdm_manager_class_init (GdmManagerClass *klass);
static void gdm_manager_init (GdmManager *manager);
static void gdm_manager_dispose (GObject *object);
@@ -1286,96 +1284,60 @@ get_automatic_login_details (GdmManager *manager,
if (res && enabled) {
res = gdm_settings_direct_get_string (GDM_KEY_AUTO_LOGIN_USER, &username);
}
if (enabled && res && username != NULL && username[0] != '\0') {
goto out;
}
g_free (username);
username = NULL;
enabled = FALSE;
out:
if (enabled) {
g_debug ("GdmDisplay: Got automatic login details for display: %d %s",
enabled,
username);
} else {
g_debug ("GdmDisplay: Got automatic login details for display: 0");
}
if (usernamep != NULL) {
*usernamep = username;
} else {
g_free (username);
}
return enabled;
}
-static void
-maybe_start_pending_initial_login (GdmManager *manager,
- GdmDisplay *greeter_display)
-{
- StartUserSessionOperation *operation;
- char *greeter_seat_id = NULL;
- char *user_session_seat_id = NULL;
-
- /* There may be a user session waiting to be started.
- * This would happen if we couldn't start it earlier because
- * the login screen X server was coming up and two X servers
- * can't be started on the same seat at the same time.
- */
-
- if (manager->priv->initial_login_operation == NULL) {
- return;
- }
-
- operation = manager->priv->initial_login_operation;
-
- g_object_get (G_OBJECT (greeter_display),
- "seat-id", &greeter_seat_id,
- NULL);
- g_object_get (G_OBJECT (operation->session),
- "display-seat-id", &user_session_seat_id,
- NULL);
-
- if (g_strcmp0 (greeter_seat_id, user_session_seat_id) == 0) {
- start_user_session (manager, operation);
- manager->priv->initial_login_operation = NULL;
- }
-
- g_free (greeter_seat_id);
- g_free (user_session_seat_id);
-}
-
static const char *
get_username_for_greeter_display (GdmManager *manager,
GdmDisplay *display)
{
gboolean doing_initial_setup = FALSE;
g_object_get (G_OBJECT (display),
"doing-initial-setup", &doing_initial_setup,
NULL);
if (doing_initial_setup) {
return INITIAL_SETUP_USERNAME;
} else {
return GDM_USERNAME;
}
}
static void
set_up_automatic_login_session (GdmManager *manager,
GdmDisplay *display)
{
GdmSession *session;
char *display_session_type = NULL;
gboolean is_initial;
/* 0 is root user; since the daemon talks to the session object
* directly, itself, for automatic login
*/
session = create_user_session_for_display (manager, display, 0);
@@ -1498,131 +1460,115 @@ set_up_session (GdmManager *manager,
return;
}
#endif
set_up_greeter_session (manager, display);
return;
}
/* Check whether the user really exists before committing to autologin. */
user_manager = act_user_manager_get_default ();
user = act_user_manager_get_user (user_manager, username);
g_object_get (user_manager, "is-loaded", &loaded, NULL);
if (loaded) {
set_up_automatic_login_session_if_user_exists (manager, display, user);
} else {
UsernameLookupOperation *operation;
operation = g_new (UsernameLookupOperation, 1);
operation->manager = g_object_ref (manager);
operation->display = g_object_ref (display);
operation->username = username;
g_signal_connect (user,
"notify::is-loaded",
G_CALLBACK (on_user_is_loaded_changed),
operation);
}
}
-static void
-greeter_display_started (GdmManager *manager,
- GdmDisplay *display)
-{
- 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 doing_initial_setup = FALSE;
gboolean quit_plymouth = FALSE;
g_object_get (display,
"is-local", &display_is_local,
"doing-initial-setup", &doing_initial_setup,
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);
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
if (!doing_initial_setup && (status == GDM_DISPLAY_FINISHED || g_strcmp0 (session_type, "x11") == 0)) {
manager->priv->ran_once = TRUE;
}
- maybe_start_pending_initial_login (manager, display);
break;
default:
break;
}
}
static void
on_display_removed (GdmDisplayStore *display_store,
GdmDisplay *display,
GdmManager *manager)
{
char *id;
gdm_display_get_id (display, &id, NULL);
g_dbus_object_manager_server_unexport (manager->priv->object_manager, id);
g_free (id);
g_signal_handlers_disconnect_by_func (display, G_CALLBACK (on_display_status_changed), manager);
g_signal_emit (manager, signals[DISPLAY_REMOVED], 0, display);
}
static void
destroy_start_user_session_operation (StartUserSessionOperation *operation)
{
g_object_set_data (G_OBJECT (operation->session),
"start-user-session-operation",
NULL);
g_object_unref (operation->session);
@@ -1723,97 +1669,87 @@ on_start_user_session (StartUserSessionOperation *operation)
gdm_session_reset (operation->session);
destroy_start_user_session_operation (operation);
goto out;
}
display = get_display_for_user_session (operation->session);
g_object_get (G_OBJECT (display), "doing-initial-setup", &doing_initial_setup, NULL);
session_id = gdm_session_get_conversation_session_id (operation->session,
operation->service_name);
if (gdm_session_get_display_mode (operation->session) == GDM_SESSION_DISPLAY_MODE_REUSE_VT) {
/* In this case, the greeter's display is morphing into
* the user session display. Kill the greeter on this session
* and let the user session follow the same display. */
gdm_display_stop_greeter_session (display);
g_object_set (G_OBJECT (display),
"session-class", "user",
"session-id", session_id,
NULL);
} else {
uid_t allowed_uid;
g_object_ref (display);
if (doing_initial_setup) {
g_debug ("GdmManager: closing down initial setup display");
gdm_display_stop_greeter_session (display);
gdm_display_unmanage (display);
gdm_display_finish (display);
-
- /* We can't start the user session until the finished display
- * starts to respawn (since starting an X server and bringing
- * one down at the same time is a no go)
- */
- g_assert (self->priv->initial_login_operation == NULL);
- self->priv->initial_login_operation = operation;
- starting_user_session_right_away = FALSE;
} else {
g_debug ("GdmManager: session has its display server, reusing our server for another login screen");
}
/* The user session is going to follow the session worker
* into the new display. Untie it from this display and
* create a new session for a future user login. */
allowed_uid = gdm_session_get_allowed_user (operation->session);
g_object_set_data (G_OBJECT (display), "gdm-user-session", NULL);
g_object_set_data (G_OBJECT (operation->session), "gdm-display", NULL);
create_user_session_for_display (operation->manager, display, allowed_uid);
if ((g_strcmp0 (operation->service_name, "gdm-autologin") == 0) &&
!gdm_session_client_is_connected (operation->session)) {
/* remove the unused prepared greeter display since we're not going
* to have a greeter */
gdm_display_store_remove (self->priv->display_store, display);
g_object_unref (display);
}
/* Give the user session a new display object for bookkeeping purposes */
create_display_for_user_session (operation->manager,
operation->session,
session_id);
}
- if (starting_user_session_right_away) {
- start_user_session (operation->manager, operation);
- }
+ start_user_session (operation->manager, operation);
out:
return G_SOURCE_REMOVE;
}
static void
queue_start_user_session (GdmManager *manager,
GdmSession *session,
const char *service_name)
{
StartUserSessionOperation *operation;
operation = g_slice_new0 (StartUserSessionOperation);
operation->manager = manager;
operation->session = g_object_ref (session);
operation->service_name = g_strdup (service_name);
operation->idle_id = g_idle_add ((GSourceFunc) on_start_user_session, operation);
g_object_set_data (G_OBJECT (session), "start-user-session-operation", operation);
}
static void
start_user_session_if_ready (GdmManager *manager,
GdmSession *session,
const char *service_name)
{
gboolean start_when_ready;
start_when_ready = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (session), "start-when-ready"));
if (start_when_ready) {
--
2.27.0

View File

@ -0,0 +1,309 @@
From 3073c23c673ede5093c1f93fb0775c2cd3203d7f Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 30 Aug 2018 16:09:02 -0400
Subject: [PATCH 28/51] gdm-wayland-session,gdm-x-session: register after delay
Right now gdm-x-session registers with GDM as soon as the
X server is started, and gdm-wayland-session registers as
soon as the session is started.
Ideally registration wouldn't happen until the session
says things started successfully.
This commit inches us toward that ideal but adding a little
timeout before proceeding with registration.
A future commit will add a new xsession file key to allow
us to know whether or not the session manager of the session
supports doing registration.
---
daemon/gdm-wayland-session.c | 23 ++++++++++++++++-------
daemon/gdm-x-session.c | 25 +++++++++++++++++--------
2 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/daemon/gdm-wayland-session.c b/daemon/gdm-wayland-session.c
index 94f49e19c..de1991b34 100644
--- a/daemon/gdm-wayland-session.c
+++ b/daemon/gdm-wayland-session.c
@@ -427,60 +427,75 @@ init_state (State **state)
static State state_allocation;
*state = &state_allocation;
}
static void
clear_state (State **out_state)
{
State *state = *out_state;
g_clear_object (&state->cancellable);
g_clear_object (&state->bus_connection);
g_clear_object (&state->session_subprocess);
g_clear_pointer (&state->environment, g_strfreev);
g_clear_pointer (&state->main_loop, g_main_loop_unref);
*out_state = NULL;
}
static gboolean
on_sigterm (State *state)
{
g_cancellable_cancel (state->cancellable);
if (g_main_loop_is_running (state->main_loop)) {
g_main_loop_quit (state->main_loop);
}
return G_SOURCE_CONTINUE;
}
+static gboolean
+on_registration_delay_complete (State *state)
+{
+ gboolean ret;
+
+ ret = register_display (state, state->cancellable);
+
+ if (!ret) {
+ g_printerr ("Unable to register display with display manager\n");
+ g_main_loop_quit (state->main_loop);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
int
main (int argc,
char **argv)
{
State *state = NULL;
GOptionContext *context = NULL;
static char **args = NULL;
gboolean debug = FALSE;
gboolean ret;
int exit_status = EX_OK;
static GOptionEntry entries [] = {
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, "", "" },
{ NULL }
};
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
textdomain (GETTEXT_PACKAGE);
setlocale (LC_ALL, "");
gdm_log_init ();
context = g_option_context_new (_("GNOME Display Manager Wayland Session Launcher"));
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_parse (context, &argc, &argv, NULL);
g_option_context_free (context);
if (args == NULL || args[0] == NULL || args[1] != NULL) {
g_warning ("gdm-wayland-session takes one argument (the session)");
exit_status = EX_USAGE;
@@ -501,55 +516,49 @@ main (int argc,
}
gdm_settings_direct_get_boolean (GDM_KEY_DEBUG, &debug);
state->debug_enabled = debug;
gdm_log_set_debug (debug);
state->main_loop = g_main_loop_new (NULL, FALSE);
state->cancellable = g_cancellable_new ();
g_unix_signal_add (SIGTERM, (GSourceFunc) on_sigterm, state);
ret = spawn_bus (state, state->cancellable);
if (!ret) {
g_printerr ("Unable to run session message bus\n");
exit_status = EX_SOFTWARE;
goto out;
}
import_environment (state, state->cancellable);
ret = spawn_session (state, state->cancellable);
if (!ret) {
g_printerr ("Unable to run session\n");
exit_status = EX_SOFTWARE;
goto out;
}
- ret = register_display (state, state->cancellable);
-
- if (!ret) {
- g_printerr ("Unable to register display with display manager\n");
- exit_status = EX_SOFTWARE;
- goto out;
- }
+ g_timeout_add_seconds (2, (GSourceFunc) on_registration_delay_complete, state);
g_main_loop_run (state->main_loop);
/* Only use exit status of session if we're here because it exit */
if (state->session_subprocess == NULL) {
exit_status = state->session_exit_status;
}
out:
if (state != NULL) {
signal_subprocesses (state);
wait_on_subprocesses (state);
clear_state (&state);
}
return exit_status;
}
diff --git a/daemon/gdm-x-session.c b/daemon/gdm-x-session.c
index 3b2fcef47..412999cf5 100644
--- a/daemon/gdm-x-session.c
+++ b/daemon/gdm-x-session.c
@@ -783,60 +783,75 @@ init_state (State **state)
}
static void
clear_state (State **out_state)
{
State *state = *out_state;
g_clear_object (&state->cancellable);
g_clear_object (&state->bus_connection);
g_clear_object (&state->session_subprocess);
g_clear_object (&state->x_subprocess);
g_clear_pointer (&state->environment, g_strfreev);
g_clear_pointer (&state->auth_file, g_free);
g_clear_pointer (&state->display_name, g_free);
g_clear_pointer (&state->main_loop, g_main_loop_unref);
*out_state = NULL;
}
static gboolean
on_sigterm (State *state)
{
g_cancellable_cancel (state->cancellable);
if (g_main_loop_is_running (state->main_loop)) {
g_main_loop_quit (state->main_loop);
}
return G_SOURCE_CONTINUE;
}
+static gboolean
+on_registration_delay_complete (State *state)
+{
+ gboolean ret;
+
+ ret = register_display (state, state->cancellable);
+
+ if (!ret) {
+ g_printerr ("Unable to register display with display manager\n");
+ g_main_loop_quit (state->main_loop);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
int
main (int argc,
char **argv)
{
State *state = NULL;
GOptionContext *context = NULL;
static char **args = NULL;
static gboolean run_script = FALSE;
static gboolean allow_remote_connections = FALSE;
gboolean debug = FALSE;
gboolean ret;
int exit_status = EX_OK;
static GOptionEntry entries [] = {
{ "run-script", 'r', 0, G_OPTION_ARG_NONE, &run_script, N_("Run program through /etc/gdm/Xsession wrapper script"), NULL },
{ "allow-remote-connections", 'a', 0, G_OPTION_ARG_NONE, &allow_remote_connections, N_("Listen on TCP socket"), NULL },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, "", "" },
{ NULL }
};
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
textdomain (GETTEXT_PACKAGE);
setlocale (LC_ALL, "");
gdm_log_init ();
context = g_option_context_new (_("GNOME Display Manager X Session Launcher"));
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_parse (context, &argc, &argv, NULL);
g_option_context_free (context);
@@ -869,63 +884,57 @@ main (int argc,
state->cancellable = g_cancellable_new ();
g_unix_signal_add (SIGTERM, (GSourceFunc) on_sigterm, state);
ret = spawn_x_server (state, allow_remote_connections, state->cancellable);
if (!ret) {
g_printerr ("Unable to run X server\n");
exit_status = EX_SOFTWARE;
goto out;
}
ret = spawn_bus (state, state->cancellable);
if (!ret) {
g_printerr ("Unable to run session message bus\n");
exit_status = EX_SOFTWARE;
goto out;
}
import_environment (state, state->cancellable);
ret = update_bus_environment (state, state->cancellable);
if (!ret) {
g_printerr ("Unable to update bus environment\n");
exit_status = EX_SOFTWARE;
goto out;
}
- ret = register_display (state, state->cancellable);
-
- if (!ret) {
- g_printerr ("Unable to register display with display manager\n");
- exit_status = EX_SOFTWARE;
- goto out;
- }
-
ret = spawn_session (state, run_script, state->cancellable);
if (!ret) {
g_printerr ("Unable to run session\n");
exit_status = EX_SOFTWARE;
goto out;
}
+ g_timeout_add_seconds (2, (GSourceFunc) on_registration_delay_complete, state);
+
g_main_loop_run (state->main_loop);
/* Only use exit status of session if we're here because it exit */
if (state->session_subprocess == NULL) {
exit_status = state->session_exit_status;
}
out:
if (state != NULL) {
signal_subprocesses (state);
wait_on_subprocesses (state);
clear_state (&state);
}
return exit_status;
}
--
2.27.0

View File

@ -0,0 +1,399 @@
From d85448e2e523deb1487e7e405a480e1c4e6a5f6f Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 31 Aug 2018 15:33:00 -0400
Subject: [PATCH 29/51] local-display-factory: defer killing greeter until new
session registers
At the moment we kill the greeter the second the VT change to the new
session happens.
That can cause flicker if the new session doesn't take over the display
quickly enough.
This commit defers killing the greeter until the new display registers.
Closes https://gitlab.gnome.org/GNOME/gdm/issues/413
---
daemon/gdm-display.h | 1 +
daemon/gdm-local-display-factory.c | 43 +++++++++++++++++++++++++-----
2 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/daemon/gdm-display.h b/daemon/gdm-display.h
index 6d5e88df9..33dc3be41 100644
--- a/daemon/gdm-display.h
+++ b/daemon/gdm-display.h
@@ -13,60 +13,61 @@
* 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_DISPLAY_H
#define __GDM_DISPLAY_H
#include <glib-object.h>
#include <gio/gio.h>
G_BEGIN_DECLS
#define GDM_TYPE_DISPLAY (gdm_display_get_type ())
#define GDM_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_DISPLAY, GdmDisplay))
#define GDM_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_DISPLAY, GdmDisplayClass))
#define GDM_IS_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_DISPLAY))
#define GDM_IS_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_DISPLAY))
#define GDM_DISPLAY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_DISPLAY, GdmDisplayClass))
typedef struct GdmDisplayPrivate GdmDisplayPrivate;
typedef enum {
GDM_DISPLAY_UNMANAGED = 0,
GDM_DISPLAY_PREPARED,
GDM_DISPLAY_MANAGED,
+ GDM_DISPLAY_WAITING_TO_FINISH,
GDM_DISPLAY_FINISHED,
GDM_DISPLAY_FAILED,
} GdmDisplayStatus;
typedef struct
{
GObject parent;
GdmDisplayPrivate *priv;
} GdmDisplay;
typedef struct
{
GObjectClass parent_class;
/* methods */
gboolean (*prepare) (GdmDisplay *display);
void (*manage) (GdmDisplay *self);
} GdmDisplayClass;
typedef enum
{
GDM_DISPLAY_ERROR_GENERAL,
GDM_DISPLAY_ERROR_GETTING_USER_INFO,
GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
} GdmDisplayError;
#define GDM_DISPLAY_ERROR gdm_display_error_quark ()
GQuark gdm_display_error_quark (void);
GType gdm_display_get_type (void);
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 127127005..bc6ac6855 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -241,60 +241,90 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact
display = gdm_legacy_display_new (num);
}
#endif
g_object_set (display,
"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 gboolean
+finish_display_on_seat_if_waiting (GdmDisplayStore *display_store,
+ GdmDisplay *display,
+ const char *seat_id)
+{
+ if (gdm_display_get_status (display) != GDM_DISPLAY_WAITING_TO_FINISH)
+ return FALSE;
+
+ g_debug ("GdmLocalDisplayFactory: finish background display\n");
+ gdm_display_stop_greeter_session (display);
+ gdm_display_unmanage (display);
+ gdm_display_finish (display);
+
+ return FALSE;
+}
+
+static void
+finish_waiting_displays_on_seat (GdmLocalDisplayFactory *factory,
+ const char *seat_id)
+{
+ GdmDisplayStore *store;
+
+ store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
+
+ gdm_display_store_foreach (store,
+ (GdmDisplayStoreFunc) finish_display_on_seat_if_waiting,
+ (gpointer)
+ seat_id);
+}
+
static void
on_display_status_changed (GdmDisplay *display,
GParamSpec *arg1,
GdmLocalDisplayFactory *factory)
{
int status;
int num;
char *seat_id = NULL;
char *session_type = NULL;
char *session_class = NULL;
gboolean is_initial = TRUE;
gboolean is_local = TRUE;
num = -1;
gdm_display_get_x11_display_number (display, &num, NULL);
g_object_get (display,
"seat-id", &seat_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
@@ -324,60 +354,63 @@ on_display_status_changed (GdmDisplay *display,
/* 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;
/* workaround logind race for now
* bug 1643874
*/
g_usleep (2 * G_USEC_PER_SEC);
}
#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:
+ finish_waiting_displays_on_seat (factory, seat_id);
+ break;
+ case GDM_DISPLAY_WAITING_TO_FINISH:
break;
default:
g_assert_not_reached ();
break;
}
g_free (seat_id);
g_free (session_type);
g_free (session_class);
}
static gboolean
lookup_by_seat_id (const char *id,
GdmDisplay *display,
gpointer user_data)
{
const char *looking_for = user_data;
char *current;
gboolean res;
g_object_get (G_OBJECT (display), "seat-id", &current, NULL);
res = g_strcmp0 (current, looking_for) == 0;
g_free(current);
return res;
}
static gboolean
@@ -561,84 +594,82 @@ on_seat_new (GDBusConnection *connection,
static void
on_seat_removed (GDBusConnection *connection,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
const char *seat;
g_variant_get (parameters, "(&s&o)", &seat, NULL);
delete_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat);
}
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
static gboolean
lookup_by_session_id (const char *id,
GdmDisplay *display,
gpointer user_data)
{
const char *looking_for = user_data;
const char *current;
current = gdm_display_get_session_id (display);
return g_strcmp0 (current, looking_for) == 0;
}
static void
-maybe_stop_greeter_display (GdmDisplay *display)
+maybe_stop_greeter_in_background (GdmDisplay *display)
{
g_autofree char *display_session_type = NULL;
if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED) {
g_debug ("GdmLocalDisplayFactory: login window not in managed state, so ignoring");
return;
}
g_object_get (G_OBJECT (display),
"session-type", &display_session_type,
NULL);
/* we can only stop greeter for wayland sessions, since
* X server would jump back on exit */
if (g_strcmp0 (display_session_type, "wayland") != 0) {
g_debug ("GdmLocalDisplayFactory: login window is running on Xorg, so ignoring");
return;
}
- g_debug ("GdmLocalDisplayFactory: killing login window since its now unused");
- gdm_display_stop_greeter_session (display);
- gdm_display_unmanage (display);
- gdm_display_finish (display);
+ g_debug ("GdmLocalDisplayFactory: killing login window once its unused");
+ g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL);
}
static gboolean
on_vt_changed (GIOChannel *source,
GIOCondition condition,
GdmLocalDisplayFactory *factory)
{
GIOStatus status;
static const char *tty_of_initial_vt = "tty" GDM_INITIAL_VT;
g_autofree char *tty_of_previous_vt = NULL;
g_autofree char *tty_of_active_vt = NULL;
g_autofree char *login_session_id = NULL;
g_autofree char *active_session_id = NULL;
const char *session_type = NULL;
int ret;
g_debug ("GdmLocalDisplayFactory: received VT change event");
g_io_channel_seek_position (source, 0, G_SEEK_SET, NULL);
if (condition & G_IO_PRI) {
g_autoptr (GError) error = NULL;
status = g_io_channel_read_line (source, &tty_of_active_vt, NULL, NULL, &error);
if (error != NULL) {
g_warning ("could not read active VT from kernel: %s", error->message);
}
switch (status) {
case G_IO_STATUS_ERROR:
return G_SOURCE_REMOVE;
case G_IO_STATUS_EOF:
@@ -678,61 +709,61 @@ on_vt_changed (GIOChannel *source,
return G_SOURCE_CONTINUE;
}
g_debug ("GdmLocalDisplayFactory: VT changed from %s to %s",
tty_of_previous_vt, factory->priv->tty_of_active_vt);
/* if the old VT was running a wayland login screen kill it
*/
if (gdm_get_login_window_session_id ("seat0", &login_session_id)) {
unsigned int vt;
ret = sd_session_get_vt (login_session_id, &vt);
if (ret == 0 && vt != 0) {
g_autofree char *tty_of_login_window_vt = NULL;
tty_of_login_window_vt = g_strdup_printf ("tty%u", vt);
g_debug ("GdmLocalDisplayFactory: tty of login window is %s", tty_of_login_window_vt);
if (g_strcmp0 (tty_of_login_window_vt, tty_of_previous_vt) == 0) {
GdmDisplayStore *store;
GdmDisplay *display;
g_debug ("GdmLocalDisplayFactory: VT switched from login window");
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
display = gdm_display_store_find (store,
lookup_by_session_id,
(gpointer) login_session_id);
if (display != NULL)
- maybe_stop_greeter_display (display);
+ maybe_stop_greeter_in_background (display);
} else {
g_debug ("GdmLocalDisplayFactory: VT not switched from login window");
}
}
}
/* if user jumped back to initial vt and it's empty put a login screen
* on it (unless a login screen is already running elsewhere, then
* jump to that login screen)
*/
if (strcmp (factory->priv->tty_of_active_vt, tty_of_initial_vt) != 0) {
g_debug ("GdmLocalDisplayFactory: active VT is not initial VT, so ignoring");
return G_SOURCE_CONTINUE;
}
ret = sd_seat_get_active ("seat0", &active_session_id, NULL);
if (ret == 0) {
g_autofree char *state = NULL;
ret = sd_session_get_state (active_session_id, &state);
/* if there's something already running on the active VT then bail */
if (ret == 0 && g_strcmp0 (state, "closing") != 0) {
g_debug ("GdmLocalDisplayFactory: initial VT is in use, so ignoring");
return G_SOURCE_CONTINUE;
}
}
if (gdm_local_display_factory_use_wayland ())
session_type = "wayland";
--
2.27.0

View File

@ -0,0 +1,708 @@
From 0ff911467265831006aac6216060dbecff84c1cb Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Tue, 4 Sep 2018 10:56:45 +0200
Subject: [PATCH 30/51] daemon: Move the waiting the session to have taken over
the fb to gdm-local-display-factory
Commit 708618746683 ("gdm-wayland-session,gdm-x-session: register after
delay") delayed displays changing their status from PREPARED to MANAGED
so that their status would not change until the session has had a change
to install its own framebuffer and tell the GPU to scanout this new fb.
Commit 74ee77717df7 ("local-display-factory: defer killing greeter until
new session registers") uses this to avoid a flicker when transitioning
from the greeter to the user-session by deferring the stopping of the
greeter-session until the new display moves to the MANAGED state.
But this only works when transitioning to a new user-session, when moving
to an existing user-session (fast user switching) the display already
is in MANAGED state and instead of deferring the stopping of the greeter
commit 74ee77717df7 causes us to now never stop the greeter-session.
This commit fixes this by starting a timeout when switching away from
the initial-vt and letting that timeout stop the greeter-session.
This commit removes the finish_waiting_displays_on_seat() call when the
display's status changes to MANAGED, so that we still only have one code
path stopping the greeter and not two.
This means we also no longer need to delay registering the display. So this
commit removes the code adding the delay (reverts commit 74ee77717df7).
Note this commit uses a delay of 10 seconds, rather then 2 seconds. The
transition to a new user-session takes about 8 seconds on my budget
Apollo Lake based laptop (with SSD).
Note this all really is a workaround, the proper solution for this would
be able to tell the kernel to keep the greeter framebuffer around until
a new framebuffer is installed. There is a patch to add a new unref_fb
ioctl for this: https://www.spinics.net/lists/dri-devel/msg140912.html .
We need to get this patch upstream and teach mutter to use it.
---
daemon/gdm-local-display-factory.c | 29 ++++++++++++++++++++++++++---
daemon/gdm-wayland-session.c | 23 +++++++----------------
daemon/gdm-x-session.c | 25 ++++++++-----------------
3 files changed, 41 insertions(+), 36 deletions(-)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index bc6ac6855..be6b377be 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -22,76 +22,78 @@
#include <stdlib.h>
#include <stdio.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include <gio/gio.h>
#include <systemd/sd-login.h>
#include "gdm-common.h"
#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
+#define WAIT_TO_FINISH_TIMEOUT 10 /* seconds */
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;
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
char *tty_of_active_vt;
guint active_vt_watch_id;
+ guint wait_to_finish_timeout_id;
#endif
};
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;
static gboolean lookup_by_session_id (const char *id,
GdmDisplay *display,
gpointer user_data);
G_DEFINE_TYPE (GdmLocalDisplayFactory, gdm_local_display_factory, GDM_TYPE_DISPLAY_FACTORY)
GQuark
gdm_local_display_factory_error_quark (void)
@@ -354,61 +356,60 @@ on_display_status_changed (GdmDisplay *display,
/* 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;
/* workaround logind race for now
* bug 1643874
*/
g_usleep (2 * G_USEC_PER_SEC);
}
#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:
- finish_waiting_displays_on_seat (factory, seat_id);
break;
case GDM_DISPLAY_WAITING_TO_FINISH:
break;
default:
g_assert_not_reached ();
break;
}
g_free (seat_id);
g_free (session_type);
g_free (session_class);
}
static gboolean
lookup_by_seat_id (const char *id,
GdmDisplay *display,
gpointer user_data)
{
const char *looking_for = user_data;
char *current;
gboolean res;
g_object_get (G_OBJECT (display), "seat-id", &current, NULL);
res = g_strcmp0 (current, looking_for) == 0;
g_free(current);
return res;
}
@@ -593,83 +594,101 @@ on_seat_new (GDBusConnection *connection,
}
static void
on_seat_removed (GDBusConnection *connection,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
const char *seat;
g_variant_get (parameters, "(&s&o)", &seat, NULL);
delete_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat);
}
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
static gboolean
lookup_by_session_id (const char *id,
GdmDisplay *display,
gpointer user_data)
{
const char *looking_for = user_data;
const char *current;
current = gdm_display_get_session_id (display);
return g_strcmp0 (current, looking_for) == 0;
}
+static gboolean
+wait_to_finish_timeout (GdmLocalDisplayFactory *factory)
+{
+ finish_waiting_displays_on_seat (factory, "seat0");
+ factory->priv->wait_to_finish_timeout_id = 0;
+ return G_SOURCE_REMOVE;
+}
+
static void
-maybe_stop_greeter_in_background (GdmDisplay *display)
+maybe_stop_greeter_in_background (GdmLocalDisplayFactory *factory,
+ GdmDisplay *display)
{
g_autofree char *display_session_type = NULL;
if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED) {
g_debug ("GdmLocalDisplayFactory: login window not in managed state, so ignoring");
return;
}
g_object_get (G_OBJECT (display),
"session-type", &display_session_type,
NULL);
/* we can only stop greeter for wayland sessions, since
* X server would jump back on exit */
if (g_strcmp0 (display_session_type, "wayland") != 0) {
g_debug ("GdmLocalDisplayFactory: login window is running on Xorg, so ignoring");
return;
}
g_debug ("GdmLocalDisplayFactory: killing login window once its unused");
g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL);
+
+ /* We stop the greeter after a timeout to avoid flicker */
+ if (factory->priv->wait_to_finish_timeout_id != 0)
+ g_source_remove (factory->priv->wait_to_finish_timeout_id);
+
+ factory->priv->wait_to_finish_timeout_id =
+ g_timeout_add_seconds (WAIT_TO_FINISH_TIMEOUT,
+ (GSourceFunc)wait_to_finish_timeout,
+ factory);
}
static gboolean
on_vt_changed (GIOChannel *source,
GIOCondition condition,
GdmLocalDisplayFactory *factory)
{
GIOStatus status;
static const char *tty_of_initial_vt = "tty" GDM_INITIAL_VT;
g_autofree char *tty_of_previous_vt = NULL;
g_autofree char *tty_of_active_vt = NULL;
g_autofree char *login_session_id = NULL;
g_autofree char *active_session_id = NULL;
const char *session_type = NULL;
int ret;
g_debug ("GdmLocalDisplayFactory: received VT change event");
g_io_channel_seek_position (source, 0, G_SEEK_SET, NULL);
if (condition & G_IO_PRI) {
g_autoptr (GError) error = NULL;
status = g_io_channel_read_line (source, &tty_of_active_vt, NULL, NULL, &error);
if (error != NULL) {
g_warning ("could not read active VT from kernel: %s", error->message);
}
switch (status) {
case G_IO_STATUS_ERROR:
return G_SOURCE_REMOVE;
case G_IO_STATUS_EOF:
@@ -709,61 +728,61 @@ on_vt_changed (GIOChannel *source,
return G_SOURCE_CONTINUE;
}
g_debug ("GdmLocalDisplayFactory: VT changed from %s to %s",
tty_of_previous_vt, factory->priv->tty_of_active_vt);
/* if the old VT was running a wayland login screen kill it
*/
if (gdm_get_login_window_session_id ("seat0", &login_session_id)) {
unsigned int vt;
ret = sd_session_get_vt (login_session_id, &vt);
if (ret == 0 && vt != 0) {
g_autofree char *tty_of_login_window_vt = NULL;
tty_of_login_window_vt = g_strdup_printf ("tty%u", vt);
g_debug ("GdmLocalDisplayFactory: tty of login window is %s", tty_of_login_window_vt);
if (g_strcmp0 (tty_of_login_window_vt, tty_of_previous_vt) == 0) {
GdmDisplayStore *store;
GdmDisplay *display;
g_debug ("GdmLocalDisplayFactory: VT switched from login window");
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
display = gdm_display_store_find (store,
lookup_by_session_id,
(gpointer) login_session_id);
if (display != NULL)
- maybe_stop_greeter_in_background (display);
+ maybe_stop_greeter_in_background (factory, display);
} else {
g_debug ("GdmLocalDisplayFactory: VT not switched from login window");
}
}
}
/* if user jumped back to initial vt and it's empty put a login screen
* on it (unless a login screen is already running elsewhere, then
* jump to that login screen)
*/
if (strcmp (factory->priv->tty_of_active_vt, tty_of_initial_vt) != 0) {
g_debug ("GdmLocalDisplayFactory: active VT is not initial VT, so ignoring");
return G_SOURCE_CONTINUE;
}
ret = sd_seat_get_active ("seat0", &active_session_id, NULL);
if (ret == 0) {
g_autofree char *state = NULL;
ret = sd_session_get_state (active_session_id, &state);
/* if there's something already running on the active VT then bail */
if (ret == 0 && g_strcmp0 (state, "closing") != 0) {
g_debug ("GdmLocalDisplayFactory: initial VT is in use, so ignoring");
return G_SOURCE_CONTINUE;
}
}
if (gdm_local_display_factory_use_wayland ())
session_type = "wayland";
@@ -803,60 +822,64 @@ gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory)
g_object_unref);
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
io_channel = g_io_channel_new_file ("/sys/class/tty/tty0/active", "r", NULL);
if (io_channel != NULL) {
factory->priv->active_vt_watch_id =
g_io_add_watch (io_channel,
G_IO_PRI,
(GIOFunc)
on_vt_changed,
factory);
}
#endif
}
static void
gdm_local_display_factory_stop_monitor (GdmLocalDisplayFactory *factory)
{
if (factory->priv->seat_new_id) {
g_dbus_connection_signal_unsubscribe (factory->priv->connection,
factory->priv->seat_new_id);
factory->priv->seat_new_id = 0;
}
if (factory->priv->seat_removed_id) {
g_dbus_connection_signal_unsubscribe (factory->priv->connection,
factory->priv->seat_removed_id);
factory->priv->seat_removed_id = 0;
}
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
+ if (factory->priv->wait_to_finish_timeout_id != 0) {
+ g_source_remove (factory->priv->wait_to_finish_timeout_id);
+ factory->priv->wait_to_finish_timeout_id = 0;
+ }
if (factory->priv->active_vt_watch_id) {
g_source_remove (factory->priv->active_vt_watch_id);
factory->priv->active_vt_watch_id = 0;
}
g_clear_pointer (&factory->priv->tty_of_active_vt, g_free);
#endif
}
static void
on_display_added (GdmDisplayStore *display_store,
const char *id,
GdmLocalDisplayFactory *factory)
{
GdmDisplay *display;
display = gdm_display_store_lookup (display_store, id);
if (display != NULL) {
g_signal_connect_object (display, "notify::status",
G_CALLBACK (on_display_status_changed),
factory,
0);
g_object_weak_ref (G_OBJECT (display), (GWeakNotify)on_display_disposed, factory);
}
}
static void
on_display_removed (GdmDisplayStore *display_store,
diff --git a/daemon/gdm-wayland-session.c b/daemon/gdm-wayland-session.c
index de1991b34..94f49e19c 100644
--- a/daemon/gdm-wayland-session.c
+++ b/daemon/gdm-wayland-session.c
@@ -427,75 +427,60 @@ init_state (State **state)
static State state_allocation;
*state = &state_allocation;
}
static void
clear_state (State **out_state)
{
State *state = *out_state;
g_clear_object (&state->cancellable);
g_clear_object (&state->bus_connection);
g_clear_object (&state->session_subprocess);
g_clear_pointer (&state->environment, g_strfreev);
g_clear_pointer (&state->main_loop, g_main_loop_unref);
*out_state = NULL;
}
static gboolean
on_sigterm (State *state)
{
g_cancellable_cancel (state->cancellable);
if (g_main_loop_is_running (state->main_loop)) {
g_main_loop_quit (state->main_loop);
}
return G_SOURCE_CONTINUE;
}
-static gboolean
-on_registration_delay_complete (State *state)
-{
- gboolean ret;
-
- ret = register_display (state, state->cancellable);
-
- if (!ret) {
- g_printerr ("Unable to register display with display manager\n");
- g_main_loop_quit (state->main_loop);
- }
-
- return G_SOURCE_REMOVE;
-}
-
int
main (int argc,
char **argv)
{
State *state = NULL;
GOptionContext *context = NULL;
static char **args = NULL;
gboolean debug = FALSE;
gboolean ret;
int exit_status = EX_OK;
static GOptionEntry entries [] = {
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, "", "" },
{ NULL }
};
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
textdomain (GETTEXT_PACKAGE);
setlocale (LC_ALL, "");
gdm_log_init ();
context = g_option_context_new (_("GNOME Display Manager Wayland Session Launcher"));
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_parse (context, &argc, &argv, NULL);
g_option_context_free (context);
if (args == NULL || args[0] == NULL || args[1] != NULL) {
g_warning ("gdm-wayland-session takes one argument (the session)");
exit_status = EX_USAGE;
@@ -516,49 +501,55 @@ main (int argc,
}
gdm_settings_direct_get_boolean (GDM_KEY_DEBUG, &debug);
state->debug_enabled = debug;
gdm_log_set_debug (debug);
state->main_loop = g_main_loop_new (NULL, FALSE);
state->cancellable = g_cancellable_new ();
g_unix_signal_add (SIGTERM, (GSourceFunc) on_sigterm, state);
ret = spawn_bus (state, state->cancellable);
if (!ret) {
g_printerr ("Unable to run session message bus\n");
exit_status = EX_SOFTWARE;
goto out;
}
import_environment (state, state->cancellable);
ret = spawn_session (state, state->cancellable);
if (!ret) {
g_printerr ("Unable to run session\n");
exit_status = EX_SOFTWARE;
goto out;
}
- g_timeout_add_seconds (2, (GSourceFunc) on_registration_delay_complete, state);
+ ret = register_display (state, state->cancellable);
+
+ if (!ret) {
+ g_printerr ("Unable to register display with display manager\n");
+ exit_status = EX_SOFTWARE;
+ goto out;
+ }
g_main_loop_run (state->main_loop);
/* Only use exit status of session if we're here because it exit */
if (state->session_subprocess == NULL) {
exit_status = state->session_exit_status;
}
out:
if (state != NULL) {
signal_subprocesses (state);
wait_on_subprocesses (state);
clear_state (&state);
}
return exit_status;
}
diff --git a/daemon/gdm-x-session.c b/daemon/gdm-x-session.c
index 412999cf5..3b2fcef47 100644
--- a/daemon/gdm-x-session.c
+++ b/daemon/gdm-x-session.c
@@ -783,75 +783,60 @@ init_state (State **state)
}
static void
clear_state (State **out_state)
{
State *state = *out_state;
g_clear_object (&state->cancellable);
g_clear_object (&state->bus_connection);
g_clear_object (&state->session_subprocess);
g_clear_object (&state->x_subprocess);
g_clear_pointer (&state->environment, g_strfreev);
g_clear_pointer (&state->auth_file, g_free);
g_clear_pointer (&state->display_name, g_free);
g_clear_pointer (&state->main_loop, g_main_loop_unref);
*out_state = NULL;
}
static gboolean
on_sigterm (State *state)
{
g_cancellable_cancel (state->cancellable);
if (g_main_loop_is_running (state->main_loop)) {
g_main_loop_quit (state->main_loop);
}
return G_SOURCE_CONTINUE;
}
-static gboolean
-on_registration_delay_complete (State *state)
-{
- gboolean ret;
-
- ret = register_display (state, state->cancellable);
-
- if (!ret) {
- g_printerr ("Unable to register display with display manager\n");
- g_main_loop_quit (state->main_loop);
- }
-
- return G_SOURCE_REMOVE;
-}
-
int
main (int argc,
char **argv)
{
State *state = NULL;
GOptionContext *context = NULL;
static char **args = NULL;
static gboolean run_script = FALSE;
static gboolean allow_remote_connections = FALSE;
gboolean debug = FALSE;
gboolean ret;
int exit_status = EX_OK;
static GOptionEntry entries [] = {
{ "run-script", 'r', 0, G_OPTION_ARG_NONE, &run_script, N_("Run program through /etc/gdm/Xsession wrapper script"), NULL },
{ "allow-remote-connections", 'a', 0, G_OPTION_ARG_NONE, &allow_remote_connections, N_("Listen on TCP socket"), NULL },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, "", "" },
{ NULL }
};
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
textdomain (GETTEXT_PACKAGE);
setlocale (LC_ALL, "");
gdm_log_init ();
context = g_option_context_new (_("GNOME Display Manager X Session Launcher"));
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_parse (context, &argc, &argv, NULL);
g_option_context_free (context);
@@ -884,57 +869,63 @@ main (int argc,
state->cancellable = g_cancellable_new ();
g_unix_signal_add (SIGTERM, (GSourceFunc) on_sigterm, state);
ret = spawn_x_server (state, allow_remote_connections, state->cancellable);
if (!ret) {
g_printerr ("Unable to run X server\n");
exit_status = EX_SOFTWARE;
goto out;
}
ret = spawn_bus (state, state->cancellable);
if (!ret) {
g_printerr ("Unable to run session message bus\n");
exit_status = EX_SOFTWARE;
goto out;
}
import_environment (state, state->cancellable);
ret = update_bus_environment (state, state->cancellable);
if (!ret) {
g_printerr ("Unable to update bus environment\n");
exit_status = EX_SOFTWARE;
goto out;
}
+ ret = register_display (state, state->cancellable);
+
+ if (!ret) {
+ g_printerr ("Unable to register display with display manager\n");
+ exit_status = EX_SOFTWARE;
+ goto out;
+ }
+
ret = spawn_session (state, run_script, state->cancellable);
if (!ret) {
g_printerr ("Unable to run session\n");
exit_status = EX_SOFTWARE;
goto out;
}
- g_timeout_add_seconds (2, (GSourceFunc) on_registration_delay_complete, state);
-
g_main_loop_run (state->main_loop);
/* Only use exit status of session if we're here because it exit */
if (state->session_subprocess == NULL) {
exit_status = state->session_exit_status;
}
out:
if (state != NULL) {
signal_subprocesses (state);
wait_on_subprocesses (state);
clear_state (&state);
}
return exit_status;
}
--
2.27.0

View File

@ -0,0 +1,100 @@
From 59b3b809400dfac25410cf99dbc15cb5f66f85a3 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 25 Sep 2018 14:52:15 -0400
Subject: [PATCH 31/51] local-display-factory: don't autoreap initial-setup
We automatically kill the login screen when switching VTs away
from it, but we should never kill the initial-setup screen in
that situation.
This commit adds a check to prevent that from happening.
---
daemon/gdm-local-display-factory.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index be6b377be..13d56dcff 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -607,70 +607,78 @@ on_seat_removed (GDBusConnection *connection,
g_variant_get (parameters, "(&s&o)", &seat, NULL);
delete_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat);
}
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
static gboolean
lookup_by_session_id (const char *id,
GdmDisplay *display,
gpointer user_data)
{
const char *looking_for = user_data;
const char *current;
current = gdm_display_get_session_id (display);
return g_strcmp0 (current, looking_for) == 0;
}
static gboolean
wait_to_finish_timeout (GdmLocalDisplayFactory *factory)
{
finish_waiting_displays_on_seat (factory, "seat0");
factory->priv->wait_to_finish_timeout_id = 0;
return G_SOURCE_REMOVE;
}
static void
maybe_stop_greeter_in_background (GdmLocalDisplayFactory *factory,
GdmDisplay *display)
{
g_autofree char *display_session_type = NULL;
+ gboolean doing_initial_setup = FALSE;
if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED) {
g_debug ("GdmLocalDisplayFactory: login window not in managed state, so ignoring");
return;
}
g_object_get (G_OBJECT (display),
"session-type", &display_session_type,
+ "doing-initial-setup", &doing_initial_setup,
NULL);
+ /* we don't ever stop initial-setup implicitly */
+ if (doing_initial_setup) {
+ g_debug ("GdmLocalDisplayFactory: login window is performing initial-setup, so ignoring");
+ return;
+ }
+
/* we can only stop greeter for wayland sessions, since
* X server would jump back on exit */
if (g_strcmp0 (display_session_type, "wayland") != 0) {
g_debug ("GdmLocalDisplayFactory: login window is running on Xorg, so ignoring");
return;
}
g_debug ("GdmLocalDisplayFactory: killing login window once its unused");
g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL);
/* We stop the greeter after a timeout to avoid flicker */
if (factory->priv->wait_to_finish_timeout_id != 0)
g_source_remove (factory->priv->wait_to_finish_timeout_id);
factory->priv->wait_to_finish_timeout_id =
g_timeout_add_seconds (WAIT_TO_FINISH_TIMEOUT,
(GSourceFunc)wait_to_finish_timeout,
factory);
}
static gboolean
on_vt_changed (GIOChannel *source,
GIOCondition condition,
GdmLocalDisplayFactory *factory)
{
GIOStatus status;
static const char *tty_of_initial_vt = "tty" GDM_INITIAL_VT;
g_autofree char *tty_of_previous_vt = NULL;
g_autofree char *tty_of_active_vt = NULL;
g_autofree char *login_session_id = NULL;
--
2.27.0

View File

@ -0,0 +1,460 @@
From 566720ce07db8745c0ae6780ff289292dc0a9b60 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 25 Sep 2018 10:59:37 -0400
Subject: [PATCH 32/51] manager: rework how autologin is figured out
At the moment we decide whether or not to perform autologin, by
looking at if the display is the initial VT display and if autologin
hasn't been started before.
That isn't going to work in the future when autologin is started
on a non-initial vt.
This commit changes GDM to instead check if the seat is seat0, and
if autologin hasn't run before, before deciding to do autologin.
---
daemon/gdm-manager.c | 46 ++++++++++++++++++++++++++++++++------------
1 file changed, 34 insertions(+), 12 deletions(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index fb7b1ec4b..228cec6ff 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -51,75 +51,76 @@
#include "gdm-session.h"
#include "gdm-session-record.h"
#include "gdm-settings-direct.h"
#include "gdm-settings-keys.h"
#include "gdm-xdmcp-display-factory.h"
#include "gdm-xdmcp-chooser-display.h"
#define GDM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_MANAGER, GdmManagerPrivate))
#define GDM_DBUS_PATH "/org/gnome/DisplayManager"
#define GDM_MANAGER_PATH GDM_DBUS_PATH "/Manager"
#define GDM_MANAGER_DISPLAYS_PATH GDM_DBUS_PATH "/Displays"
#define INITIAL_SETUP_USERNAME "gnome-initial-setup"
typedef struct
{
GdmManager *manager;
GdmSession *session;
char *service_name;
guint idle_id;
} StartUserSessionOperation;
struct GdmManagerPrivate
{
GdmDisplayStore *display_store;
GdmLocalDisplayFactory *local_factory;
#ifdef HAVE_LIBXDMCP
GdmXdmcpDisplayFactory *xdmcp_factory;
#endif
+ GdmDisplay *automatic_login_display;
GList *user_sessions;
GHashTable *transient_sessions;
GHashTable *open_reauthentication_requests;
gboolean xdmcp_enabled;
gboolean started;
gboolean show_local_greeter;
GDBusConnection *connection;
GDBusObjectManagerServer *object_manager;
#ifdef WITH_PLYMOUTH
guint plymouth_is_running : 1;
#endif
- guint ran_once : 1;
+ guint did_automatic_login : 1;
};
enum {
PROP_0,
PROP_XDMCP_ENABLED,
PROP_SHOW_LOCAL_GREETER
};
enum {
DISPLAY_ADDED,
DISPLAY_REMOVED,
LAST_SIGNAL
};
typedef enum {
SESSION_RECORD_LOGIN,
SESSION_RECORD_LOGOUT,
SESSION_RECORD_FAILED,
} SessionRecord;
static guint signals [LAST_SIGNAL] = { 0, };
static void gdm_manager_class_init (GdmManagerClass *klass);
static void gdm_manager_init (GdmManager *manager);
static void gdm_manager_dispose (GObject *object);
static GdmSession *create_user_session_for_display (GdmManager *manager,
GdmDisplay *display,
uid_t allowed_user);
static void start_user_session (GdmManager *manager,
@@ -1415,67 +1416,74 @@ typedef struct {
static void
destroy_username_lookup_operation (UsernameLookupOperation *operation)
{
g_object_unref (operation->manager);
g_object_unref (operation->display);
g_free (operation->username);
g_free (operation);
}
static void
on_user_is_loaded_changed (ActUser *user,
GParamSpec *pspec,
UsernameLookupOperation *operation)
{
if (act_user_is_loaded (user)) {
set_up_automatic_login_session_if_user_exists (operation->manager, operation->display, user);
g_signal_handlers_disconnect_by_func (G_OBJECT (user),
G_CALLBACK (on_user_is_loaded_changed),
operation);
destroy_username_lookup_operation (operation);
}
}
static void
set_up_session (GdmManager *manager,
GdmDisplay *display)
{
ActUserManager *user_manager;
ActUser *user;
gboolean loaded;
- gboolean is_initial_display = FALSE;
+ gboolean seat_can_autologin = FALSE, seat_did_autologin = FALSE;
gboolean autologin_enabled = FALSE;
+ g_autofree char *seat_id = NULL;
char *username = NULL;
- g_object_get (G_OBJECT (display), "is-initial", &is_initial_display, NULL);
+ g_object_get (G_OBJECT (display), "seat-id", &seat_id, NULL);
+
+ if (g_strcmp0 (seat_id, "seat0") == 0)
+ seat_can_autologin = TRUE;
+
+ if (manager->priv->did_automatic_login || manager->priv->automatic_login_display != NULL)
+ seat_did_autologin = TRUE;
- if (!manager->priv->ran_once && is_initial_display)
+ if (seat_can_autologin && !seat_did_autologin)
autologin_enabled = get_automatic_login_details (manager, &username);
if (!autologin_enabled) {
g_free (username);
#ifdef HAVE_LIBXDMCP
if (GDM_IS_XDMCP_CHOOSER_DISPLAY (display)) {
set_up_chooser_session (manager, display);
return;
}
#endif
set_up_greeter_session (manager, display);
return;
}
/* Check whether the user really exists before committing to autologin. */
user_manager = act_user_manager_get_default ();
user = act_user_manager_get_user (user_manager, username);
g_object_get (user_manager, "is-loaded", &loaded, NULL);
if (loaded) {
set_up_automatic_login_session_if_user_exists (manager, display, user);
} else {
UsernameLookupOperation *operation;
operation = g_new (UsernameLookupOperation, 1);
operation->manager = g_object_ref (manager);
operation->display = g_object_ref (display);
operation->username = username;
@@ -1512,62 +1520,72 @@ on_display_status_changed (GdmDisplay *display,
"session-type", &session_type,
NULL);
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);
}
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
- if (!doing_initial_setup && (status == GDM_DISPLAY_FINISHED || g_strcmp0 (session_type, "x11") == 0)) {
- manager->priv->ran_once = TRUE;
+ if (display == manager->priv->automatic_login_display) {
+ g_clear_weak_pointer (&manager->priv->automatic_login_display);
+
+ manager->priv->did_automatic_login = TRUE;
+
+#ifdef ENABLE_WAYLAND_SUPPORT
+ if (g_strcmp0 (session_type, "wayland") != 0 && status == GDM_DISPLAY_FAILED) {
+ /* we're going to fall back to X11, so try to autologin again
+ */
+ manager->priv->did_automatic_login = FALSE;
+ }
+#endif
}
break;
default:
break;
}
}
static void
on_display_removed (GdmDisplayStore *display_store,
GdmDisplay *display,
GdmManager *manager)
{
char *id;
gdm_display_get_id (display, &id, NULL);
g_dbus_object_manager_server_unexport (manager->priv->object_manager, id);
g_free (id);
g_signal_handlers_disconnect_by_func (display, G_CALLBACK (on_display_status_changed), manager);
g_signal_emit (manager, signals[DISPLAY_REMOVED], 0, display);
}
static void
destroy_start_user_session_operation (StartUserSessionOperation *operation)
{
g_object_set_data (G_OBJECT (operation->session),
"start-user-session-operation",
NULL);
@@ -1621,132 +1639,134 @@ create_display_for_user_session (GdmManager *self,
const char *session_id)
{
GdmDisplay *display;
/* at the moment we only create GdmLocalDisplay objects on seat0 */
const char *seat_id = "seat0";
display = gdm_local_display_new ();
g_object_set (G_OBJECT (display),
"session-class", "user",
"seat-id", seat_id,
"session-id", session_id,
NULL);
gdm_display_store_add (self->priv->display_store,
display);
g_object_set_data (G_OBJECT (session), "gdm-display", display);
g_object_set_data_full (G_OBJECT (display),
"gdm-user-session",
g_object_ref (session),
(GDestroyNotify)
clean_user_session);
}
static gboolean
on_start_user_session (StartUserSessionOperation *operation)
{
GdmManager *self = operation->manager;
gboolean migrated;
gboolean fail_if_already_switched = TRUE;
gboolean doing_initial_setup = FALSE;
- gboolean starting_user_session_right_away = TRUE;
GdmDisplay *display;
const char *session_id;
g_debug ("GdmManager: start or jump to session");
/* If there's already a session running, jump to it.
* If the only session running is the one we just opened,
* start a session on it.
*/
migrated = switch_to_compatible_user_session (operation->manager, operation->session, fail_if_already_switched);
g_debug ("GdmManager: migrated: %d", migrated);
if (migrated) {
/* We don't stop the manager here because
when Xorg exits it switches to the VT it was
started from. That interferes with fast
user switching. */
gdm_session_reset (operation->session);
destroy_start_user_session_operation (operation);
goto out;
}
display = get_display_for_user_session (operation->session);
g_object_get (G_OBJECT (display), "doing-initial-setup", &doing_initial_setup, NULL);
session_id = gdm_session_get_conversation_session_id (operation->session,
operation->service_name);
if (gdm_session_get_display_mode (operation->session) == GDM_SESSION_DISPLAY_MODE_REUSE_VT) {
/* In this case, the greeter's display is morphing into
* the user session display. Kill the greeter on this session
* and let the user session follow the same display. */
gdm_display_stop_greeter_session (display);
g_object_set (G_OBJECT (display),
"session-class", "user",
"session-id", session_id,
NULL);
} else {
uid_t allowed_uid;
g_object_ref (display);
if (doing_initial_setup) {
g_debug ("GdmManager: closing down initial setup display");
gdm_display_stop_greeter_session (display);
gdm_display_unmanage (display);
gdm_display_finish (display);
} else {
g_debug ("GdmManager: session has its display server, reusing our server for another login screen");
}
/* The user session is going to follow the session worker
* into the new display. Untie it from this display and
* create a new session for a future user login. */
allowed_uid = gdm_session_get_allowed_user (operation->session);
g_object_set_data (G_OBJECT (display), "gdm-user-session", NULL);
g_object_set_data (G_OBJECT (operation->session), "gdm-display", NULL);
create_user_session_for_display (operation->manager, display, allowed_uid);
+ /* Give the user session a new display object for bookkeeping purposes */
+ create_display_for_user_session (operation->manager,
+ operation->session,
+ session_id);
+
if ((g_strcmp0 (operation->service_name, "gdm-autologin") == 0) &&
!gdm_session_client_is_connected (operation->session)) {
/* remove the unused prepared greeter display since we're not going
* to have a greeter */
gdm_display_store_remove (self->priv->display_store, display);
g_object_unref (display);
- }
- /* Give the user session a new display object for bookkeeping purposes */
- create_display_for_user_session (operation->manager,
- operation->session,
- session_id);
+ self->priv->automatic_login_display = g_object_get_data (G_OBJECT (operation->session), "gdm-display");
+ g_object_add_weak_pointer (G_OBJECT (display), (gpointer *) &self->priv->automatic_login_display);
+ }
}
start_user_session (operation->manager, operation);
out:
return G_SOURCE_REMOVE;
}
static void
queue_start_user_session (GdmManager *manager,
GdmSession *session,
const char *service_name)
{
StartUserSessionOperation *operation;
operation = g_slice_new0 (StartUserSessionOperation);
operation->manager = manager;
operation->session = g_object_ref (session);
operation->service_name = g_strdup (service_name);
operation->idle_id = g_idle_add ((GSourceFunc) on_start_user_session, operation);
g_object_set_data (G_OBJECT (session), "start-user-session-operation", operation);
}
static void
start_user_session_if_ready (GdmManager *manager,
GdmSession *session,
const char *service_name)
{
gboolean start_when_ready;
@@ -2601,60 +2621,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);
+ g_clear_weak_pointer (&manager->priv->automatic_login_display);
+
#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.27.0

View File

@ -0,0 +1,85 @@
From 05e49542a9de81731fce68614babe22d437e8fff Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 1 Oct 2018 11:05:57 -0400
Subject: [PATCH 33/51] manager: correct display confusion
commit c5c5bf1f reworked autologin and broke it.
This commit addresses the breakage by accessing
the proper display variable.
Closes https://gitlab.gnome.org/GNOME/gdm/issues/426
---
daemon/gdm-manager.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 228cec6ff..4c81dac7f 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1711,61 +1711,61 @@ on_start_user_session (StartUserSessionOperation *operation)
if (doing_initial_setup) {
g_debug ("GdmManager: closing down initial setup display");
gdm_display_stop_greeter_session (display);
gdm_display_unmanage (display);
gdm_display_finish (display);
} else {
g_debug ("GdmManager: session has its display server, reusing our server for another login screen");
}
/* The user session is going to follow the session worker
* into the new display. Untie it from this display and
* create a new session for a future user login. */
allowed_uid = gdm_session_get_allowed_user (operation->session);
g_object_set_data (G_OBJECT (display), "gdm-user-session", NULL);
g_object_set_data (G_OBJECT (operation->session), "gdm-display", NULL);
create_user_session_for_display (operation->manager, display, allowed_uid);
/* Give the user session a new display object for bookkeeping purposes */
create_display_for_user_session (operation->manager,
operation->session,
session_id);
if ((g_strcmp0 (operation->service_name, "gdm-autologin") == 0) &&
!gdm_session_client_is_connected (operation->session)) {
/* remove the unused prepared greeter display since we're not going
* to have a greeter */
gdm_display_store_remove (self->priv->display_store, display);
g_object_unref (display);
self->priv->automatic_login_display = g_object_get_data (G_OBJECT (operation->session), "gdm-display");
- g_object_add_weak_pointer (G_OBJECT (display), (gpointer *) &self->priv->automatic_login_display);
+ g_object_add_weak_pointer (G_OBJECT (self->priv->automatic_login_display), (gpointer *) &self->priv->automatic_login_display);
}
}
start_user_session (operation->manager, operation);
out:
return G_SOURCE_REMOVE;
}
static void
queue_start_user_session (GdmManager *manager,
GdmSession *session,
const char *service_name)
{
StartUserSessionOperation *operation;
operation = g_slice_new0 (StartUserSessionOperation);
operation->manager = manager;
operation->session = g_object_ref (session);
operation->service_name = g_strdup (service_name);
operation->idle_id = g_idle_add ((GSourceFunc) on_start_user_session, operation);
g_object_set_data (G_OBJECT (session), "start-user-session-operation", operation);
}
static void
start_user_session_if_ready (GdmManager *manager,
GdmSession *session,
const char *service_name)
{
--
2.27.0

View File

@ -0,0 +1,99 @@
From e4c9a998f89d429d31b02997f146c8218c0742bc Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 24 Sep 2018 14:45:38 -0400
Subject: [PATCH 34/51] manager: don't run autologin display on tty1
tty1 is really meant for the login screen.
If a user autologins on it and we need a login
screen later, then the login screen has to go
in some auxiliary VT which isn't very nice.
This commit changes autologin to not use the
initial vt.
---
daemon/gdm-manager.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 4c81dac7f..e896c8945 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1308,74 +1308,72 @@ get_automatic_login_details (GdmManager *manager,
} else {
g_free (username);
}
return enabled;
}
static const char *
get_username_for_greeter_display (GdmManager *manager,
GdmDisplay *display)
{
gboolean doing_initial_setup = FALSE;
g_object_get (G_OBJECT (display),
"doing-initial-setup", &doing_initial_setup,
NULL);
if (doing_initial_setup) {
return INITIAL_SETUP_USERNAME;
} else {
return GDM_USERNAME;
}
}
static void
set_up_automatic_login_session (GdmManager *manager,
GdmDisplay *display)
{
GdmSession *session;
char *display_session_type = NULL;
- gboolean is_initial;
/* 0 is root user; since the daemon talks to the session object
* directly, itself, for automatic login
*/
session = create_user_session_for_display (manager, display, 0);
g_object_get (G_OBJECT (display),
- "is-initial", &is_initial,
"session-type", &display_session_type,
NULL);
g_object_set (G_OBJECT (session),
- "display-is-initial", is_initial,
+ "display-is-initial", FALSE,
NULL);
g_debug ("GdmManager: Starting automatic login conversation");
gdm_session_start_conversation (session, "gdm-autologin");
}
static void
set_up_chooser_session (GdmManager *manager,
GdmDisplay *display)
{
const char *allowed_user;
struct passwd *passwd_entry;
allowed_user = get_username_for_greeter_display (manager, display);
if (!gdm_get_pwent_for_name (allowed_user, &passwd_entry)) {
g_warning ("GdmManager: couldn't look up username %s",
allowed_user);
gdm_display_unmanage (display);
gdm_display_finish (display);
return;
}
gdm_display_start_greeter_session (display);
}
static void
set_up_greeter_session (GdmManager *manager,
GdmDisplay *display)
{
--
2.27.0

View File

@ -0,0 +1,110 @@
From 2843a951ef826afd01fa3c7340780b1929db38c7 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Tue, 4 Sep 2018 08:12:34 +0200
Subject: [PATCH 35/51] local-display-factory: Remove initial VT is in use
check
The initial VT is in use check in on_vt_changed() is racy, when switching
to VT1 from an active session, on_vt_changed() may run before logind has
processed the VT change and then sd_seat_get_active() will return the
active session which we are switching away from. This results in the greeter
not being started on VT1.
On my system gdm reliably wins the race resulting in not getting a greeter
when manually switching from an active session to VT1.
gdm already starts the greeter unconditionally from
gdm_local_display_factory_sync_seats() on both startup and when an user
session exits. gdm also starts it unconditionally when selecting
"Switch user" from an user session.
Now autologin sessions avoid the initial VT as well.
So we now can assume that the initial VT is free for the login screen's
use. And create_display already checks for and re-uses
an existing greeter, so we can safely remove the racy check.
---
daemon/gdm-local-display-factory.c | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 13d56dcff..8e46dbca2 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -752,73 +752,60 @@ on_vt_changed (GIOChannel *source,
g_debug ("GdmLocalDisplayFactory: tty of login window is %s", tty_of_login_window_vt);
if (g_strcmp0 (tty_of_login_window_vt, tty_of_previous_vt) == 0) {
GdmDisplayStore *store;
GdmDisplay *display;
g_debug ("GdmLocalDisplayFactory: VT switched from login window");
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
display = gdm_display_store_find (store,
lookup_by_session_id,
(gpointer) login_session_id);
if (display != NULL)
maybe_stop_greeter_in_background (factory, display);
} else {
g_debug ("GdmLocalDisplayFactory: VT not switched from login window");
}
}
}
/* if user jumped back to initial vt and it's empty put a login screen
* on it (unless a login screen is already running elsewhere, then
* jump to that login screen)
*/
if (strcmp (factory->priv->tty_of_active_vt, tty_of_initial_vt) != 0) {
g_debug ("GdmLocalDisplayFactory: active VT is not initial VT, so ignoring");
return G_SOURCE_CONTINUE;
}
- ret = sd_seat_get_active ("seat0", &active_session_id, NULL);
-
- if (ret == 0) {
- g_autofree char *state = NULL;
- ret = sd_session_get_state (active_session_id, &state);
-
- /* if there's something already running on the active VT then bail */
- if (ret == 0 && g_strcmp0 (state, "closing") != 0) {
- g_debug ("GdmLocalDisplayFactory: initial VT is in use, so ignoring");
- return G_SOURCE_CONTINUE;
- }
- }
-
if (gdm_local_display_factory_use_wayland ())
session_type = "wayland";
g_debug ("GdmLocalDisplayFactory: creating new display on seat0 because of VT change");
create_display (factory, "seat0", session_type, TRUE);
return G_SOURCE_CONTINUE;
}
#endif
static void
gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory)
{
g_autoptr (GIOChannel) io_channel = NULL;
factory->priv->seat_new_id = g_dbus_connection_signal_subscribe (factory->priv->connection,
"org.freedesktop.login1",
"org.freedesktop.login1.Manager",
"SeatNew",
"/org/freedesktop/login1",
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
on_seat_new,
g_object_ref (factory),
g_object_unref);
factory->priv->seat_removed_id = g_dbus_connection_signal_subscribe (factory->priv->connection,
"org.freedesktop.login1",
"org.freedesktop.login1.Manager",
"SeatRemoved",
--
2.27.0

View File

@ -0,0 +1,140 @@
From f5acee2766c05403235c06da6b1bb68af744da79 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 25 Sep 2018 14:30:16 -0400
Subject: [PATCH 36/51] local-display-factory: Remove same VT so don't switch
check
We avoid changing to the login screen vt if we're already on it,
but the call is racy since we react to vt changes concurrently
with logind (who we query for the active vt).
This check drops the active vt check since it's pointless and
getting in the way.
---
daemon/gdm-local-display-factory.c | 39 ++++++++++--------------------
1 file changed, 13 insertions(+), 26 deletions(-)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 8e46dbca2..be7b43cff 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -410,103 +410,90 @@ lookup_by_seat_id (const char *id,
res = g_strcmp0 (current, looking_for) == 0;
g_free(current);
return res;
}
static gboolean
lookup_prepared_display_by_seat_id (const char *id,
GdmDisplay *display,
gpointer user_data)
{
int status;
status = gdm_display_get_status (display);
if (status != GDM_DISPLAY_PREPARED)
return FALSE;
return lookup_by_seat_id (id, display, user_data);
}
static GdmDisplay *
create_display (GdmLocalDisplayFactory *factory,
const char *seat_id,
const char *session_type,
gboolean initial)
{
GdmDisplayStore *store;
GdmDisplay *display = NULL;
- char *active_session_id = NULL;
- int ret;
+ g_autofree char *login_session_id = NULL;
g_debug ("GdmLocalDisplayFactory: %s login display for seat %s requested",
session_type? : "X11", seat_id);
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
if (sd_seat_can_multi_session (seat_id))
display = gdm_display_store_find (store, lookup_prepared_display_by_seat_id, (gpointer) seat_id);
else
display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id);
/* Ensure we don't create the same display more than once */
if (display != NULL) {
g_debug ("GdmLocalDisplayFactory: display already created");
return NULL;
}
- ret = sd_seat_get_active (seat_id, &active_session_id, NULL);
-
- if (ret == 0) {
- char *login_session_id = NULL;
-
- /* If we already have a login window, switch to it */
- if (gdm_get_login_window_session_id (seat_id, &login_session_id)) {
- GdmDisplay *display;
-
- display = gdm_display_store_find (store,
- lookup_by_session_id,
- (gpointer) login_session_id);
- if (display != NULL && gdm_display_get_status (display) == GDM_DISPLAY_MANAGED) {
- if (g_strcmp0 (active_session_id, login_session_id) != 0) {
- g_debug ("GdmLocalDisplayFactory: session %s found, activating.",
- login_session_id);
- gdm_activate_session_by_id (factory->priv->connection, seat_id, login_session_id);
- }
- g_clear_pointer (&login_session_id, g_free);
- g_clear_pointer (&active_session_id, g_free);
- return NULL;
- }
- g_clear_pointer (&login_session_id, g_free);
+ /* If we already have a login window, switch to it */
+ if (gdm_get_login_window_session_id (seat_id, &login_session_id)) {
+ GdmDisplay *display;
+
+ display = gdm_display_store_find (store,
+ lookup_by_session_id,
+ (gpointer) login_session_id);
+ if (display != NULL && gdm_display_get_status (display) == GDM_DISPLAY_MANAGED) {
+ g_debug ("GdmLocalDisplayFactory: session %s found, activating.",
+ login_session_id);
+ gdm_activate_session_by_id (factory->priv->connection, seat_id, login_session_id);
+ return NULL;
}
- g_clear_pointer (&active_session_id, g_free);
}
g_debug ("GdmLocalDisplayFactory: Adding display on seat %s", seat_id);
#ifdef ENABLE_USER_DISPLAY_SERVER
if (g_strcmp0 (seat_id, "seat0") == 0) {
display = gdm_local_display_new ();
if (session_type != NULL) {
g_object_set (G_OBJECT (display), "session-type", session_type, NULL);
}
}
#endif
if (display == NULL) {
guint32 num;
num = take_next_display_number (factory);
display = gdm_legacy_display_new (num);
}
g_object_set (display, "seat-id", seat_id, NULL);
g_object_set (display, "is-initial", initial, NULL);
store_display (factory, display);
/* let store own the ref */
g_object_unref (display);
if (! gdm_display_manage (display)) {
--
2.27.0

View File

@ -0,0 +1,88 @@
From 59a4538e335362a92186217be03529f3694697e1 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Tue, 25 Sep 2018 14:39:42 -0400
Subject: [PATCH 37/51] local-display-factory: handle reviving displays that
are waiting to die
We may end up re-using a display in waiting-to-finish state before it gets
finished in this case reset its state to managed to avoid it getting
finished while it is being used.
Closes https://gitlab.gnome.org/GNOME/gdm/merge_requests/45
---
daemon/gdm-local-display-factory.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index be7b43cff..d999596b5 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -434,61 +434,64 @@ create_display (GdmLocalDisplayFactory *factory,
const char *seat_id,
const char *session_type,
gboolean initial)
{
GdmDisplayStore *store;
GdmDisplay *display = NULL;
g_autofree char *login_session_id = NULL;
g_debug ("GdmLocalDisplayFactory: %s login display for seat %s requested",
session_type? : "X11", seat_id);
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
if (sd_seat_can_multi_session (seat_id))
display = gdm_display_store_find (store, lookup_prepared_display_by_seat_id, (gpointer) seat_id);
else
display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id);
/* Ensure we don't create the same display more than once */
if (display != NULL) {
g_debug ("GdmLocalDisplayFactory: display already created");
return NULL;
}
/* If we already have a login window, switch to it */
if (gdm_get_login_window_session_id (seat_id, &login_session_id)) {
GdmDisplay *display;
display = gdm_display_store_find (store,
lookup_by_session_id,
(gpointer) login_session_id);
- if (display != NULL && gdm_display_get_status (display) == GDM_DISPLAY_MANAGED) {
+ if (display != NULL &&
+ (gdm_display_get_status (display) == GDM_DISPLAY_MANAGED ||
+ gdm_display_get_status (display) == GDM_DISPLAY_WAITING_TO_FINISH)) {
+ g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_MANAGED, NULL);
g_debug ("GdmLocalDisplayFactory: session %s found, activating.",
login_session_id);
gdm_activate_session_by_id (factory->priv->connection, seat_id, login_session_id);
return NULL;
}
}
g_debug ("GdmLocalDisplayFactory: Adding display on seat %s", seat_id);
#ifdef ENABLE_USER_DISPLAY_SERVER
if (g_strcmp0 (seat_id, "seat0") == 0) {
display = gdm_local_display_new ();
if (session_type != NULL) {
g_object_set (G_OBJECT (display), "session-type", session_type, NULL);
}
}
#endif
if (display == NULL) {
guint32 num;
num = take_next_display_number (factory);
display = gdm_legacy_display_new (num);
}
g_object_set (display, "seat-id", seat_id, NULL);
g_object_set (display, "is-initial", initial, NULL);
store_display (factory, display);
--
2.27.0

View File

@ -0,0 +1,151 @@
From c65a0dbd195be52f0db0c49ea0355fe1b5eb4c09 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 31 Aug 2018 15:48:38 -0400
Subject: [PATCH 38/51] manager: don't kill initial-setup before starting user
session on wayland
Right now we kill initial-setup before starting the session for the user
initial-setup created. This is the right thing to do for Xorg, since
Xorg can't be killed in the background, but it adds unncessary flicker
for wayland.
This commit checks if it's wayland and avoids killing it right away
in that case.
---
daemon/gdm-manager.c | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index e896c8945..0823e8638 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1639,105 +1639,121 @@ create_display_for_user_session (GdmManager *self,
GdmDisplay *display;
/* at the moment we only create GdmLocalDisplay objects on seat0 */
const char *seat_id = "seat0";
display = gdm_local_display_new ();
g_object_set (G_OBJECT (display),
"session-class", "user",
"seat-id", seat_id,
"session-id", session_id,
NULL);
gdm_display_store_add (self->priv->display_store,
display);
g_object_set_data (G_OBJECT (session), "gdm-display", display);
g_object_set_data_full (G_OBJECT (display),
"gdm-user-session",
g_object_ref (session),
(GDestroyNotify)
clean_user_session);
}
static gboolean
on_start_user_session (StartUserSessionOperation *operation)
{
GdmManager *self = operation->manager;
gboolean migrated;
gboolean fail_if_already_switched = TRUE;
gboolean doing_initial_setup = FALSE;
GdmDisplay *display;
const char *session_id;
+#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
+ g_autofree char *display_session_type = NULL;
+#endif
g_debug ("GdmManager: start or jump to session");
/* If there's already a session running, jump to it.
* If the only session running is the one we just opened,
* start a session on it.
*/
migrated = switch_to_compatible_user_session (operation->manager, operation->session, fail_if_already_switched);
g_debug ("GdmManager: migrated: %d", migrated);
if (migrated) {
/* We don't stop the manager here because
when Xorg exits it switches to the VT it was
started from. That interferes with fast
user switching. */
gdm_session_reset (operation->session);
destroy_start_user_session_operation (operation);
goto out;
}
display = get_display_for_user_session (operation->session);
- g_object_get (G_OBJECT (display), "doing-initial-setup", &doing_initial_setup, NULL);
+ g_object_get (G_OBJECT (display),
+ "doing-initial-setup", &doing_initial_setup,
+#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
+ "session-type", &display_session_type,
+#endif
+ NULL);
session_id = gdm_session_get_conversation_session_id (operation->session,
operation->service_name);
if (gdm_session_get_display_mode (operation->session) == GDM_SESSION_DISPLAY_MODE_REUSE_VT) {
/* In this case, the greeter's display is morphing into
* the user session display. Kill the greeter on this session
* and let the user session follow the same display. */
gdm_display_stop_greeter_session (display);
g_object_set (G_OBJECT (display),
"session-class", "user",
"session-id", session_id,
NULL);
} else {
uid_t allowed_uid;
g_object_ref (display);
if (doing_initial_setup) {
- g_debug ("GdmManager: closing down initial setup display");
- gdm_display_stop_greeter_session (display);
- gdm_display_unmanage (display);
- gdm_display_finish (display);
+#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
+ if (g_strcmp0 (display_session_type, "wayland") == 0) {
+ g_debug ("GdmManager: closing down initial setup display in background");
+ g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL);
+ }
+#endif
+ if (gdm_display_get_status (display) == GDM_DISPLAY_MANAGED) {
+ g_debug ("GdmManager: closing down initial setup display");
+ gdm_display_stop_greeter_session (display);
+ gdm_display_unmanage (display);
+ gdm_display_finish (display);
+ }
} else {
g_debug ("GdmManager: session has its display server, reusing our server for another login screen");
}
/* The user session is going to follow the session worker
* into the new display. Untie it from this display and
* create a new session for a future user login. */
allowed_uid = gdm_session_get_allowed_user (operation->session);
g_object_set_data (G_OBJECT (display), "gdm-user-session", NULL);
g_object_set_data (G_OBJECT (operation->session), "gdm-display", NULL);
create_user_session_for_display (operation->manager, display, allowed_uid);
/* Give the user session a new display object for bookkeeping purposes */
create_display_for_user_session (operation->manager,
operation->session,
session_id);
if ((g_strcmp0 (operation->service_name, "gdm-autologin") == 0) &&
!gdm_session_client_is_connected (operation->session)) {
/* remove the unused prepared greeter display since we're not going
* to have a greeter */
gdm_display_store_remove (self->priv->display_store, display);
g_object_unref (display);
self->priv->automatic_login_display = g_object_get_data (G_OBJECT (operation->session), "gdm-display");
g_object_add_weak_pointer (G_OBJECT (self->priv->automatic_login_display), (gpointer *) &self->priv->automatic_login_display);
}
}
start_user_session (operation->manager, operation);
--
2.27.0

View File

@ -0,0 +1,694 @@
From c08afca0807d8820030c19a40e7590f72878c788 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 6 Sep 2018 19:31:50 -0400
Subject: [PATCH 39/51] manager: do initial-setup post work in manager code
Right now we do the initial-setup related post work
when stopping the greeter, but the problem is we delay
stopping the greeter now until after the user session
is started.
That post-work needs to be done before the user session
is started.
This commit moves the code to a more logical place.
---
daemon/gdm-display.c | 132 -------------------------------------------
daemon/gdm-manager.c | 132 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 132 insertions(+), 132 deletions(-)
diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c
index 875534272..1cef8c7c1 100644
--- a/daemon/gdm-display.c
+++ b/daemon/gdm-display.c
@@ -22,61 +22,60 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include <xcb/xcb.h>
#include <X11/Xlib.h>
#include "gdm-common.h"
#include "gdm-display.h"
#include "gdm-display-glue.h"
#include "gdm-display-access-file.h"
#include "gdm-launch-environment.h"
#include "gdm-settings-direct.h"
#include "gdm-settings-keys.h"
#include "gdm-launch-environment.h"
#include "gdm-dbus-util.h"
-#define INITIAL_SETUP_USERNAME "gnome-initial-setup"
#define GNOME_SESSION_SESSIONS_PATH DATADIR "/gnome-session/sessions"
#define GDM_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DISPLAY, GdmDisplayPrivate))
struct GdmDisplayPrivate
{
char *id;
char *seat_id;
char *session_id;
char *session_class;
char *session_type;
char *remote_hostname;
int x11_display_number;
char *x11_display_name;
int status;
time_t creation_time;
GTimer *server_timer;
char *x11_cookie;
gsize x11_cookie_size;
GdmDisplayAccessFile *access_file;
guint finish_idle_id;
xcb_connection_t *xcb_connection;
int xcb_screen_number;
GDBusConnection *connection;
GdmDisplayAccessFile *user_access_file;
@@ -98,131 +97,60 @@ enum {
PROP_0,
PROP_ID,
PROP_STATUS,
PROP_SEAT_ID,
PROP_SESSION_ID,
PROP_SESSION_CLASS,
PROP_SESSION_TYPE,
PROP_REMOTE_HOSTNAME,
PROP_X11_DISPLAY_NUMBER,
PROP_X11_DISPLAY_NAME,
PROP_X11_COOKIE,
PROP_X11_AUTHORITY_FILE,
PROP_IS_CONNECTED,
PROP_IS_LOCAL,
PROP_LAUNCH_ENVIRONMENT,
PROP_IS_INITIAL,
PROP_ALLOW_TIMED_LOGIN,
PROP_HAVE_EXISTING_USER_ACCOUNTS,
PROP_DOING_INITIAL_SETUP,
};
static void gdm_display_class_init (GdmDisplayClass *klass);
static void gdm_display_init (GdmDisplay *self);
static void gdm_display_finalize (GObject *object);
static void queue_finish (GdmDisplay *self);
static void _gdm_display_set_status (GdmDisplay *self,
int status);
static gboolean wants_initial_setup (GdmDisplay *self);
G_DEFINE_ABSTRACT_TYPE (GdmDisplay, gdm_display, G_TYPE_OBJECT)
-static gboolean
-chown_file (GFile *file,
- uid_t uid,
- gid_t gid,
- GError **error)
-{
- if (!g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_UID, uid,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- NULL, error)) {
- return FALSE;
- }
- if (!g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_GID, gid,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- NULL, error)) {
- return FALSE;
- }
- return TRUE;
-}
-
-static gboolean
-chown_recursively (GFile *dir,
- uid_t uid,
- gid_t gid,
- GError **error)
-{
- GFile *file = NULL;
- GFileInfo *info = NULL;
- GFileEnumerator *enumerator = NULL;
- gboolean retval = FALSE;
-
- if (chown_file (dir, uid, gid, error) == FALSE) {
- goto out;
- }
-
- enumerator = g_file_enumerate_children (dir,
- G_FILE_ATTRIBUTE_STANDARD_TYPE","
- G_FILE_ATTRIBUTE_STANDARD_NAME,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- NULL, error);
- if (!enumerator) {
- goto out;
- }
-
- while ((info = g_file_enumerator_next_file (enumerator, NULL, error)) != NULL) {
- file = g_file_get_child (dir, g_file_info_get_name (info));
-
- if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
- if (chown_recursively (file, uid, gid, error) == FALSE) {
- goto out;
- }
- } else if (chown_file (file, uid, gid, error) == FALSE) {
- goto out;
- }
-
- g_clear_object (&file);
- g_clear_object (&info);
- }
-
- if (*error) {
- goto out;
- }
-
- retval = TRUE;
-out:
- g_clear_object (&file);
- g_clear_object (&info);
- g_clear_object (&enumerator);
-
- return retval;
-}
-
GQuark
gdm_display_error_quark (void)
{
static GQuark ret = 0;
if (ret == 0) {
ret = g_quark_from_static_string ("gdm_display_error");
}
return ret;
}
time_t
gdm_display_get_creation_time (GdmDisplay *self)
{
g_return_val_if_fail (GDM_IS_DISPLAY (self), 0);
return self->priv->creation_time;
}
int
gdm_display_get_status (GdmDisplay *self)
{
g_return_val_if_fail (GDM_IS_DISPLAY (self), 0);
return self->priv->status;
}
const char *
gdm_display_get_session_id (GdmDisplay *self)
{
@@ -1649,145 +1577,85 @@ gdm_display_start_greeter_session (GdmDisplay *self)
G_CALLBACK (on_launch_environment_session_stopped),
self, 0);
g_signal_connect_object (self->priv->launch_environment,
"exited",
G_CALLBACK (on_launch_environment_session_exited),
self, 0);
g_signal_connect_object (self->priv->launch_environment,
"died",
G_CALLBACK (on_launch_environment_session_died),
self, 0);
if (auth_file != NULL) {
g_object_set (self->priv->launch_environment,
"x11-authority-file", auth_file,
NULL);
}
gdm_launch_environment_start (self->priv->launch_environment);
session = gdm_launch_environment_get_session (self->priv->launch_environment);
g_object_set (G_OBJECT (session),
"display-is-initial", self->priv->is_initial,
NULL);
g_free (display_name);
g_free (seat_id);
g_free (hostname);
g_free (auth_file);
}
-static void
-chown_initial_setup_home_dir (void)
-{
- GFile *dir;
- GError *error;
- char *gis_dir_path;
- char *gis_uid_path;
- char *gis_uid_contents;
- struct passwd *pwe;
- uid_t uid;
-
- if (!gdm_get_pwent_for_name (INITIAL_SETUP_USERNAME, &pwe)) {
- g_warning ("Unknown user %s", INITIAL_SETUP_USERNAME);
- return;
- }
-
- gis_dir_path = g_strdup (pwe->pw_dir);
-
- gis_uid_path = g_build_filename (gis_dir_path,
- "gnome-initial-setup-uid",
- NULL);
- if (!g_file_get_contents (gis_uid_path, &gis_uid_contents, NULL, NULL)) {
- g_warning ("Unable to read %s", gis_uid_path);
- goto out;
- }
-
- uid = (uid_t) atoi (gis_uid_contents);
- pwe = getpwuid (uid);
- if (uid == 0 || pwe == NULL) {
- g_warning ("UID '%s' in %s is not valid", gis_uid_contents, gis_uid_path);
- goto out;
- }
-
- error = NULL;
- dir = g_file_new_for_path (gis_dir_path);
- if (!chown_recursively (dir, pwe->pw_uid, pwe->pw_gid, &error)) {
- g_warning ("Failed to change ownership for %s: %s", gis_dir_path, error->message);
- g_error_free (error);
- }
- g_object_unref (dir);
-out:
- g_free (gis_uid_contents);
- g_free (gis_uid_path);
- g_free (gis_dir_path);
-}
-
void
gdm_display_stop_greeter_session (GdmDisplay *self)
{
GError *error = NULL;
if (self->priv->launch_environment != NULL) {
g_signal_handlers_disconnect_by_func (self->priv->launch_environment,
G_CALLBACK (on_launch_environment_session_opened),
self);
g_signal_handlers_disconnect_by_func (self->priv->launch_environment,
G_CALLBACK (on_launch_environment_session_started),
self);
g_signal_handlers_disconnect_by_func (self->priv->launch_environment,
G_CALLBACK (on_launch_environment_session_stopped),
self);
g_signal_handlers_disconnect_by_func (self->priv->launch_environment,
G_CALLBACK (on_launch_environment_session_exited),
self);
g_signal_handlers_disconnect_by_func (self->priv->launch_environment,
G_CALLBACK (on_launch_environment_session_died),
self);
gdm_launch_environment_stop (self->priv->launch_environment);
g_clear_object (&self->priv->launch_environment);
}
-
- if (self->priv->doing_initial_setup) {
- chown_initial_setup_home_dir ();
-
- if (!g_file_set_contents (ALREADY_RAN_INITIAL_SETUP_ON_THIS_BOOT,
- "1",
- 1,
- &error)) {
- g_warning ("GdmDisplay: Could not write initial-setup-done marker to %s: %s",
- ALREADY_RAN_INITIAL_SETUP_ON_THIS_BOOT,
- error->message);
- g_clear_error (&error);
- }
- }
}
static xcb_window_t
get_root_window (xcb_connection_t *connection,
int screen_number)
{
xcb_screen_t *screen = NULL;
xcb_screen_iterator_t iter;
iter = xcb_setup_roots_iterator (xcb_get_setup (connection));
while (iter.rem) {
if (screen_number == 0)
screen = iter.data;
screen_number--;
xcb_screen_next (&iter);
}
if (screen != NULL) {
return screen->root;
}
return XCB_WINDOW_NONE;
}
static void
gdm_display_set_windowpath (GdmDisplay *self)
{
/* setting WINDOWPATH for clients */
xcb_intern_atom_cookie_t atom_cookie;
xcb_intern_atom_reply_t *atom_reply = NULL;
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 0823e8638..cf982870c 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -35,60 +35,61 @@
#include <glib-object.h>
#include <act/act-user-manager.h>
#include <systemd/sd-login.h>
#include "gdm-common.h"
#include "gdm-dbus-util.h"
#include "gdm-manager.h"
#include "gdm-manager-glue.h"
#include "gdm-display-store.h"
#include "gdm-display-factory.h"
#include "gdm-launch-environment.h"
#include "gdm-local-display.h"
#include "gdm-local-display-factory.h"
#include "gdm-session.h"
#include "gdm-session-record.h"
#include "gdm-settings-direct.h"
#include "gdm-settings-keys.h"
#include "gdm-xdmcp-display-factory.h"
#include "gdm-xdmcp-chooser-display.h"
#define GDM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_MANAGER, GdmManagerPrivate))
#define GDM_DBUS_PATH "/org/gnome/DisplayManager"
#define GDM_MANAGER_PATH GDM_DBUS_PATH "/Manager"
#define GDM_MANAGER_DISPLAYS_PATH GDM_DBUS_PATH "/Displays"
#define INITIAL_SETUP_USERNAME "gnome-initial-setup"
+#define ALREADY_RAN_INITIAL_SETUP_ON_THIS_BOOT GDM_RUN_DIR "/gdm.ran-initial-setup"
typedef struct
{
GdmManager *manager;
GdmSession *session;
char *service_name;
guint idle_id;
} StartUserSessionOperation;
struct GdmManagerPrivate
{
GdmDisplayStore *display_store;
GdmLocalDisplayFactory *local_factory;
#ifdef HAVE_LIBXDMCP
GdmXdmcpDisplayFactory *xdmcp_factory;
#endif
GdmDisplay *automatic_login_display;
GList *user_sessions;
GHashTable *transient_sessions;
GHashTable *open_reauthentication_requests;
gboolean xdmcp_enabled;
gboolean started;
gboolean show_local_greeter;
GDBusConnection *connection;
GDBusObjectManagerServer *object_manager;
#ifdef WITH_PLYMOUTH
guint plymouth_is_running : 1;
@@ -1630,130 +1631,261 @@ start_user_session (GdmManager *manager,
destroy_start_user_session_operation (operation);
}
static void
create_display_for_user_session (GdmManager *self,
GdmSession *session,
const char *session_id)
{
GdmDisplay *display;
/* at the moment we only create GdmLocalDisplay objects on seat0 */
const char *seat_id = "seat0";
display = gdm_local_display_new ();
g_object_set (G_OBJECT (display),
"session-class", "user",
"seat-id", seat_id,
"session-id", session_id,
NULL);
gdm_display_store_add (self->priv->display_store,
display);
g_object_set_data (G_OBJECT (session), "gdm-display", display);
g_object_set_data_full (G_OBJECT (display),
"gdm-user-session",
g_object_ref (session),
(GDestroyNotify)
clean_user_session);
}
+static gboolean
+chown_file (GFile *file,
+ uid_t uid,
+ gid_t gid,
+ GError **error)
+{
+ if (!g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_UID, uid,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL, error)) {
+ return FALSE;
+ }
+ if (!g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_GID, gid,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL, error)) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+chown_recursively (GFile *dir,
+ uid_t uid,
+ gid_t gid,
+ GError **error)
+{
+ GFile *file = NULL;
+ GFileInfo *info = NULL;
+ GFileEnumerator *enumerator = NULL;
+ gboolean retval = FALSE;
+
+ if (chown_file (dir, uid, gid, error) == FALSE) {
+ goto out;
+ }
+
+ enumerator = g_file_enumerate_children (dir,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE","
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL, error);
+ if (!enumerator) {
+ goto out;
+ }
+
+ while ((info = g_file_enumerator_next_file (enumerator, NULL, error)) != NULL) {
+ file = g_file_get_child (dir, g_file_info_get_name (info));
+
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+ if (chown_recursively (file, uid, gid, error) == FALSE) {
+ goto out;
+ }
+ } else if (chown_file (file, uid, gid, error) == FALSE) {
+ goto out;
+ }
+
+ g_clear_object (&file);
+ g_clear_object (&info);
+ }
+
+ if (*error) {
+ goto out;
+ }
+
+ retval = TRUE;
+out:
+ g_clear_object (&file);
+ g_clear_object (&info);
+ g_clear_object (&enumerator);
+
+ return retval;
+}
+
+static void
+chown_initial_setup_home_dir (void)
+{
+ GFile *dir;
+ GError *error;
+ char *gis_dir_path;
+ char *gis_uid_path;
+ char *gis_uid_contents;
+ struct passwd *pwe;
+ uid_t uid;
+
+ if (!gdm_get_pwent_for_name (INITIAL_SETUP_USERNAME, &pwe)) {
+ g_warning ("Unknown user %s", INITIAL_SETUP_USERNAME);
+ return;
+ }
+
+ gis_dir_path = g_strdup (pwe->pw_dir);
+
+ gis_uid_path = g_build_filename (gis_dir_path,
+ "gnome-initial-setup-uid",
+ NULL);
+ if (!g_file_get_contents (gis_uid_path, &gis_uid_contents, NULL, NULL)) {
+ g_warning ("Unable to read %s", gis_uid_path);
+ goto out;
+ }
+
+ uid = (uid_t) atoi (gis_uid_contents);
+ pwe = getpwuid (uid);
+ if (uid == 0 || pwe == NULL) {
+ g_warning ("UID '%s' in %s is not valid", gis_uid_contents, gis_uid_path);
+ goto out;
+ }
+
+ error = NULL;
+ dir = g_file_new_for_path (gis_dir_path);
+ if (!chown_recursively (dir, pwe->pw_uid, pwe->pw_gid, &error)) {
+ g_warning ("Failed to change ownership for %s: %s", gis_dir_path, error->message);
+ g_error_free (error);
+ }
+ g_object_unref (dir);
+out:
+ g_free (gis_uid_contents);
+ g_free (gis_uid_path);
+ g_free (gis_dir_path);
+}
+
static gboolean
on_start_user_session (StartUserSessionOperation *operation)
{
GdmManager *self = operation->manager;
gboolean migrated;
gboolean fail_if_already_switched = TRUE;
gboolean doing_initial_setup = FALSE;
GdmDisplay *display;
const char *session_id;
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
g_autofree char *display_session_type = NULL;
#endif
g_debug ("GdmManager: start or jump to session");
/* If there's already a session running, jump to it.
* If the only session running is the one we just opened,
* start a session on it.
*/
migrated = switch_to_compatible_user_session (operation->manager, operation->session, fail_if_already_switched);
g_debug ("GdmManager: migrated: %d", migrated);
if (migrated) {
/* We don't stop the manager here because
when Xorg exits it switches to the VT it was
started from. That interferes with fast
user switching. */
gdm_session_reset (operation->session);
destroy_start_user_session_operation (operation);
goto out;
}
display = get_display_for_user_session (operation->session);
g_object_get (G_OBJECT (display),
"doing-initial-setup", &doing_initial_setup,
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
"session-type", &display_session_type,
#endif
NULL);
session_id = gdm_session_get_conversation_session_id (operation->session,
operation->service_name);
if (gdm_session_get_display_mode (operation->session) == GDM_SESSION_DISPLAY_MODE_REUSE_VT) {
/* In this case, the greeter's display is morphing into
* the user session display. Kill the greeter on this session
* and let the user session follow the same display. */
gdm_display_stop_greeter_session (display);
g_object_set (G_OBJECT (display),
"session-class", "user",
"session-id", session_id,
NULL);
} else {
uid_t allowed_uid;
g_object_ref (display);
if (doing_initial_setup) {
+ g_autoptr(GError) error = NULL;
+
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
if (g_strcmp0 (display_session_type, "wayland") == 0) {
g_debug ("GdmManager: closing down initial setup display in background");
g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL);
}
#endif
if (gdm_display_get_status (display) == GDM_DISPLAY_MANAGED) {
g_debug ("GdmManager: closing down initial setup display");
gdm_display_stop_greeter_session (display);
gdm_display_unmanage (display);
gdm_display_finish (display);
}
+
+ chown_initial_setup_home_dir ();
+
+ if (!g_file_set_contents (ALREADY_RAN_INITIAL_SETUP_ON_THIS_BOOT,
+ "1",
+ 1,
+ &error)) {
+ g_warning ("GdmDisplay: Could not write initial-setup-done marker to %s: %s",
+ ALREADY_RAN_INITIAL_SETUP_ON_THIS_BOOT,
+ error->message);
+ g_clear_error (&error);
+ }
} else {
g_debug ("GdmManager: session has its display server, reusing our server for another login screen");
}
/* The user session is going to follow the session worker
* into the new display. Untie it from this display and
* create a new session for a future user login. */
allowed_uid = gdm_session_get_allowed_user (operation->session);
g_object_set_data (G_OBJECT (display), "gdm-user-session", NULL);
g_object_set_data (G_OBJECT (operation->session), "gdm-display", NULL);
create_user_session_for_display (operation->manager, display, allowed_uid);
/* Give the user session a new display object for bookkeeping purposes */
create_display_for_user_session (operation->manager,
operation->session,
session_id);
if ((g_strcmp0 (operation->service_name, "gdm-autologin") == 0) &&
!gdm_session_client_is_connected (operation->session)) {
/* remove the unused prepared greeter display since we're not going
* to have a greeter */
gdm_display_store_remove (self->priv->display_store, display);
g_object_unref (display);
self->priv->automatic_login_display = g_object_get_data (G_OBJECT (operation->session), "gdm-display");
g_object_add_weak_pointer (G_OBJECT (self->priv->automatic_login_display), (gpointer *) &self->priv->automatic_login_display);
}
}
start_user_session (operation->manager, operation);
--
2.27.0

View File

@ -0,0 +1,117 @@
From 49383786d96414e7204ea50ca5ea0263be97b581 Mon Sep 17 00:00:00 2001
From: xiaoguang wang <xwang@suse.com>
Date: Wed, 20 Feb 2019 09:26:02 +0800
Subject: [PATCH 40/51] display-store: make foreach ignore callback return
value
gdm_display_store_foreach is designed to iterate through all
displays in the display store. Under the hood, it currently
uses gdm_display_store_find, though, so will prematurely stop
it's loop if a callback returns TRUE. Callers are getting this
wrong. Some return TRUE with the expectation it goes on, and
some fail to return a value at all.
This commit changes gdm_display_store_foreach to use
g_hash_table_foreach instead, so the callback return values no
longer matter.
---
daemon/gdm-display-store.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/daemon/gdm-display-store.c b/daemon/gdm-display-store.c
index fd24334eb..910468cd7 100644
--- a/daemon/gdm-display-store.c
+++ b/daemon/gdm-display-store.c
@@ -119,76 +119,86 @@ remove_display (char *id,
}
gboolean
gdm_display_store_remove (GdmDisplayStore *store,
GdmDisplay *display)
{
g_return_val_if_fail (store != NULL, FALSE);
gdm_display_store_foreach_remove (store,
(GdmDisplayStoreFunc)remove_display,
display);
return FALSE;
}
typedef struct
{
GdmDisplayStoreFunc predicate;
gpointer user_data;
} FindClosure;
static gboolean
find_func (const char *id,
StoredDisplay *stored_display,
FindClosure *closure)
{
return closure->predicate (id,
stored_display->display,
closure->user_data);
}
+static void
+foreach_func (const char *id,
+ StoredDisplay *stored_display,
+ FindClosure *closure)
+{
+ (void) closure->predicate (id,
+ stored_display->display,
+ closure->user_data);
+}
+
void
gdm_display_store_foreach (GdmDisplayStore *store,
GdmDisplayStoreFunc func,
gpointer user_data)
{
FindClosure closure;
g_return_if_fail (store != NULL);
g_return_if_fail (func != NULL);
closure.predicate = func;
closure.user_data = user_data;
- g_hash_table_find (store->priv->displays,
- (GHRFunc) find_func,
- &closure);
+ g_hash_table_foreach (store->priv->displays,
+ (GHFunc) foreach_func,
+ &closure);
}
GdmDisplay *
gdm_display_store_lookup (GdmDisplayStore *store,
const char *id)
{
StoredDisplay *stored_display;
g_return_val_if_fail (store != NULL, NULL);
g_return_val_if_fail (id != NULL, NULL);
stored_display = g_hash_table_lookup (store->priv->displays,
id);
if (stored_display == NULL) {
return NULL;
}
return stored_display->display;
}
GdmDisplay *
gdm_display_store_find (GdmDisplayStore *store,
GdmDisplayStoreFunc predicate,
gpointer user_data)
{
StoredDisplay *stored_display;
FindClosure closure;
g_return_val_if_fail (store != NULL, NULL);
g_return_val_if_fail (predicate != NULL, NULL);
--
2.27.0

View File

@ -0,0 +1,180 @@
From 323358ef61d969588ea048d5b0eba6fd102d3dcf Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 21 Feb 2019 15:20:01 -0500
Subject: [PATCH 41/51] xdmcp-display-factory: don't return value from foreach
funcs
The xdmcp code is returning TRUE from its display store foreach
functions, which is useless since commit 47d01abe and wrong
before that.
This commit makes it return void instead.
---
daemon/gdm-xdmcp-display-factory.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/daemon/gdm-xdmcp-display-factory.c b/daemon/gdm-xdmcp-display-factory.c
index 5b5786c6f..2e14beab4 100644
--- a/daemon/gdm-xdmcp-display-factory.c
+++ b/daemon/gdm-xdmcp-display-factory.c
@@ -639,76 +639,74 @@ gdm_xdmcp_host_allow (GdmAddress *address)
{
#ifdef HAVE_TCPWRAPPERS
char *client;
char *host;
gboolean ret;
host = NULL;
client = NULL;
/* Find client hostname */
gdm_address_get_hostname (address, &client);
gdm_address_get_numeric_info (address, &host, NULL);
/* Check with tcp_wrappers if client is allowed to access */
ret = hosts_ctl ("gdm", client, host, "");
g_free (host);
g_free (client);
return ret;
#else /* HAVE_TCPWRAPPERS */
return (TRUE);
#endif /* HAVE_TCPWRAPPERS */
}
typedef struct {
GdmAddress *address;
int count;
} CountDisplayData;
-static gboolean
+static void
count_displays_from_host (const char *id,
GdmDisplay *display,
CountDisplayData *data)
{
GdmAddress *address;
if (GDM_IS_XDMCP_DISPLAY (display)) {
address = gdm_xdmcp_display_get_remote_address (GDM_XDMCP_DISPLAY (display));
if (gdm_address_equal (address, data->address)) {
data->count++;
}
}
-
- return TRUE;
}
static int
gdm_xdmcp_num_displays_from_host (GdmXdmcpDisplayFactory *factory,
GdmAddress *address)
{
CountDisplayData data;
GdmDisplayStore *store;
data.count = 0;
data.address = address;
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
gdm_display_store_foreach (store,
(GdmDisplayStoreFunc)count_displays_from_host,
&data);
return data.count;
}
typedef struct {
GdmAddress *address;
int display_num;
} LookupHostData;
static gboolean
lookup_by_host (const char *id,
GdmDisplay *display,
LookupHostData *data)
{
@@ -1780,78 +1778,76 @@ gdm_xdmcp_send_managed_forward (GdmXdmcpDisplayFactory *factory,
static void
gdm_xdmcp_send_got_managed_forward (GdmXdmcpDisplayFactory *factory,
GdmAddress *address,
GdmAddress *origin)
{
ARRAY8 addr;
XdmcpHeader header;
char *host;
host = NULL;
gdm_address_get_numeric_info (address, &host, NULL);
g_debug ("GdmXdmcpDisplayFactory: Sending GOT_MANAGED_FORWARD to %s",
host ? host : "(null)");
g_free (host);
set_address_for_request (origin, &addr);
header.opcode = (CARD16) GDM_XDMCP_GOT_MANAGED_FORWARD;
header.length = 4 + addr.length;
header.version = GDM_XDMCP_PROTOCOL_VERSION;
XdmcpWriteHeader (&factory->priv->buf, &header);
XdmcpWriteARRAY8 (&factory->priv->buf, &addr);
XdmcpFlush (factory->priv->socket_fd,
&factory->priv->buf,
(XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
(int)gdm_sockaddr_len (gdm_address_peek_sockaddr_storage (address)));
}
-static gboolean
+static void
count_sessions (const char *id,
GdmDisplay *display,
GdmXdmcpDisplayFactory *factory)
{
if (GDM_IS_XDMCP_DISPLAY (display)) {
int status;
status = gdm_display_get_status (display);
if (status == GDM_DISPLAY_MANAGED) {
factory->priv->num_sessions++;
} else if (status == GDM_DISPLAY_UNMANAGED) {
factory->priv->num_pending_sessions++;
}
}
-
- return TRUE;
}
static void
gdm_xdmcp_recount_sessions (GdmXdmcpDisplayFactory *factory)
{
GdmDisplayStore *store;
factory->priv->num_sessions = 0;
factory->priv->num_pending_sessions = 0;
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
gdm_display_store_foreach (store,
(GdmDisplayStoreFunc)count_sessions,
factory);
}
static gboolean
purge_displays (const char *id,
GdmDisplay *display,
GdmXdmcpDisplayFactory *factory)
{
if (GDM_IS_XDMCP_DISPLAY (display)) {
int status;
time_t currtime;
time_t acctime;
currtime = time (NULL);
status = gdm_display_get_status (display);
acctime = gdm_display_get_creation_time (display);
--
2.27.0

View File

@ -0,0 +1,538 @@
From 3cf5b4b12d3d39fa858ff593adeecfe711cdddaf Mon Sep 17 00:00:00 2001
From: Iain Lane <iainl@gnome.org>
Date: Tue, 7 May 2019 15:35:23 +0100
Subject: [PATCH 42/51] GdmLocalDisplayFactory: Store VT number, not tty
identifier
This makes the code a fair bit simpler.
---
configure.ac | 6 ++--
daemon/gdm-local-display-factory.c | 50 ++++++++++++++++--------------
daemon/gdm-server.c | 2 +-
daemon/gdm-session-worker.c | 2 +-
4 files changed, 31 insertions(+), 29 deletions(-)
diff --git a/configure.ac b/configure.ac
index c549146ce..0c138ab38 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1477,66 +1477,66 @@ fi
AC_SUBST(DEBUG_CFLAGS)
#
# Enable Profiling
#
AC_ARG_ENABLE(profiling,
AS_HELP_STRING([--enable-profiling],
[turn on profiling]),,
enable_profiling=yes)
if test "$enable_profiling" = "yes"; then
AC_DEFINE(ENABLE_PROFILING,1,[enable profiling])
fi
#
# Set SHELL to use in scripts.
#
if test x$os_solaris = xyes ; then
XSESSION_SHELL=/bin/ksh
else
XSESSION_SHELL=/bin/sh
fi
#
# Set VT to use for initial server
#
AC_ARG_WITH(initial-vt,
AS_HELP_STRING([--with-initial-vt=<nr>],
[Initial virtual terminal to use]))
if ! test -z "$with_initial_vt"; then
- GDM_INITIAL_VT="$with_initial_vt"
+ GDM_INITIAL_VT=$with_initial_vt
else
- GDM_INITIAL_VT="1"
+ GDM_INITIAL_VT=1
fi
AC_SUBST(GDM_INITIAL_VT)
-AC_DEFINE_UNQUOTED(GDM_INITIAL_VT, "$GDM_INITIAL_VT", [Initial Virtual Terminal])
+AC_DEFINE_UNQUOTED(GDM_INITIAL_VT, $GDM_INITIAL_VT, [Initial Virtual Terminal])
# Set configuration choices.
#
AC_SUBST(XSESSION_SHELL)
AC_DEFINE_UNQUOTED(XSESSION_SHELL,"$XSESSION_SHELL",[xsession shell])
AC_SUBST(SOUND_PROGRAM)
AC_DEFINE_UNQUOTED(SOUND_PROGRAM,"$SOUND_PROGRAM",[])
AC_SUBST(X_PATH)
AC_SUBST(X_SERVER)
AC_SUBST(X_SERVER_PATH)
AC_DEFINE_UNQUOTED(X_SERVER,"$X_SERVER",[])
AC_DEFINE_UNQUOTED(X_SERVER_PATH,"$X_SERVER_PATH",[])
## Stuff for debian/changelog.in
#if test -e "debian/changelog"; then
# DEBIAN_DATESTAMP=`head -1 debian/changelog| sed -e 's/.*cvs.//' -e 's/).*//'`
# DEBIAN_DATE=`grep '^ --' debian/changelog | head -1 | sed -e 's/.* //'`
#else
# DEBIAN_DATESTAMP=`date +%Y%m%d%H%M%s`
# DEBIAN_DATE=`date -R`
#fi
#
#AC_SUBST(DEBIAN_DATESTAMP)
#AC_SUBST(DEBIAN_DATE)
AC_CONFIG_FILES([
Makefile
pam-extensions/Makefile
pam-extensions/gdm-pam-extensions.pc
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index d999596b5..7a013c694 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -37,61 +37,61 @@
#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
#define WAIT_TO_FINISH_TIMEOUT 10 /* seconds */
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;
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
- char *tty_of_active_vt;
+ unsigned int active_vt;
guint active_vt_watch_id;
guint wait_to_finish_timeout_id;
#endif
};
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;
static gboolean lookup_by_session_id (const char *id,
GdmDisplay *display,
gpointer user_data);
G_DEFINE_TYPE (GdmLocalDisplayFactory, gdm_local_display_factory, GDM_TYPE_DISPLAY_FACTORY)
@@ -641,157 +641,161 @@ maybe_stop_greeter_in_background (GdmLocalDisplayFactory *factory,
g_debug ("GdmLocalDisplayFactory: login window is performing initial-setup, so ignoring");
return;
}
/* we can only stop greeter for wayland sessions, since
* X server would jump back on exit */
if (g_strcmp0 (display_session_type, "wayland") != 0) {
g_debug ("GdmLocalDisplayFactory: login window is running on Xorg, so ignoring");
return;
}
g_debug ("GdmLocalDisplayFactory: killing login window once its unused");
g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL);
/* We stop the greeter after a timeout to avoid flicker */
if (factory->priv->wait_to_finish_timeout_id != 0)
g_source_remove (factory->priv->wait_to_finish_timeout_id);
factory->priv->wait_to_finish_timeout_id =
g_timeout_add_seconds (WAIT_TO_FINISH_TIMEOUT,
(GSourceFunc)wait_to_finish_timeout,
factory);
}
static gboolean
on_vt_changed (GIOChannel *source,
GIOCondition condition,
GdmLocalDisplayFactory *factory)
{
GIOStatus status;
- static const char *tty_of_initial_vt = "tty" GDM_INITIAL_VT;
- g_autofree char *tty_of_previous_vt = NULL;
g_autofree char *tty_of_active_vt = NULL;
g_autofree char *login_session_id = NULL;
g_autofree char *active_session_id = NULL;
+ unsigned int previous_vt, new_vt;
const char *session_type = NULL;
- int ret;
+ int ret, n_returned;
g_debug ("GdmLocalDisplayFactory: received VT change event");
g_io_channel_seek_position (source, 0, G_SEEK_SET, NULL);
if (condition & G_IO_PRI) {
g_autoptr (GError) error = NULL;
status = g_io_channel_read_line (source, &tty_of_active_vt, NULL, NULL, &error);
if (error != NULL) {
g_warning ("could not read active VT from kernel: %s", error->message);
}
switch (status) {
case G_IO_STATUS_ERROR:
return G_SOURCE_REMOVE;
case G_IO_STATUS_EOF:
return G_SOURCE_REMOVE;
case G_IO_STATUS_AGAIN:
return G_SOURCE_CONTINUE;
case G_IO_STATUS_NORMAL:
break;
}
}
if ((condition & G_IO_ERR) || (condition & G_IO_HUP)) {
g_debug ("GdmLocalDisplayFactory: kernel hung up active vt watch");
return G_SOURCE_REMOVE;
}
if (tty_of_active_vt == NULL) {
g_debug ("GdmLocalDisplayFactory: unable to read active VT from kernel");
return G_SOURCE_CONTINUE;
}
g_strchomp (tty_of_active_vt);
+ errno = 0;
+ n_returned = sscanf (tty_of_active_vt, "tty%u", &new_vt);
+
+ if (n_returned != 1 || errno != 0) {
+ g_critical ("GdmLocalDisplayFactory: Couldn't read active VT (got '%s')",
+ tty_of_active_vt);
+ return G_SOURCE_CONTINUE;
+ }
+
/* don't do anything if we're on the same VT we were before */
- if (g_strcmp0 (tty_of_active_vt, factory->priv->tty_of_active_vt) == 0) {
+ if (new_vt == factory->priv->active_vt) {
g_debug ("GdmLocalDisplayFactory: VT changed to the same VT, ignoring");
return G_SOURCE_CONTINUE;
}
- tty_of_previous_vt = g_steal_pointer (&factory->priv->tty_of_active_vt);
- factory->priv->tty_of_active_vt = g_steal_pointer (&tty_of_active_vt);
+ previous_vt = factory->priv->active_vt;
+ factory->priv->active_vt = new_vt;
/* don't do anything at start up */
- if (tty_of_previous_vt == NULL) {
- g_debug ("GdmLocalDisplayFactory: VT is %s at startup",
- factory->priv->tty_of_active_vt);
+ if (previous_vt == 0) {
+ g_debug ("GdmLocalDisplayFactory: VT is %u at startup",
+ factory->priv->active_vt);
return G_SOURCE_CONTINUE;
}
- g_debug ("GdmLocalDisplayFactory: VT changed from %s to %s",
- tty_of_previous_vt, factory->priv->tty_of_active_vt);
+ g_debug ("GdmLocalDisplayFactory: VT changed from %u to %u",
+ previous_vt, factory->priv->active_vt);
/* if the old VT was running a wayland login screen kill it
*/
if (gdm_get_login_window_session_id ("seat0", &login_session_id)) {
- unsigned int vt;
+ unsigned int login_window_vt;
- ret = sd_session_get_vt (login_session_id, &vt);
- if (ret == 0 && vt != 0) {
- g_autofree char *tty_of_login_window_vt = NULL;
-
- tty_of_login_window_vt = g_strdup_printf ("tty%u", vt);
-
- g_debug ("GdmLocalDisplayFactory: tty of login window is %s", tty_of_login_window_vt);
- if (g_strcmp0 (tty_of_login_window_vt, tty_of_previous_vt) == 0) {
+ ret = sd_session_get_vt (login_session_id, &login_window_vt);
+ if (ret == 0 && login_window_vt != 0) {
+ g_debug ("GdmLocalDisplayFactory: VT of login window is %u", login_window_vt);
+ if (login_window_vt == previous_vt) {
GdmDisplayStore *store;
GdmDisplay *display;
g_debug ("GdmLocalDisplayFactory: VT switched from login window");
store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
display = gdm_display_store_find (store,
lookup_by_session_id,
(gpointer) login_session_id);
if (display != NULL)
maybe_stop_greeter_in_background (factory, display);
} else {
g_debug ("GdmLocalDisplayFactory: VT not switched from login window");
}
}
}
/* if user jumped back to initial vt and it's empty put a login screen
* on it (unless a login screen is already running elsewhere, then
* jump to that login screen)
*/
- if (strcmp (factory->priv->tty_of_active_vt, tty_of_initial_vt) != 0) {
+ if (factory->priv->active_vt != GDM_INITIAL_VT) {
g_debug ("GdmLocalDisplayFactory: active VT is not initial VT, so ignoring");
return G_SOURCE_CONTINUE;
}
if (gdm_local_display_factory_use_wayland ())
session_type = "wayland";
g_debug ("GdmLocalDisplayFactory: creating new display on seat0 because of VT change");
create_display (factory, "seat0", session_type, TRUE);
return G_SOURCE_CONTINUE;
}
#endif
static void
gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory)
{
g_autoptr (GIOChannel) io_channel = NULL;
factory->priv->seat_new_id = g_dbus_connection_signal_subscribe (factory->priv->connection,
"org.freedesktop.login1",
"org.freedesktop.login1.Manager",
"SeatNew",
"/org/freedesktop/login1",
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
on_seat_new,
g_object_ref (factory),
g_object_unref);
@@ -815,62 +819,60 @@ gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory)
G_IO_PRI,
(GIOFunc)
on_vt_changed,
factory);
}
#endif
}
static void
gdm_local_display_factory_stop_monitor (GdmLocalDisplayFactory *factory)
{
if (factory->priv->seat_new_id) {
g_dbus_connection_signal_unsubscribe (factory->priv->connection,
factory->priv->seat_new_id);
factory->priv->seat_new_id = 0;
}
if (factory->priv->seat_removed_id) {
g_dbus_connection_signal_unsubscribe (factory->priv->connection,
factory->priv->seat_removed_id);
factory->priv->seat_removed_id = 0;
}
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
if (factory->priv->wait_to_finish_timeout_id != 0) {
g_source_remove (factory->priv->wait_to_finish_timeout_id);
factory->priv->wait_to_finish_timeout_id = 0;
}
if (factory->priv->active_vt_watch_id) {
g_source_remove (factory->priv->active_vt_watch_id);
factory->priv->active_vt_watch_id = 0;
}
-
- g_clear_pointer (&factory->priv->tty_of_active_vt, g_free);
#endif
}
static void
on_display_added (GdmDisplayStore *display_store,
const char *id,
GdmLocalDisplayFactory *factory)
{
GdmDisplay *display;
display = gdm_display_store_lookup (display_store, id);
if (display != NULL) {
g_signal_connect_object (display, "notify::status",
G_CALLBACK (on_display_status_changed),
factory,
0);
g_object_weak_ref (G_OBJECT (display), (GWeakNotify)on_display_disposed, factory);
}
}
static void
on_display_removed (GdmDisplayStore *display_store,
GdmDisplay *display,
GdmLocalDisplayFactory *factory)
{
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);
}
diff --git a/daemon/gdm-server.c b/daemon/gdm-server.c
index 83fba99c8..04406a61a 100644
--- a/daemon/gdm-server.c
+++ b/daemon/gdm-server.c
@@ -726,61 +726,61 @@ gdm_server_spawn (GdmServer *server,
(GChildWatchFunc)server_child_watch,
server);
ret = TRUE;
out:
g_strfreev (argv);
if (env) {
g_ptr_array_foreach (env, (GFunc)g_free, NULL);
g_ptr_array_free (env, TRUE);
}
return ret;
}
/**
* gdm_server_start:
* @disp: Pointer to a GdmDisplay structure
*
* Starts a local X server. Handles retries and fatal errors properly.
*/
gboolean
gdm_server_start (GdmServer *server)
{
gboolean res = FALSE;
const char *vtarg = NULL;
GError *local_error = NULL;
GError **error = &local_error;
/* Hardcode the VT for the initial X server, but nothing else */
if (server->priv->is_initial) {
- vtarg = "vt" GDM_INITIAL_VT;
+ vtarg = "vt" G_STRINGIFY (GDM_INITIAL_VT);
}
/* fork X server process */
if (!gdm_server_spawn (server, vtarg, error)) {
goto out;
}
res = TRUE;
out:
if (local_error) {
g_printerr ("%s\n", local_error->message);
g_clear_error (&local_error);
}
return res;
}
static void
server_died (GdmServer *server)
{
int exit_status;
g_debug ("GdmServer: Waiting on process %d", server->priv->pid);
exit_status = gdm_wait_on_pid (server->priv->pid);
if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) {
g_debug ("GdmServer: Wait on child process failed");
} else {
/* exited normally */
}
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 7ed2789da..b4befaa83 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -2202,61 +2202,61 @@ gdm_session_worker_start_session (GdmSessionWorker *worker,
g_debug ("GdmSessionWorker: 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);
+ session_vt = GDM_INITIAL_VT;
} else {
if (ioctl(fd, VT_OPENQRY, &session_vt) < 0) {
g_debug ("GdmSessionWorker: couldn't open new VT: %m");
goto fail;
}
}
worker->priv->session_vt = session_vt;
close (fd);
fd = -1;
g_assert (session_vt > 0);
g_snprintf (vt_string, sizeof (vt_string), "%d", session_vt);
/* Set the VTNR. This is used by logind to configure a session in
* the logind-managed case, but it doesn't hurt to set it always.
* When logind gains support for XDG_VTNR=auto, we can make the
* OPENQRY and this whole path only used by the new VT code. */
gdm_session_worker_set_environment_variable (worker,
"XDG_VTNR",
vt_string);
g_snprintf (tty_string, 256, "/dev/tty%d", session_vt);
worker->priv->session_tty_fd = open (tty_string, O_RDWR | O_NOCTTY);
pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string);
return TRUE;
--
2.27.0

View File

@ -0,0 +1,344 @@
From 476230f7b721781c682d26983c9a2fd82afc45e1 Mon Sep 17 00:00:00 2001
From: Benjamin Berg <bberg@redhat.com>
Date: Wed, 25 Sep 2019 14:51:40 +0200
Subject: [PATCH 43/51] 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 <iainl@gnome.org>,
taking into account that we can make the assumption about the login_vt.
Closes #515
---
daemon/gdm-session-worker.c | 43 +++++++++----------------------------
1 file changed, 10 insertions(+), 33 deletions(-)
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index b4befaa83..0bd78cfaf 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[] = {
@@ -1029,141 +1028,120 @@ 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);
+ /* Switch to the login VT if we are not the login screen. */
+ if (worker->priv->session_vt != GDM_INITIAL_VT) {
+ jump_to_vt (worker, GDM_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
@@ -1204,64 +1182,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);
+ g_snprintf (tty_string, 256, "/dev/tty%d", GDM_INITIAL_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;
if (password_is_required) {
authentication_flags |= PAM_DISALLOW_NULL_AUTHTOK;
}
/* blocking call, does the actual conversation */
--
2.27.0

View File

@ -0,0 +1,160 @@
From 75b65846ca77bd2d42e25365b4b7242a406330cf Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 7 Apr 2020 14:37:41 -0400
Subject: [PATCH 44/51] session-worker: ensure initial vt is never picked for
!is_initial displays
Normally, a !is_initial display would never "get" tty1, since the system
boots to tty1. But if, for some reason, the user booted to runlevel 3,
then switched to runlevel 5, the login screen could get started when
tty1 is free.
That means, e.g., an autologin user can end up getting allocated tty1,
which is bad, since we assume tty1 is used for the login screen.
This commit opens up /dev/tty1 when querying for available VTs, so that
it never gets returned by the kernel as available.
---
daemon/gdm-session-worker.c | 39 +++++++++++++++++++++++++------------
1 file changed, 27 insertions(+), 12 deletions(-)
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 0bd78cfaf..42c415837 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -2167,105 +2167,120 @@ gdm_session_worker_start_session (GdmSessionWorker *worker,
/* 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");
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;
+ int initial_vt_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");
+ /* open the initial vt. We need it for two scenarios:
+ *
+ * 1) display_is_initial is TRUE. We need it directly.
+ * 2) display_is_initial is FALSE. We need it to mark
+ * the initial VT as "in use" so it doesn't get returned
+ * by VT_OPENQRY
+ * */
+ g_snprintf (tty_string, sizeof (tty_string), "/dev/tty%d", GDM_INITIAL_VT);
+ initial_vt_fd = open (tty_string, O_RDWR | O_NOCTTY);
+
+ if (initial_vt_fd < 0) {
+ g_debug ("GdmSessionWorker: couldn't open console of initial fd: %m");
return FALSE;
}
if (worker->priv->display_is_initial) {
session_vt = GDM_INITIAL_VT;
} else {
- if (ioctl(fd, VT_OPENQRY, &session_vt) < 0) {
+
+ /* Typically VT_OPENQRY is called on /dev/tty0, but we already
+ * have /dev/tty1 open above, so might as well use it.
+ */
+ if (ioctl (initial_vt_fd, VT_OPENQRY, &session_vt) < 0) {
g_debug ("GdmSessionWorker: couldn't open new VT: %m");
goto fail;
}
}
worker->priv->session_vt = session_vt;
- close (fd);
- fd = -1;
-
g_assert (session_vt > 0);
g_snprintf (vt_string, sizeof (vt_string), "%d", session_vt);
/* Set the VTNR. This is used by logind to configure a session in
* the logind-managed case, but it doesn't hurt to set it always.
* When logind gains support for XDG_VTNR=auto, we can make the
* OPENQRY and this whole path only used by the new VT code. */
gdm_session_worker_set_environment_variable (worker,
"XDG_VTNR",
vt_string);
- g_snprintf (tty_string, 256, "/dev/tty%d", session_vt);
- worker->priv->session_tty_fd = open (tty_string, O_RDWR | O_NOCTTY);
+ if (worker->priv->display_is_initial) {
+ worker->priv->session_tty_fd = initial_vt_fd;
+ } else {
+ g_snprintf (tty_string, sizeof (tty_string), "/dev/tty%d", session_vt);
+ worker->priv->session_tty_fd = open (tty_string, O_RDWR | O_NOCTTY);
+ close (initial_vt_fd);
+ }
+
pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string);
return TRUE;
fail:
- close (fd);
+ close (initial_vt_fd);
return FALSE;
}
static gboolean
set_xdg_vtnr_to_current_vt (GdmSessionWorker *worker)
{
int fd;
char vt_string[256];
struct vt_stat vt_state = { 0 };
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 fail;
}
close (fd);
fd = -1;
g_snprintf (vt_string, sizeof (vt_string), "%d", vt_state.v_active);
gdm_session_worker_set_environment_variable (worker,
"XDG_VTNR",
vt_string);
--
2.27.0

View File

@ -0,0 +1,114 @@
From fc3503f16e9de535d2a36b904720b360370f880f Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 15 May 2020 10:08:24 -0400
Subject: [PATCH 45/51] local-display-factory: Always force login screen to VT
1
These days we always want the login screen on VT 1, even
when it's created by user switching.
Unfortunately, since commit f843233ad the login screen
won't naturally pick VT 1 when user switching.
This commit forces it to make the right choice.
Closes https://gitlab.gnome.org/GNOME/gdm/-/issues/602
---
daemon/gdm-local-display-factory.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 7a013c694..a288f8765 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -197,84 +197,87 @@ store_display (GdmLocalDisplayFactory *factory,
gdm_display_store_add (store, display);
}
static gboolean
gdm_local_display_factory_use_wayland (void)
{
#ifdef ENABLE_WAYLAND_SUPPORT
gboolean wayland_enabled = FALSE;
if (gdm_settings_direct_get_boolean (GDM_KEY_WAYLAND_ENABLE, &wayland_enabled)) {
if (wayland_enabled && g_file_test ("/usr/bin/Xwayland", G_FILE_TEST_IS_EXECUTABLE) )
return TRUE;
}
#endif
return FALSE;
}
/*
Example:
dbus-send --system --dest=org.gnome.DisplayManager \
--type=method_call --print-reply --reply-timeout=2000 \
/org/gnome/DisplayManager/Manager \
org.gnome.DisplayManager.Manager.GetDisplays
*/
gboolean
gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *factory,
char **id,
GError **error)
{
gboolean ret;
GdmDisplay *display = NULL;
+ gboolean is_initial = FALSE;
g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
ret = FALSE;
g_debug ("GdmLocalDisplayFactory: Creating transient display");
#ifdef ENABLE_USER_DISPLAY_SERVER
display = gdm_local_display_new ();
if (gdm_local_display_factory_use_wayland ())
g_object_set (G_OBJECT (display), "session-type", "wayland", NULL);
+ is_initial = TRUE;
#else
if (display == NULL) {
guint32 num;
num = take_next_display_number (factory);
display = gdm_legacy_display_new (num);
}
#endif
g_object_set (display,
"seat-id", "seat0",
"allow-timed-login", FALSE,
+ "is-initial", is_initial,
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 gboolean
finish_display_on_seat_if_waiting (GdmDisplayStore *display_store,
GdmDisplay *display,
const char *seat_id)
{
if (gdm_display_get_status (display) != GDM_DISPLAY_WAITING_TO_FINISH)
return FALSE;
--
2.27.0

View File

@ -0,0 +1,81 @@
From 763e31a576a4cd665e5ad06ad0eb4610cecc0b42 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 10 Jul 2020 10:45:52 -0400
Subject: [PATCH 46/51] gdm-x-session: tell x server to not vt switch
gdm already handles the VT switching on X's behalf,
so it's redundant, and X does it at inopportune times,
so instruct it to not get involved.
---
daemon/gdm-x-session.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/daemon/gdm-x-session.c b/daemon/gdm-x-session.c
index 3b2fcef47..d8e3c7d53 100644
--- a/daemon/gdm-x-session.c
+++ b/daemon/gdm-x-session.c
@@ -247,60 +247,61 @@ spawn_x_server (State *state,
}
g_ptr_array_add (arguments, "-displayfd");
g_ptr_array_add (arguments, display_fd_string);
g_ptr_array_add (arguments, "-auth");
g_ptr_array_add (arguments, auth_file);
/* If we were compiled with Xserver >= 1.17 we need to specify
* '-listen tcp' as the X server dosen't listen on tcp sockets
* by default anymore. In older versions we need to pass
* -nolisten tcp to disable listening on tcp sockets.
*/
#ifdef HAVE_XSERVER_THAT_DEFAULTS_TO_LOCAL_ONLY
if (allow_remote_connections) {
g_ptr_array_add (arguments, "-listen");
g_ptr_array_add (arguments, "tcp");
}
#else
if (!allow_remote_connections) {
g_ptr_array_add (arguments, "-nolisten");
g_ptr_array_add (arguments, "tcp");
}
#endif
g_ptr_array_add (arguments, "-background");
g_ptr_array_add (arguments, "none");
g_ptr_array_add (arguments, "-noreset");
g_ptr_array_add (arguments, "-keeptty");
+ g_ptr_array_add (arguments, "-novtswitch");
g_ptr_array_add (arguments, "-verbose");
if (state->debug_enabled) {
g_ptr_array_add (arguments, "7");
} else {
g_ptr_array_add (arguments, "3");
}
if (state->debug_enabled) {
g_ptr_array_add (arguments, "-core");
}
g_ptr_array_add (arguments, NULL);
subprocess = g_subprocess_launcher_spawnv (launcher,
(const char * const *) arguments->pdata,
&error);
g_free (display_fd_string);
g_clear_object (&launcher);
g_ptr_array_free (arguments, TRUE);
if (subprocess == NULL) {
g_debug ("could not start X server: %s", error->message);
goto out;
}
input_stream = g_unix_input_stream_new (pipe_fds[0], TRUE);
data_stream = g_data_input_stream_new (input_stream);
g_clear_object (&input_stream);
display_number = g_data_input_stream_read_line (data_stream,
--
2.27.0

View File

@ -0,0 +1,115 @@
From a1c74e2e42dea464ab0b439b767da5c12cbf3986 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 11 Oct 2018 07:15:56 -0400
Subject: [PATCH 47/51] local-display-factory: kill X on login just like
wayland
These days we kill the wayland login screen during login to
conserve system resources.
We've been reluctant to do the same for X based login screens,
because X didn't handle being killed in the background so well.
This is no longer a problem, since this commit:
https://gitlab.freedesktop.org/xorg/xserver/-/commit/ff91c696ff8f5f56da40e107cb5c321539758a81
So let's go ahead and kill it now.
---
daemon/gdm-local-display-factory.c | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index a288f8765..aae226750 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -599,86 +599,77 @@ on_seat_removed (GDBusConnection *connection,
g_variant_get (parameters, "(&s&o)", &seat, NULL);
delete_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat);
}
#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
static gboolean
lookup_by_session_id (const char *id,
GdmDisplay *display,
gpointer user_data)
{
const char *looking_for = user_data;
const char *current;
current = gdm_display_get_session_id (display);
return g_strcmp0 (current, looking_for) == 0;
}
static gboolean
wait_to_finish_timeout (GdmLocalDisplayFactory *factory)
{
finish_waiting_displays_on_seat (factory, "seat0");
factory->priv->wait_to_finish_timeout_id = 0;
return G_SOURCE_REMOVE;
}
static void
maybe_stop_greeter_in_background (GdmLocalDisplayFactory *factory,
GdmDisplay *display)
{
- g_autofree char *display_session_type = NULL;
gboolean doing_initial_setup = FALSE;
if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED) {
g_debug ("GdmLocalDisplayFactory: login window not in managed state, so ignoring");
return;
}
g_object_get (G_OBJECT (display),
- "session-type", &display_session_type,
"doing-initial-setup", &doing_initial_setup,
NULL);
/* we don't ever stop initial-setup implicitly */
if (doing_initial_setup) {
g_debug ("GdmLocalDisplayFactory: login window is performing initial-setup, so ignoring");
return;
}
- /* we can only stop greeter for wayland sessions, since
- * X server would jump back on exit */
- if (g_strcmp0 (display_session_type, "wayland") != 0) {
- g_debug ("GdmLocalDisplayFactory: login window is running on Xorg, so ignoring");
- return;
- }
-
g_debug ("GdmLocalDisplayFactory: killing login window once its unused");
g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL);
/* We stop the greeter after a timeout to avoid flicker */
if (factory->priv->wait_to_finish_timeout_id != 0)
g_source_remove (factory->priv->wait_to_finish_timeout_id);
factory->priv->wait_to_finish_timeout_id =
g_timeout_add_seconds (WAIT_TO_FINISH_TIMEOUT,
(GSourceFunc)wait_to_finish_timeout,
factory);
}
static gboolean
on_vt_changed (GIOChannel *source,
GIOCondition condition,
GdmLocalDisplayFactory *factory)
{
GIOStatus status;
g_autofree char *tty_of_active_vt = NULL;
g_autofree char *login_session_id = NULL;
g_autofree char *active_session_id = NULL;
unsigned int previous_vt, new_vt;
const char *session_type = NULL;
int ret, n_returned;
g_debug ("GdmLocalDisplayFactory: received VT change event");
g_io_channel_seek_position (source, 0, G_SEEK_SET, NULL);
if (condition & G_IO_PRI) {
--
2.27.0

View File

@ -0,0 +1,149 @@
From f1b7d85b46dfc253176d6a043dcce26da3a26dfb Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 13 Jul 2020 09:23:06 -0400
Subject: [PATCH 48/51] manager: don't kill initial-setup right away with Xorg
either
The login screen for both Xorg and wayland sessions is now silently
killed in the background post login.
We still kill initial-setup for Xorg sessions up front, though.
This commit fixes that.
---
daemon/gdm-manager.c | 20 ++------------------
1 file changed, 2 insertions(+), 18 deletions(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index cf982870c..b147d73db 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1757,123 +1757,107 @@ chown_initial_setup_home_dir (void)
uid = (uid_t) atoi (gis_uid_contents);
pwe = getpwuid (uid);
if (uid == 0 || pwe == NULL) {
g_warning ("UID '%s' in %s is not valid", gis_uid_contents, gis_uid_path);
goto out;
}
error = NULL;
dir = g_file_new_for_path (gis_dir_path);
if (!chown_recursively (dir, pwe->pw_uid, pwe->pw_gid, &error)) {
g_warning ("Failed to change ownership for %s: %s", gis_dir_path, error->message);
g_error_free (error);
}
g_object_unref (dir);
out:
g_free (gis_uid_contents);
g_free (gis_uid_path);
g_free (gis_dir_path);
}
static gboolean
on_start_user_session (StartUserSessionOperation *operation)
{
GdmManager *self = operation->manager;
gboolean migrated;
gboolean fail_if_already_switched = TRUE;
gboolean doing_initial_setup = FALSE;
GdmDisplay *display;
const char *session_id;
-#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
- g_autofree char *display_session_type = NULL;
-#endif
g_debug ("GdmManager: start or jump to session");
/* If there's already a session running, jump to it.
* If the only session running is the one we just opened,
* start a session on it.
*/
migrated = switch_to_compatible_user_session (operation->manager, operation->session, fail_if_already_switched);
g_debug ("GdmManager: migrated: %d", migrated);
if (migrated) {
/* We don't stop the manager here because
when Xorg exits it switches to the VT it was
started from. That interferes with fast
user switching. */
gdm_session_reset (operation->session);
destroy_start_user_session_operation (operation);
goto out;
}
display = get_display_for_user_session (operation->session);
g_object_get (G_OBJECT (display),
"doing-initial-setup", &doing_initial_setup,
-#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
- "session-type", &display_session_type,
-#endif
NULL);
session_id = gdm_session_get_conversation_session_id (operation->session,
operation->service_name);
if (gdm_session_get_display_mode (operation->session) == GDM_SESSION_DISPLAY_MODE_REUSE_VT) {
/* In this case, the greeter's display is morphing into
* the user session display. Kill the greeter on this session
* and let the user session follow the same display. */
gdm_display_stop_greeter_session (display);
g_object_set (G_OBJECT (display),
"session-class", "user",
"session-id", session_id,
NULL);
} else {
uid_t allowed_uid;
g_object_ref (display);
if (doing_initial_setup) {
g_autoptr(GError) error = NULL;
-#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
- if (g_strcmp0 (display_session_type, "wayland") == 0) {
- g_debug ("GdmManager: closing down initial setup display in background");
- g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL);
- }
-#endif
- if (gdm_display_get_status (display) == GDM_DISPLAY_MANAGED) {
- g_debug ("GdmManager: closing down initial setup display");
- gdm_display_stop_greeter_session (display);
- gdm_display_unmanage (display);
- gdm_display_finish (display);
- }
+ g_debug ("GdmManager: closing down initial setup display in background");
+ g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL);
chown_initial_setup_home_dir ();
if (!g_file_set_contents (ALREADY_RAN_INITIAL_SETUP_ON_THIS_BOOT,
"1",
1,
&error)) {
g_warning ("GdmDisplay: Could not write initial-setup-done marker to %s: %s",
ALREADY_RAN_INITIAL_SETUP_ON_THIS_BOOT,
error->message);
g_clear_error (&error);
}
} else {
g_debug ("GdmManager: session has its display server, reusing our server for another login screen");
}
/* The user session is going to follow the session worker
* into the new display. Untie it from this display and
* create a new session for a future user login. */
allowed_uid = gdm_session_get_allowed_user (operation->session);
g_object_set_data (G_OBJECT (display), "gdm-user-session", NULL);
g_object_set_data (G_OBJECT (operation->session), "gdm-display", NULL);
create_user_session_for_display (operation->manager, display, allowed_uid);
/* Give the user session a new display object for bookkeeping purposes */
create_display_for_user_session (operation->manager,
operation->session,
session_id);
if ((g_strcmp0 (operation->service_name, "gdm-autologin") == 0) &&
--
2.27.0

View File

@ -0,0 +1,551 @@
From 2724b4fd6d4ac527acc481f056f535141b63fe24 Mon Sep 17 00:00:00 2001
From: Iain Lane <iainl@gnome.org>
Date: Tue, 7 May 2019 15:57:43 +0100
Subject: [PATCH 49/51] GdmManager, GdmDisplay: Add RegisterSession method
Window managers can use this to register with GDM when they've finished
starting up and started displaying.
---
daemon/gdm-display.c | 24 ++++++++++++++++++++++++
daemon/gdm-manager.c | 30 ++++++++++++++++++++++++++++++
daemon/gdm-manager.xml | 3 +++
3 files changed, 57 insertions(+)
diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c
index 1cef8c7c1..56799741d 100644
--- a/daemon/gdm-display.c
+++ b/daemon/gdm-display.c
@@ -64,82 +64,84 @@ struct GdmDisplayPrivate
char *remote_hostname;
int x11_display_number;
char *x11_display_name;
int status;
time_t creation_time;
GTimer *server_timer;
char *x11_cookie;
gsize x11_cookie_size;
GdmDisplayAccessFile *access_file;
guint finish_idle_id;
xcb_connection_t *xcb_connection;
int xcb_screen_number;
GDBusConnection *connection;
GdmDisplayAccessFile *user_access_file;
GdmDBusDisplay *display_skeleton;
GDBusObjectSkeleton *object_skeleton;
/* this spawns and controls the greeter session */
GdmLaunchEnvironment *launch_environment;
guint is_local : 1;
guint is_initial : 1;
guint allow_timed_login : 1;
guint have_existing_user_accounts : 1;
guint doing_initial_setup : 1;
+ guint session_registered : 1;
};
enum {
PROP_0,
PROP_ID,
PROP_STATUS,
PROP_SEAT_ID,
PROP_SESSION_ID,
PROP_SESSION_CLASS,
PROP_SESSION_TYPE,
PROP_REMOTE_HOSTNAME,
PROP_X11_DISPLAY_NUMBER,
PROP_X11_DISPLAY_NAME,
PROP_X11_COOKIE,
PROP_X11_AUTHORITY_FILE,
PROP_IS_CONNECTED,
PROP_IS_LOCAL,
PROP_LAUNCH_ENVIRONMENT,
PROP_IS_INITIAL,
PROP_ALLOW_TIMED_LOGIN,
PROP_HAVE_EXISTING_USER_ACCOUNTS,
PROP_DOING_INITIAL_SETUP,
+ PROP_SESSION_REGISTERED,
};
static void gdm_display_class_init (GdmDisplayClass *klass);
static void gdm_display_init (GdmDisplay *self);
static void gdm_display_finalize (GObject *object);
static void queue_finish (GdmDisplay *self);
static void _gdm_display_set_status (GdmDisplay *self,
int status);
static gboolean wants_initial_setup (GdmDisplay *self);
G_DEFINE_ABSTRACT_TYPE (GdmDisplay, gdm_display, G_TYPE_OBJECT)
GQuark
gdm_display_error_quark (void)
{
static GQuark ret = 0;
if (ret == 0) {
ret = g_quark_from_static_string ("gdm_display_error");
}
return ret;
}
time_t
gdm_display_get_creation_time (GdmDisplay *self)
{
g_return_val_if_fail (GDM_IS_DISPLAY (self), 0);
return self->priv->creation_time;
}
@@ -733,60 +735,68 @@ static void
_gdm_display_set_x11_display_number (GdmDisplay *self,
int num)
{
self->priv->x11_display_number = num;
}
static void
_gdm_display_set_x11_display_name (GdmDisplay *self,
const char *x11_display)
{
g_free (self->priv->x11_display_name);
self->priv->x11_display_name = g_strdup (x11_display);
}
static void
_gdm_display_set_x11_cookie (GdmDisplay *self,
const char *x11_cookie)
{
g_free (self->priv->x11_cookie);
self->priv->x11_cookie = g_strdup (x11_cookie);
}
static void
_gdm_display_set_is_local (GdmDisplay *self,
gboolean is_local)
{
g_debug ("GdmDisplay: local: %s", is_local? "yes" : "no");
self->priv->is_local = is_local;
}
+static void
+_gdm_display_set_session_registered (GdmDisplay *self,
+ gboolean registered)
+{
+ g_debug ("GdmDisplay: session registered: %s", registered? "yes" : "no");
+ self->priv->session_registered = registered;
+}
+
static void
_gdm_display_set_launch_environment (GdmDisplay *self,
GdmLaunchEnvironment *launch_environment)
{
g_clear_object (&self->priv->launch_environment);
self->priv->launch_environment = g_object_ref (launch_environment);
}
static void
_gdm_display_set_is_initial (GdmDisplay *self,
gboolean initial)
{
g_debug ("GdmDisplay: initial: %s", initial? "yes" : "no");
self->priv->is_initial = initial;
}
static void
_gdm_display_set_allow_timed_login (GdmDisplay *self,
gboolean allow_timed_login)
{
g_debug ("GdmDisplay: allow timed login: %s", allow_timed_login? "yes" : "no");
self->priv->allow_timed_login = allow_timed_login;
}
static void
gdm_display_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
@@ -811,60 +821,63 @@ gdm_display_set_property (GObject *object,
case PROP_SESSION_CLASS:
_gdm_display_set_session_class (self, g_value_get_string (value));
break;
case PROP_SESSION_TYPE:
_gdm_display_set_session_type (self, g_value_get_string (value));
break;
case PROP_REMOTE_HOSTNAME:
_gdm_display_set_remote_hostname (self, g_value_get_string (value));
break;
case PROP_X11_DISPLAY_NUMBER:
_gdm_display_set_x11_display_number (self, g_value_get_int (value));
break;
case PROP_X11_DISPLAY_NAME:
_gdm_display_set_x11_display_name (self, g_value_get_string (value));
break;
case PROP_X11_COOKIE:
_gdm_display_set_x11_cookie (self, g_value_get_string (value));
break;
case PROP_IS_LOCAL:
_gdm_display_set_is_local (self, g_value_get_boolean (value));
break;
case PROP_ALLOW_TIMED_LOGIN:
_gdm_display_set_allow_timed_login (self, g_value_get_boolean (value));
break;
case PROP_LAUNCH_ENVIRONMENT:
_gdm_display_set_launch_environment (self, g_value_get_object (value));
break;
case PROP_IS_INITIAL:
_gdm_display_set_is_initial (self, g_value_get_boolean (value));
break;
+ case PROP_SESSION_REGISTERED:
+ _gdm_display_set_session_registered (self, g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_display_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdmDisplay *self;
self = GDM_DISPLAY (object);
switch (prop_id) {
case PROP_ID:
g_value_set_string (value, self->priv->id);
break;
case PROP_STATUS:
g_value_set_int (value, self->priv->status);
break;
case PROP_SEAT_ID:
g_value_set_string (value, self->priv->seat_id);
break;
case PROP_SESSION_ID:
g_value_set_string (value, self->priv->session_id);
break;
case PROP_SESSION_CLASS:
@@ -881,60 +894,63 @@ gdm_display_get_property (GObject *object,
break;
case PROP_X11_DISPLAY_NAME:
g_value_set_string (value, self->priv->x11_display_name);
break;
case PROP_X11_COOKIE:
g_value_set_string (value, self->priv->x11_cookie);
break;
case PROP_X11_AUTHORITY_FILE:
g_value_take_string (value,
self->priv->access_file?
gdm_display_access_file_get_path (self->priv->access_file) : NULL);
break;
case PROP_IS_LOCAL:
g_value_set_boolean (value, self->priv->is_local);
break;
case PROP_IS_CONNECTED:
g_value_set_boolean (value, self->priv->xcb_connection != NULL);
break;
case PROP_LAUNCH_ENVIRONMENT:
g_value_set_object (value, self->priv->launch_environment);
break;
case PROP_IS_INITIAL:
g_value_set_boolean (value, self->priv->is_initial);
break;
case PROP_HAVE_EXISTING_USER_ACCOUNTS:
g_value_set_boolean (value, self->priv->have_existing_user_accounts);
break;
case PROP_DOING_INITIAL_SETUP:
g_value_set_boolean (value, self->priv->doing_initial_setup);
break;
+ case PROP_SESSION_REGISTERED:
+ g_value_set_boolean (value, priv->session_registered);
+ break;
case PROP_ALLOW_TIMED_LOGIN:
g_value_set_boolean (value, self->priv->allow_timed_login);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
handle_get_id (GdmDBusDisplay *skeleton,
GDBusMethodInvocation *invocation,
GdmDisplay *self)
{
char *id;
gdm_display_get_id (self, &id, NULL);
gdm_dbus_display_complete_get_id (skeleton, invocation, id);
g_free (id);
return TRUE;
}
static gboolean
handle_get_remote_hostname (GdmDBusDisplay *skeleton,
GDBusMethodInvocation *invocation,
GdmDisplay *self)
{
char *hostname;
@@ -1197,60 +1213,68 @@ gdm_display_class_init (GdmDisplayClass *klass)
G_PARAM_READABLE));
g_object_class_install_property (object_class,
PROP_IS_LOCAL,
g_param_spec_boolean ("is-local",
NULL,
NULL,
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_IS_CONNECTED,
g_param_spec_boolean ("is-connected",
NULL,
NULL,
TRUE,
G_PARAM_READABLE));
g_object_class_install_property (object_class,
PROP_HAVE_EXISTING_USER_ACCOUNTS,
g_param_spec_boolean ("have-existing-user-accounts",
NULL,
NULL,
FALSE,
G_PARAM_READABLE));
g_object_class_install_property (object_class,
PROP_DOING_INITIAL_SETUP,
g_param_spec_boolean ("doing-initial-setup",
NULL,
NULL,
FALSE,
G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ PROP_SESSION_REGISTERED,
+ g_param_spec_boolean ("session-registered",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
g_object_class_install_property (object_class,
PROP_LAUNCH_ENVIRONMENT,
g_param_spec_object ("launch-environment",
NULL,
NULL,
GDM_TYPE_LAUNCH_ENVIRONMENT,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_STATUS,
g_param_spec_int ("status",
"status",
"status",
-1,
G_MAXINT,
GDM_DISPLAY_UNMANAGED,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_type_class_add_private (klass, sizeof (GdmDisplayPrivate));
}
static void
gdm_display_init (GdmDisplay *self)
{
self->priv = GDM_DISPLAY_GET_PRIVATE (self);
self->priv->creation_time = time (NULL);
self->priv->server_timer = g_timer_new ();
}
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index b147d73db..bff602a07 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -789,60 +789,89 @@ gdm_manager_handle_register_display (GdmDBusManager *manager,
if (session != NULL) {
GPid pid;
if (x11_display_name != NULL) {
g_object_set (G_OBJECT (session), "display-name", x11_display_name, NULL);
g_object_set (G_OBJECT (display), "x11-display-name", x11_display_name, NULL);
}
/* FIXME: this should happen in gdm-session.c when the session is opened
*/
if (tty != NULL)
g_object_set (G_OBJECT (session), "display-device", tty, NULL);
pid = gdm_session_get_pid (session);
if (pid > 0) {
add_session_record (self, session, pid, SESSION_RECORD_LOGIN);
}
}
g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_MANAGED, NULL);
gdm_dbus_manager_complete_register_display (GDM_DBUS_MANAGER (manager),
invocation);
g_clear_pointer (&x11_display_name, g_free);
g_clear_pointer (&tty, g_free);
return TRUE;
}
+static gboolean
+gdm_manager_handle_register_session (GdmDBusManager *manager,
+ GDBusMethodInvocation *invocation,
+ GVariant *details)
+{
+ GdmManager *self = GDM_MANAGER (manager);
+ GdmDisplay *display;
+ const char *sender;
+ GDBusConnection *connection;
+
+ sender = g_dbus_method_invocation_get_sender (invocation);
+ connection = g_dbus_method_invocation_get_connection (invocation);
+
+ get_display_and_details_for_bus_sender (self, connection, sender, &display,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ g_debug ("GdmManager: trying to register new session on display %p", display);
+
+ if (display != NULL)
+ g_object_set (G_OBJECT (display), "session-registered", TRUE, NULL);
+ else
+ g_debug ("GdmManager: No display, not registering");
+
+ gdm_dbus_manager_complete_register_session (GDM_DBUS_MANAGER (manager),
+ invocation);
+
+ return TRUE;
+}
+
static gboolean
gdm_manager_handle_open_session (GdmDBusManager *manager,
GDBusMethodInvocation *invocation)
{
GdmManager *self = GDM_MANAGER (manager);
const char *sender;
GDBusConnection *connection;
GdmDisplay *display = NULL;
GdmSession *session = NULL;
const char *address;
GPid pid = 0;
uid_t uid = (uid_t) -1;
uid_t allowed_user;
g_debug ("GdmManager: trying to open new session");
sender = g_dbus_method_invocation_get_sender (invocation);
connection = g_dbus_method_invocation_get_connection (invocation);
get_display_and_details_for_bus_sender (self, connection, sender, &display, NULL, NULL, NULL, &pid, &uid, NULL, NULL);
if (display == NULL) {
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
_("No session available"));
return TRUE;
}
#ifdef HAVE_LIBXDMCP
@@ -1167,60 +1196,61 @@ gdm_manager_handle_open_reauthentication_channel (GdmDBusManager *manager
g_hash_table_insert (self->priv->open_reauthentication_requests,
GINT_TO_POINTER (pid),
invocation);
} else if (is_login_screen) {
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Login screen only allowed to open reauthentication channels for running sessions");
return TRUE;
} else {
char *address;
address = open_temporary_reauthentication_channel (self,
seat_id,
session_id,
pid,
uid,
is_remote);
gdm_dbus_manager_complete_open_reauthentication_channel (GDM_DBUS_MANAGER (manager),
invocation,
address);
g_free (address);
}
return TRUE;
}
static void
manager_interface_init (GdmDBusManagerIface *interface)
{
interface->handle_register_display = gdm_manager_handle_register_display;
+ interface->handle_register_session = gdm_manager_handle_register_session;
interface->handle_open_session = gdm_manager_handle_open_session;
interface->handle_open_reauthentication_channel = gdm_manager_handle_open_reauthentication_channel;
}
static gboolean
display_is_on_seat0 (GdmDisplay *display)
{
gboolean is_on_seat0 = TRUE;
char *seat_id = NULL;
g_object_get (G_OBJECT (display), "seat-id", &seat_id, NULL);
if (g_strcmp0 (seat_id, "seat0") != 0) {
is_on_seat0 = FALSE;
}
g_free (seat_id);
return is_on_seat0;
}
static gboolean
get_timed_login_details (GdmManager *manager,
char **usernamep,
int *delayp)
{
gboolean res;
gboolean enabled;
int delay;
diff --git a/daemon/gdm-manager.xml b/daemon/gdm-manager.xml
index f11f3fb73..92ef1d02d 100644
--- a/daemon/gdm-manager.xml
+++ b/daemon/gdm-manager.xml
@@ -1,16 +1,19 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/org/gnome/DisplayManager/Manager">
<interface name="org.gnome.DisplayManager.Manager">
<method name="RegisterDisplay">
<arg name="details" direction="in" type="a{ss}"/>
</method>
+ <method name="RegisterSession">
+ <arg name="details" direction="in" type="a{sv}"/>
+ </method>
<method name="OpenSession">
<arg name="address" direction="out" type="s"/>
</method>
<method name="OpenReauthenticationChannel">
<arg name="username" direction="in" type="s"/>
<arg name="address" direction="out" type="s"/>
</method>
<property name="Version" type="s" access="read"/>
</interface>
</node>
--
2.28.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,173 @@
From f6a8a36717afc7ce00bdb2305a6219c28abc36fb Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 1 Sep 2020 13:49:27 -0400
Subject: [PATCH 51/51] display: Handle failure before display registration
Normally, e.g., gdm-wayland-session would register its display
before starting the session. This display registration is how
the display moves to the "managed" state. We currently detect
session failure in gdm_display_unmanage. If gdm-wayland-session
is killed before it registers the display, gdm_display_unmanage
won't run, and failure won't be detected.
This commit make gdm_display_unmanage get called, even if the
display isn't yet fully managed.
---
daemon/gdm-display.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c
index ae20491cd..b8ccbbd72 100644
--- a/daemon/gdm-display.c
+++ b/daemon/gdm-display.c
@@ -575,80 +575,79 @@ gdm_display_disconnect (GdmDisplay *self)
return;
}
setup = xcb_get_setup (self->priv->xcb_connection);
/* resource_id_mask is the bits given to each client for
* addressing resources */
highest_client = (XID) ~unused_bits & ~setup->resource_id_mask;
client_increment = setup->resource_id_mask + 1;
/* Kill every client but ourselves, then close our own connection
*/
for (client = 0;
client <= highest_client;
client += client_increment) {
if (client != setup->resource_id_base)
xcb_kill_client (self->priv->xcb_connection, client);
}
xcb_flush (self->priv->xcb_connection);
g_clear_pointer (&self->priv->xcb_connection, xcb_disconnect);
}
gboolean
gdm_display_unmanage (GdmDisplay *self)
{
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
- g_debug ("GdmDisplay: unmanage display");
-
gdm_display_disconnect (self);
if (self->priv->user_access_file != NULL) {
gdm_display_access_file_close (self->priv->user_access_file);
g_object_unref (self->priv->user_access_file);
self->priv->user_access_file = NULL;
}
if (self->priv->access_file != NULL) {
gdm_display_access_file_close (self->priv->access_file);
g_object_unref (self->priv->access_file);
self->priv->access_file = NULL;
}
if (!self->priv->session_registered) {
g_warning ("GdmDisplay: Session never registered, failing");
_gdm_display_set_status (self, GDM_DISPLAY_FAILED);
} else {
+ g_debug ("GdmDisplay: Unmanage display");
_gdm_display_set_status (self, GDM_DISPLAY_UNMANAGED);
}
return TRUE;
}
gboolean
gdm_display_get_id (GdmDisplay *self,
char **id,
GError **error)
{
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
if (id != NULL) {
*id = g_strdup (self->priv->id);
}
return TRUE;
}
gboolean
gdm_display_get_x11_display_name (GdmDisplay *self,
char **x11_display,
GError **error)
{
g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
if (x11_display != NULL) {
*x11_display = g_strdup (self->priv->x11_display_name);
}
@@ -1309,63 +1308,62 @@ gdm_display_finalize (GObject *object)
GDBusObjectSkeleton *
gdm_display_get_object_skeleton (GdmDisplay *self)
{
return self->priv->object_skeleton;
}
static void
on_launch_environment_session_opened (GdmLaunchEnvironment *launch_environment,
GdmDisplay *self)
{
char *session_id;
g_debug ("GdmDisplay: Greeter session opened");
session_id = gdm_launch_environment_get_session_id (launch_environment);
_gdm_display_set_session_id (self, session_id);
g_free (session_id);
}
static void
on_launch_environment_session_started (GdmLaunchEnvironment *launch_environment,
GdmDisplay *self)
{
g_debug ("GdmDisplay: Greeter started");
}
static void
self_destruct (GdmDisplay *self)
{
g_object_ref (self);
- if (gdm_display_get_status (self) == GDM_DISPLAY_MANAGED) {
- gdm_display_unmanage (self);
- }
+ g_debug ("GdmDisplay: initiating display self-destruct");
+ gdm_display_unmanage (self);
if (gdm_display_get_status (self) != GDM_DISPLAY_FINISHED) {
queue_finish (self);
}
g_object_unref (self);
}
static void
on_launch_environment_session_stopped (GdmLaunchEnvironment *launch_environment,
GdmDisplay *self)
{
g_debug ("GdmDisplay: Greeter stopped");
self_destruct (self);
}
static void
on_launch_environment_session_exited (GdmLaunchEnvironment *launch_environment,
int code,
GdmDisplay *self)
{
g_debug ("GdmDisplay: Greeter exited: %d", code);
self_destruct (self);
}
static void
on_launch_environment_session_died (GdmLaunchEnvironment *launch_environment,
int signal,
GdmDisplay *self)
{
g_debug ("GdmDisplay: Greeter died: %d", signal);
--
2.27.0

View File

@ -10,7 +10,7 @@
Name: gdm
Epoch: 1
Version: 3.28.3
Release: 29%{?dist}
Release: 39%{?dist}
Summary: The GNOME Display Manager
License: GPLv2+
@ -30,8 +30,6 @@ Patch30004: 0001-data-only-disable-wayland-on-passthrough-virt-setups.patch
Patch40001: 0001-local-display-factory-pause-for-a-few-seconds-before.patch
Patch50001: 0001-manager-ensure-is-initial-is-transfered-to-autologin.patch
Patch60001: 0001-session-ensure-login-screen-over-XDMCP-connects-to-i.patch
Patch70001: 0001-worker-don-t-load-user-settings-for-program-sessions.patch
@ -57,7 +55,72 @@ Patch110001: 0001-display-ask-accountservice-if-there-are-users-rather.patch
Patch120001: 0001-daemon-fix-wayland-detection-when-deciding-to-bypass.patch
Patch999999: system-dconf.patch
# This truckload of patches reworks how VT allocation is done, and makes sure
# the login screen is killed after login
# https://bugzilla.redhat.com/show_bug.cgi?id=1618481
Patch200001: 0001-display-factory-avoid-removing-a-display-from-store-.patch
Patch200002: 0002-local-display-factory-Add-gdm_local_display_factory_.patch
Patch200003: 0003-local-display-factory-Use-correct-session-type-for-n.patch
Patch200004: 0004-manager-make-get_login_window_session_id-fail-if-no-.patch
Patch200005: 0005-manager-avoid-leaking-session_id.patch
Patch200006: 0006-manager-gracefully-handle-the-case-of-no-session-for.patch
Patch200007: 0007-common-dedupe-gdm_get_login_window_session_id.patch
Patch200008: 0008-common-dedupe-activate_session_id.patch
Patch200009: 0009-manager-plug-leak-in-maybe_activate_other_session.patch
Patch200010: 0010-manager-start-login-screen-if-old-one-is-finished.patch
Patch200011: 0011-manager-don-t-bail-if-session-disappears-out-from-un.patch
Patch200012: 0012-daemon-try-harder-to-get-to-a-login-screen-at-logout.patch
Patch200013: 0013-local-display-factory-ensure-non-seat0-codepath-does.patch
Patch200014: 0014-daemon-kill-and-restart-greeter-on-demand-under-wayl.patch
Patch200015: 0015-local-display-factory-add-more-debug-messages-to-new.patch
Patch200016: 0016-local-display-factory-don-t-start-two-greeters-at-st.patch
Patch200017: 0017-session-worker-don-t-switch-VTs-if-we-re-already-on-.patch
Patch200018: 0018-session-worker-fix-current-vt-detection-short-circui.patch
Patch200019: 0019-local-display-factory-don-t-jump-to-failed-display.patch
Patch200020: 0020-local-display-factory-add-some-more-debug-statements.patch
Patch200021: 0021-local-display-factory-ignore-spurios-SeatNew-signal-.patch
Patch200022: 0022-common-remove-unnecessary-free.patch
Patch200023: 0023-common-don-t-bail-if-session-disappears-out-from-und.patch
Patch200024: 0024-manager-better-logind-handling.patch
Patch200025: 0025-session-worker-clear-VT-before-jumping-to-it.patch
Patch200026: 0026-manager-don-t-set-ran_once-after-running-initial-set.patch
Patch200027: 0027-manager-start-initial-setup-right-away.patch
Patch200028: 0028-gdm-wayland-session-gdm-x-session-register-after-del.patch
Patch200029: 0029-local-display-factory-defer-killing-greeter-until-ne.patch
Patch200030: 0030-daemon-Move-the-waiting-the-session-to-have-taken-ov.patch
Patch200031: 0031-local-display-factory-don-t-autoreap-initial-setup.patch
Patch200032: 0032-manager-rework-how-autologin-is-figured-out.patch
Patch200033: 0033-manager-correct-display-confusion.patch
Patch200034: 0034-manager-don-t-run-autologin-display-on-tty1.patch
Patch200035: 0035-local-display-factory-Remove-initial-VT-is-in-use-ch.patch
Patch200036: 0036-local-display-factory-Remove-same-VT-so-don-t-switch.patch
Patch200037: 0037-local-display-factory-handle-reviving-displays-that-.patch
Patch200038: 0038-manager-don-t-kill-initial-setup-before-starting-use.patch
Patch200039: 0039-manager-do-initial-setup-post-work-in-manager-code.patch
Patch200040: 0040-display-store-make-foreach-ignore-callback-return-va.patch
Patch200041: 0041-xdmcp-display-factory-don-t-return-value-from-foreac.patch
Patch200042: 0042-GdmLocalDisplayFactory-Store-VT-number-not-tty-ident.patch
Patch200043: 0043-gdm-session-worker-Drop-login_vt-assuming-it-is-GDM_.patch
Patch200044: 0044-session-worker-ensure-initial-vt-is-never-picked-for.patch
Patch200045: 0045-local-display-factory-Always-force-login-screen-to-V.patch
Patch200046: 0046-gdm-x-session-tell-x-server-to-not-vt-switch.patch
Patch200047: 0047-local-display-factory-kill-X-on-login-just-like-wayl.patch
Patch200048: 0048-manager-don-t-kill-initial-setup-right-away-with-Xor.patch
Patch200049: 0049-GdmManager-GdmDisplay-Add-RegisterSession-method.patch
Patch200050: 0050-Allow-sessions-to-register-with-GDM.patch
Patch200051: 0051-display-Handle-failure-before-display-registration.patch
# CVE-2020-16125
Patch210001: 0001-display-Exit-with-failure-if-loading-existing-users-.patch
# CVE-2020-27837
Patch220001: 0001-session-worker-Don-t-switch-back-VTs-until-session-i.patch
Patch300001: 0001-manager-Don-t-leak-session-objects.patch
Patch300002: 0002-session-Don-t-leak-remote-greeter-interface.patch
Patch300003: 0003-xdmcp-display-factory-Clear-launch-environment-when-.patch
Patch900001: 0001-data-add-system-dconf-databases-to-gdm-profile.patch
BuildRequires: pam-devel >= 0:%{pam_version}
BuildRequires: desktop-file-utils >= %{desktop_file_utils_version}
@ -116,6 +179,7 @@ Requires: system-logos
Requires: xorg-x11-server-utils
Requires: xorg-x11-xinit
Recommends: xorg-x11-server-Xorg
Conflicts: xorg-x11-server-Xorg < 1.20.8-4
Obsoletes: gdm-libs < 1:3.12.0-3
Provides: gdm-libs%{?_isa} = %{epoch}:%{version}-%{release}
@ -211,6 +275,8 @@ mkdir -p %{buildroot}%{_datadir}/gdm/autostart/LoginWindow
mkdir -p %{buildroot}/run/gdm
mkdir -p %{buildroot}%{_sysconfdir}/dconf/db/gdm.d/locks
rm -f %{buildroot}%{_bindir}/gdm-screenshot
find %{buildroot} -name '*.a' -delete
@ -303,6 +369,8 @@ fi
%dir %{_sysconfdir}/gdm/PreSession
%dir %{_sysconfdir}/gdm/PostSession
%dir %{_sysconfdir}/gdm/PostLogin
%dir %{_sysconfdir}/dconf/db/gdm.d
%dir %{_sysconfdir}/dconf/db/gdm.d/locks
%{_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
@ -357,6 +425,39 @@ fi
%{_libdir}/pkgconfig/gdm-pam-extensions.pc
%changelog
* Wed Jan 27 2021 Ray Strode <rstrode@redhat.com> - 3.28.3-39
- Ensure login screen display server is is killed at log in
- Pull in fixes for two security issues
Resolves: #1918391
* Tue Nov 10 2020 Jonas Ådahl <jadahl@redhat.com> - 3.28.3-38
- Re-add disabling Wayland for server GPUs
Related: #1670273
* Tue Nov 10 2020 Jonas Ådahl <jadahl@redhat.com> - 3.28.3-35
- Stop disabling Wayland for server GPUs
Related: #1670273
* Tue Sep 15 2020 Ray Strode <rstrode@redhat.com> - 3.28.3-34
- Fix file descriptor leak
Resolves: #1877853
* Tue Sep 01 2020 Ray Strode <rstrode@redhat.com> - 3.28.3-33
- Fix problem with Xorg fallback
Resolves: #1868260
* Tue Aug 11 2020 Ray Strode <rstrode@redhat.com> - 3.28.3-32
- Add dconf db to file manifest
Related: #1833158
* Thu Jul 23 2020 Ray Strode <rstrode@redhat.com> - 3.28.3-31
- add back gdm system db to dconf profile
Resolves: #1833158
* Mon Jul 13 2020 Ray Strode <rstrode@redhat.com> - 3.28.3-30
- Make sure login screen is killed during login
Resolves: #1618481
* Wed Feb 05 2020 Ray Strode <rstrode@redhat.com> - 3.28.3-29
- Make GNOME work slightly better in the multiple logins case.
Related: #1710882