diff --git a/SOURCES/0001-daemon-fix-wayland-detection-when-deciding-to-bypass.patch b/SOURCES/0001-daemon-fix-wayland-detection-when-deciding-to-bypass.patch new file mode 100644 index 0000000..c442a45 --- /dev/null +++ b/SOURCES/0001-daemon-fix-wayland-detection-when-deciding-to-bypass.patch @@ -0,0 +1,135 @@ +From b9f38b65417923624bf97a18daf1c2ede5e8651e Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 15 Dec 2019 14:51:44 -0500 +Subject: [PATCH] daemon: fix wayland detection when deciding to bypass + Xsession + +At the moment if there's a session file with the same name in +both /usr/share/xsessions and /usr/share/wayland-sessions, GDM +will think the wayland is getting used when deciding whether or +not to bypass the /etc/gdm/Xsession script, even if wayland is +explicitly being ignored. + +This commit fixes the check. +--- + daemon/gdm-session.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c +index a8263ba11..ecb2b3cac 100644 +--- a/daemon/gdm-session.c ++++ b/daemon/gdm-session.c +@@ -3145,96 +3145,96 @@ gdm_session_get_session_id (GdmSession *self) + return conversation->session_id; + } + + const char * + gdm_session_get_conversation_session_id (GdmSession *self, + const char *service_name) + { + GdmSessionConversation *conversation; + + g_return_val_if_fail (GDM_IS_SESSION (self), NULL); + + conversation = find_conversation_by_name (self, service_name); + + if (conversation == NULL) { + return NULL; + } + + return conversation->session_id; + } + + static char * + get_session_filename (GdmSession *self) + { + return g_strdup_printf ("%s.desktop", get_session_name (self)); + } + + #ifdef ENABLE_WAYLAND_SUPPORT + static gboolean + gdm_session_is_wayland_session (GdmSession *self) + { +- GKeyFile *key_file; ++ g_autoptr (GKeyFile) key_file = NULL; + gboolean is_wayland_session = FALSE; +- char *filename; +- char *full_path = NULL; ++ g_autofree char *filename = NULL; ++ g_autofree char *full_path = NULL; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (GDM_IS_SESSION (self), FALSE); + + filename = get_session_filename (self); + +- key_file = load_key_file_for_file (self, filename, "wayland", &full_path); ++ if (!self->priv->ignore_wayland) { ++ key_file = load_key_file_for_file (self, filename, "wayland", &full_path); + +- if (key_file == NULL) { +- goto out; +- } ++ if (key_file == NULL) { ++ goto out; ++ } + +- if (full_path != NULL && strstr (full_path, "/wayland-sessions/") != NULL) { +- is_wayland_session = TRUE; ++ if (full_path != NULL && strstr (full_path, "/wayland-sessions/") != NULL) { ++ is_wayland_session = TRUE; ++ } + } +- g_debug ("GdmSession: checking if file '%s' is wayland session: %s", filename, is_wayland_session? "yes" : "no"); + + out: +- g_clear_pointer (&key_file, (GDestroyNotify) g_key_file_free); +- g_free (filename); ++ g_debug ("GdmSession: checking if file '%s' is wayland session: %s", filename, is_wayland_session? "yes" : "no"); ++ + return is_wayland_session; + } + #endif + + static void + update_session_type (GdmSession *self) + { + #ifdef ENABLE_WAYLAND_SUPPORT + gboolean is_wayland_session = FALSE; + +- if (!self->priv->ignore_wayland) +- is_wayland_session = gdm_session_is_wayland_session (self); ++ is_wayland_session = gdm_session_is_wayland_session (self); + + if (is_wayland_session) { + set_session_type (self, "wayland"); + } else { + set_session_type (self, NULL); + } + #endif + } + + gboolean + gdm_session_bypasses_xsession (GdmSession *self) + { + GError *error; + GKeyFile *key_file; + gboolean res; + gboolean bypasses_xsession = FALSE; + char *filename = NULL; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (GDM_IS_SESSION (self), FALSE); + + #ifdef ENABLE_WAYLAND_SUPPORT + if (gdm_session_is_wayland_session (self)) { + bypasses_xsession = TRUE; + goto out; + } + #endif + + filename = get_session_filename (self); + +-- +2.18.1 + diff --git a/SOURCES/0001-data-disable-wayland-for-legacy-QXL-VMs.patch b/SOURCES/0001-data-disable-wayland-for-legacy-QXL-VMs.patch deleted file mode 100644 index f55d5f2..0000000 --- a/SOURCES/0001-data-disable-wayland-for-legacy-QXL-VMs.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 84eac5437175efc3804e8a6133c06484d6016b26 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 4 Jan 2019 16:40:07 -0500 -Subject: [PATCH] data: disable wayland for legacy QXL VMs - -There are a number of issues right now with the QXL driver that -prevent it from working well with wayland. - -These days QXL is deprecated in favor of virtio anyway. - -This commit forces Xorg fallback for QXL VMs. ---- - data/61-gdm.rules.in | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/data/61-gdm.rules.in b/data/61-gdm.rules.in -index 26cf9cf51..ec19aa447 100644 ---- a/data/61-gdm.rules.in -+++ b/data/61-gdm.rules.in -@@ -1,5 +1,8 @@ - # disable Wayland on Cirrus chipsets - ATTR{vendor}=="0x1013", ATTR{device}=="0x00b8", ATTR{subsystem_vendor}=="0x1af4", ATTR{subsystem_device}=="0x1100", RUN+="@libexecdir@/gdm-disable-wayland" - -+# disable Wayland on legacy QXL virtual machines -+ATTR{vendor}=="0x1b36", ATTR{device}=="0x0100", RUN+="@libexecdir@/gdm-disable-wayland" -+ - # disable Wayland when using the proprietary nvidia driver - DRIVER=="nvidia", RUN+="@libexecdir@/gdm-disable-wayland" --- -2.17.1 - diff --git a/SOURCES/0001-data-disable-wayland-on-server-chips-and-dual-gpu-se.patch b/SOURCES/0001-data-disable-wayland-on-server-chips-and-dual-gpu-se.patch index 3cd8a00..67f27fd 100644 --- a/SOURCES/0001-data-disable-wayland-on-server-chips-and-dual-gpu-se.patch +++ b/SOURCES/0001-data-disable-wayland-on-server-chips-and-dual-gpu-se.patch @@ -1,4 +1,4 @@ -From 21be64e1ba86bd57a4257a7526c9b4ee430bfdaa Mon Sep 17 00:00:00 2001 +From 13a617e15cca421962be888b5607a9900bbfef51 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 11 Feb 2019 18:14:07 -0500 Subject: [PATCH] data: disable wayland on server chips and dual gpu setups @@ -12,10 +12,10 @@ This commit forces Xorg for those cases. 1 file changed, 18 insertions(+) diff --git a/data/61-gdm.rules.in b/data/61-gdm.rules.in -index ec19aa447..1c308d511 100644 +index 26cf9cf51..e3631740d 100644 --- a/data/61-gdm.rules.in +++ b/data/61-gdm.rules.in -@@ -1,8 +1,26 @@ +@@ -1,5 +1,23 @@ # disable Wayland on Cirrus chipsets ATTR{vendor}=="0x1013", ATTR{device}=="0x00b8", ATTR{subsystem_vendor}=="0x1af4", ATTR{subsystem_device}=="0x1100", RUN+="@libexecdir@/gdm-disable-wayland" @@ -33,9 +33,6 @@ index ec19aa447..1c308d511 100644 +ATTR{vendor}=="0x1a03", ATTR{device}=="0x2010", RUN+="@libexecdir@/gdm-disable-wayland" +ATTR{vendor}=="0x1a03", ATTR{device}=="0x2000", RUN+="@libexecdir@/gdm-disable-wayland" + - # disable Wayland on legacy QXL virtual machines - ATTR{vendor}=="0x1b36", ATTR{device}=="0x0100", RUN+="@libexecdir@/gdm-disable-wayland" - # disable Wayland when using the proprietary nvidia driver DRIVER=="nvidia", RUN+="@libexecdir@/gdm-disable-wayland" + @@ -43,5 +40,5 @@ index ec19aa447..1c308d511 100644 +SUBSYSTEM=="drm", KERNEL=="card[1-9]*", RUN+="@libexecdir@/gdm-disable-wayland" + -- -2.18.1 +2.21.0 diff --git a/SOURCES/0001-data-enable-wayland-on-cirrus.patch b/SOURCES/0001-data-enable-wayland-on-cirrus.patch new file mode 100644 index 0000000..7442200 --- /dev/null +++ b/SOURCES/0001-data-enable-wayland-on-cirrus.patch @@ -0,0 +1,44 @@ +From 7d9b41f1d82589999f8c89ed3bcc4eec6cee4978 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Fri, 6 Dec 2019 13:59:43 -0500 +Subject: [PATCH] data: enable wayland on cirrus + +cirrus in the 5.2 kernel was substantially rewritten and is more wayland +ready. + +This commit reenables wayland on cirrus. +--- + data/61-gdm.rules.in | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/data/61-gdm.rules.in b/data/61-gdm.rules.in +index e3631740d..fc2e3315c 100644 +--- a/data/61-gdm.rules.in ++++ b/data/61-gdm.rules.in +@@ -1,23 +1,20 @@ +-# disable Wayland on Cirrus chipsets +-ATTR{vendor}=="0x1013", ATTR{device}=="0x00b8", ATTR{subsystem_vendor}=="0x1af4", ATTR{subsystem_device}=="0x1100", RUN+="@libexecdir@/gdm-disable-wayland" +- + # disable Wayland on Matrox chipsets + ATTR{vendor}=="0x102b", ATTR{device}=="0x0522", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x102b", ATTR{device}=="0x0524", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x102b", ATTR{device}=="0x0530", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x102b", ATTR{device}=="0x0532", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x102b", ATTR{device}=="0x0533", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x102b", ATTR{device}=="0x0534", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x102b", ATTR{device}=="0x0536", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x102b", ATTR{device}=="0x0538", RUN+="@libexecdir@/gdm-disable-wayland" + + # disable Wayland on aspeed chipsets + ATTR{vendor}=="0x1a03", ATTR{device}=="0x2010", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x1a03", ATTR{device}=="0x2000", RUN+="@libexecdir@/gdm-disable-wayland" + + # disable Wayland when using the proprietary nvidia driver + DRIVER=="nvidia", RUN+="@libexecdir@/gdm-disable-wayland" + + # disable Wayland on hybrid graphics setups for now + SUBSYSTEM=="drm", KERNEL=="card[1-9]*", RUN+="@libexecdir@/gdm-disable-wayland" + +-- +2.21.0 + diff --git a/SOURCES/0001-data-only-disable-wayland-on-passthrough-virt-setups.patch b/SOURCES/0001-data-only-disable-wayland-on-passthrough-virt-setups.patch new file mode 100644 index 0000000..24a222f --- /dev/null +++ b/SOURCES/0001-data-only-disable-wayland-on-passthrough-virt-setups.patch @@ -0,0 +1,55 @@ +From ab9510df0b5f7bc29662804991729c6d6ee38b70 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 12 Dec 2019 16:56:16 -0500 +Subject: [PATCH] data: only disable wayland on passthrough virt setups + +at the moment we disable wayland on all hybrid graphics setups, +but most hybrid graphics setups work fine. + +The case we really care about is passthrough virt. in that case, +wayland is a bad idea because: +1) kernel crashes +2) mutter provides no way to disable one of the cards, and will +always use one as a secondary gpu + +This commit forces xorg in passthrough setups so the user can use +an xorg.conf to turn one of the cards off. +--- + data/61-gdm.rules.in | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/data/61-gdm.rules.in b/data/61-gdm.rules.in +index fc2e3315c..f971224cf 100644 +--- a/data/61-gdm.rules.in ++++ b/data/61-gdm.rules.in +@@ -1,20 +1,25 @@ + # disable Wayland on Matrox chipsets + ATTR{vendor}=="0x102b", ATTR{device}=="0x0522", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x102b", ATTR{device}=="0x0524", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x102b", ATTR{device}=="0x0530", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x102b", ATTR{device}=="0x0532", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x102b", ATTR{device}=="0x0533", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x102b", ATTR{device}=="0x0534", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x102b", ATTR{device}=="0x0536", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x102b", ATTR{device}=="0x0538", RUN+="@libexecdir@/gdm-disable-wayland" + + # disable Wayland on aspeed chipsets + ATTR{vendor}=="0x1a03", ATTR{device}=="0x2010", RUN+="@libexecdir@/gdm-disable-wayland" + ATTR{vendor}=="0x1a03", ATTR{device}=="0x2000", RUN+="@libexecdir@/gdm-disable-wayland" + + # disable Wayland when using the proprietary nvidia driver + DRIVER=="nvidia", RUN+="@libexecdir@/gdm-disable-wayland" + +-# disable Wayland on hybrid graphics setups for now +-SUBSYSTEM=="drm", KERNEL=="card[1-9]*", RUN+="@libexecdir@/gdm-disable-wayland" ++# disable Wayland on passthrough graphics setups for now (assumes passthrough if ++# there is more than one card, and one of the cards is virt: cirrus, bochs, qxl) ++ATTR{vendor}=="0x1013", ATTR{device}=="0x00b8", ATTR{subsystem_vendor}=="0x1af4", ATTR{subsystem_device}=="0x1100", ENV{GDM_HAS_VIRTUAL_GPU}="1" ++ATTR{vendor}=="0x1b36", ATTR{device}=="0x0100", ENV{GDM_HAS_VIRTUAL_GPU}="1" ++ATTR{vendor}=="0x1234", ATTR{device}=="0x1111", ENV{GDM_HAS_VIRTUAL_GPU}="1" ++ ++SUBSYSTEM=="drm", KERNEL=="card[1-9]*", ENV{GDM_HAS_VIRTUAL_GPU}=="1", RUN+="@libexecdir@/gdm-disable-wayland" + +-- +2.21.0 + diff --git a/SOURCES/0001-display-ask-accountservice-if-there-are-users-rather.patch b/SOURCES/0001-display-ask-accountservice-if-there-are-users-rather.patch new file mode 100644 index 0000000..cd35a63 --- /dev/null +++ b/SOURCES/0001-display-ask-accountservice-if-there-are-users-rather.patch @@ -0,0 +1,269 @@ +From 781e865705b0c134271c9ec21655cd5d8ce37fec Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sat, 14 Dec 2019 13:50:53 -0500 +Subject: [PATCH] display: ask accountservice if there are users rather than + enumerate users + +At the moment we ask accountsservice to give us the list of users just +to find out if there is a list of users. + +That's rather inefficient and might be wrong for directory server users +that have never logged in before. + +This commit changes gdm to ask accountsservice the question we really +want to know the answer to; whether or not there are users. +--- + daemon/gdm-display.c | 55 ++++++++++++++++++-------------------------- + 1 file changed, 22 insertions(+), 33 deletions(-) + +diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c +index 878be88da..875534272 100644 +--- a/daemon/gdm-display.c ++++ b/daemon/gdm-display.c +@@ -57,62 +57,60 @@ + 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; + + GdmDBusDisplay *display_skeleton; + GDBusObjectSkeleton *object_skeleton; + +- GDBusProxy *accountsservice_proxy; +- + /* this spawns and controls the greeter session */ + GdmLaunchEnvironment *launch_environment; + + guint is_local : 1; + guint is_initial : 1; + guint allow_timed_login : 1; + guint have_existing_user_accounts : 1; + guint doing_initial_setup : 1; + }; + + 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, +@@ -512,96 +510,88 @@ 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 + look_for_existing_users_sync (GdmDisplay *self) + { +- GError *error = NULL; +- GVariant *call_result; +- GVariant *user_list; +- +- self->priv->accountsservice_proxy = g_dbus_proxy_new_sync (self->priv->connection, +- 0, NULL, +- "org.freedesktop.Accounts", +- "/org/freedesktop/Accounts", +- "org.freedesktop.Accounts", +- NULL, +- &error); +- +- if (!self->priv->accountsservice_proxy) { +- g_warning ("Failed to contact accountsservice: %s", error->message); +- goto out; +- } +- +- call_result = g_dbus_proxy_call_sync (self->priv->accountsservice_proxy, +- "ListCachedUsers", +- NULL, +- 0, ++ 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 (!call_result) { +- g_warning ("Failed to list cached users: %s", error->message); +- goto out; ++ if (result == NULL) { ++ g_warning ("Failed to contact accountsservice: %s", error->message); ++ return; + } + +- g_variant_get (call_result, "(@ao)", &user_list); +- self->priv->have_existing_user_accounts = g_variant_n_children (user_list) > 0; +- g_variant_unref (user_list); +- g_variant_unref (call_result); +-out: +- g_clear_error (&error); ++ 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 " : ""); + } + + 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); + + 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; + +@@ -1332,61 +1322,60 @@ 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 (); + } + + static void + gdm_display_finalize (GObject *object) + { + GdmDisplay *self; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_DISPLAY (object)); + + self = GDM_DISPLAY (object); + + g_return_if_fail (self->priv != NULL); + + g_debug ("GdmDisplay: Finalizing display: %s", self->priv->id); + g_free (self->priv->id); + g_free (self->priv->seat_id); + g_free (self->priv->session_class); + g_free (self->priv->remote_hostname); + g_free (self->priv->x11_display_name); + g_free (self->priv->x11_cookie); + + g_clear_object (&self->priv->display_skeleton); + g_clear_object (&self->priv->object_skeleton); + g_clear_object (&self->priv->connection); +- g_clear_object (&self->priv->accountsservice_proxy); + + if (self->priv->access_file != NULL) { + g_object_unref (self->priv->access_file); + } + + if (self->priv->user_access_file != NULL) { + g_object_unref (self->priv->user_access_file); + } + + if (self->priv->server_timer != NULL) { + g_timer_destroy (self->priv->server_timer); + } + + G_OBJECT_CLASS (gdm_display_parent_class)->finalize (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); +-- +2.21.0 + diff --git a/SOURCES/0001-manager-allow-multiple-xdmcp-logins-for-the-same-use.patch b/SOURCES/0001-manager-allow-multiple-xdmcp-logins-for-the-same-use.patch new file mode 100644 index 0000000..f73fb2c --- /dev/null +++ b/SOURCES/0001-manager-allow-multiple-xdmcp-logins-for-the-same-use.patch @@ -0,0 +1,343 @@ +From 53950976344f38a96a17c1bbb3c093f67b49c493 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Thu, 20 Dec 2018 14:51:38 -0500 +Subject: [PATCH] manager: allow multiple xdmcp logins for the same user + +--- + common/gdm-settings-keys.h | 1 + + daemon/gdm-manager.c | 71 ++++++++++++++++++++++++++++---------- + data/gdm.schemas.in.in | 5 +++ + 3 files changed, 59 insertions(+), 18 deletions(-) + +diff --git a/common/gdm-settings-keys.h b/common/gdm-settings-keys.h +index f0059b5cf..33676a851 100644 +--- a/common/gdm-settings-keys.h ++++ b/common/gdm-settings-keys.h +@@ -28,37 +28,38 @@ G_BEGIN_DECLS + #define GDM_KEY_USER "daemon/User" + #define GDM_KEY_GROUP "daemon/Group" + #define GDM_KEY_AUTO_LOGIN_ENABLE "daemon/AutomaticLoginEnable" + #define GDM_KEY_AUTO_LOGIN_USER "daemon/AutomaticLogin" + #define GDM_KEY_TIMED_LOGIN_ENABLE "daemon/TimedLoginEnable" + #define GDM_KEY_TIMED_LOGIN_USER "daemon/TimedLogin" + #define GDM_KEY_TIMED_LOGIN_DELAY "daemon/TimedLoginDelay" + #define GDM_KEY_INITIAL_SETUP_ENABLE "daemon/InitialSetupEnable" + #define GDM_KEY_WAYLAND_ENABLE "daemon/WaylandEnable" + + #define GDM_KEY_DEBUG "debug/Enable" + + #define GDM_KEY_INCLUDE "greeter/Include" + #define GDM_KEY_EXCLUDE "greeter/Exclude" + #define GDM_KEY_INCLUDE_ALL "greeter/IncludeAll" + + #define GDM_KEY_DISALLOW_TCP "security/DisallowTCP" + #define GDM_KEY_ALLOW_REMOTE_AUTOLOGIN "security/AllowRemoteAutoLogin" + + #define GDM_KEY_XDMCP_ENABLE "xdmcp/Enable" + #define GDM_KEY_SHOW_LOCAL_GREETER "xdmcp/ShowLocalGreeter" + #define GDM_KEY_MAX_PENDING "xdmcp/MaxPending" + #define GDM_KEY_MAX_SESSIONS "xdmcp/MaxSessions" + #define GDM_KEY_MAX_WAIT "xdmcp/MaxWait" + #define GDM_KEY_DISPLAYS_PER_HOST "xdmcp/DisplaysPerHost" + #define GDM_KEY_UDP_PORT "xdmcp/Port" + #define GDM_KEY_INDIRECT "xdmcp/HonorIndirect" + #define GDM_KEY_MAX_WAIT_INDIRECT "xdmcp/MaxWaitIndirect" + #define GDM_KEY_PING_INTERVAL "xdmcp/PingIntervalSeconds" + #define GDM_KEY_WILLING "xdmcp/Willing" ++#define GDM_KEY_ALLOW_MULTIPLE_SESSIONS_PER_USER "xdmcp/AllowMultipleSessionsPerUser" + + #define GDM_KEY_MULTICAST "chooser/Multicast" + #define GDM_KEY_MULTICAST_ADDR "chooser/MulticastAddr" + + G_END_DECLS + + #endif /* _GDM_SETTINGS_KEYS_H */ +diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c +index 056560b20..de7357ad5 100644 +--- a/daemon/gdm-manager.c ++++ b/daemon/gdm-manager.c +@@ -594,93 +594,106 @@ get_display_and_details_for_bus_sender (GdmManager *self, + if (out_tty != NULL) { + *out_tty = get_tty_for_session_id (session_id, &error); + + if (error != NULL) { + g_debug ("GdmManager: Error while retrieving tty for session: %s", + error->message); + g_clear_error (&error); + } + } + + display = gdm_display_store_find (self->priv->display_store, + lookup_by_session_id, + (gpointer) session_id); + + if (out_display != NULL) { + *out_display = display; + } + out: + g_free (session_id); + } + + static gboolean + switch_to_compatible_user_session (GdmManager *manager, + GdmSession *session, + gboolean fail_if_already_switched) + { + gboolean res; + gboolean ret; + const char *username; + const char *seat_id; +- const char *ssid_to_activate; ++ const char *ssid_to_activate = NULL; + GdmSession *existing_session; + + ret = FALSE; + + username = gdm_session_get_username (session); + seat_id = gdm_session_get_display_seat_id (session); + +- if (!fail_if_already_switched) { +- session = NULL; +- } ++ if (!fail_if_already_switched) ++ ssid_to_activate = gdm_session_get_session_id (session); + +- existing_session = find_session_for_user_on_seat (manager, username, seat_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 (existing_session != NULL) { +- ssid_to_activate = gdm_session_get_session_id (existing_session); +- if (seat_id != NULL) { +- res = activate_session_id (manager, seat_id, ssid_to_activate); +- if (! res) { +- g_debug ("GdmManager: unable to activate session: %s", ssid_to_activate); +- goto out; +- } ++ if (!fail_if_already_switched) { ++ session = NULL; + } + +- res = session_unlock (manager, ssid_to_activate); +- if (!res) { +- /* this isn't fatal */ +- g_debug ("GdmManager: unable to unlock session: %s", ssid_to_activate); ++ 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); + } +- } else { ++ } ++ ++ if (ssid_to_activate == NULL) { + goto out; + } + ++ if (seat_id != NULL) { ++ res = activate_session_id (manager, seat_id, ssid_to_activate); ++ if (! res) { ++ g_debug ("GdmManager: unable to activate session: %s", ssid_to_activate); ++ goto out; ++ } ++ } ++ ++ res = session_unlock (manager, ssid_to_activate); ++ if (!res) { ++ /* this isn't fatal */ ++ g_debug ("GdmManager: unable to unlock session: %s", ssid_to_activate); ++ } ++ + 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; + } + + return g_object_get_data (G_OBJECT (display), "gdm-user-session"); + } + + static gboolean + add_session_record (GdmManager *manager, + GdmSession *session, + GPid pid, + SessionRecord record) + { + const char *username; + char *display_name, *hostname, *display_device; +@@ -1088,92 +1101,114 @@ open_temporary_reauthentication_channel (GdmManager *self, + g_signal_connect (session, + "client-disconnected", + G_CALLBACK (on_reauthentication_client_disconnected), + self); + g_signal_connect (session, + "client-rejected", + G_CALLBACK (on_reauthentication_client_rejected), + self); + g_signal_connect (session, + "cancelled", + G_CALLBACK (on_reauthentication_cancelled), + self); + g_signal_connect (session, + "conversation-started", + G_CALLBACK (on_reauthentication_conversation_started), + self); + g_signal_connect (session, + "conversation-stopped", + G_CALLBACK (on_reauthentication_conversation_stopped), + self); + g_signal_connect (session, + "verification-complete", + G_CALLBACK (on_reauthentication_verification_complete), + self); + + address = gdm_session_get_server_address (session); + + return g_strdup (address); + } + ++static gboolean ++remote_users_can_log_in_more_than_once (GdmManager *manager) ++{ ++ gboolean enabled; ++ ++ enabled = FALSE; ++ ++ gdm_settings_direct_get_boolean (GDM_KEY_ALLOW_MULTIPLE_SESSIONS_PER_USER, &enabled); ++ ++ g_debug ("GdmDisplay: Remote users allowed to log in more than once: %s", enabled? "yes" : "no"); ++ ++ return enabled; ++} ++ + static gboolean + gdm_manager_handle_open_reauthentication_channel (GdmDBusManager *manager, + GDBusMethodInvocation *invocation, + const char *username) + { + GdmManager *self = GDM_MANAGER (manager); + const char *sender; + GdmDisplay *display = NULL; + GdmSession *session; + GDBusConnection *connection; + char *seat_id = NULL; + char *session_id = NULL; + GPid pid = 0; + uid_t uid = (uid_t) -1; + gboolean is_login_screen = FALSE; + gboolean is_remote = FALSE; + + g_debug ("GdmManager: trying to open reauthentication channel for user %s", username); + + sender = g_dbus_method_invocation_get_sender (invocation); + connection = g_dbus_method_invocation_get_connection (invocation); + get_display_and_details_for_bus_sender (self, connection, sender, &display, &seat_id, &session_id, NULL, &pid, &uid, &is_login_screen, &is_remote); + + if (session_id == NULL || pid == 0 || uid == (uid_t) -1) { + g_dbus_method_invocation_return_error_literal (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + _("No session available")); + + return TRUE; + } + ++ if (is_login_screen && is_remote && remote_users_can_log_in_more_than_once (self)) { ++ g_dbus_method_invocation_return_error_literal (invocation, ++ G_DBUS_ERROR, ++ G_DBUS_ERROR_ACCESS_DENIED, ++ "Login screen creates new sessions for remote connections"); ++ return TRUE; ++ } ++ + if (is_login_screen) { + g_debug ("GdmManager: looking for login screen session for user %s on seat %s", username, seat_id); + session = find_session_for_user_on_seat (self, + username, + seat_id, + NULL); + } else { + g_debug ("GdmManager: looking for user session on display"); + session = get_user_session_for_display (display); + } + + if (session != NULL && gdm_session_is_running (session)) { + gdm_session_start_reauthentication (session, pid, uid); + g_hash_table_insert (self->priv->open_reauthentication_requests, + GINT_TO_POINTER (pid), + invocation); + } else 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); +diff --git a/data/gdm.schemas.in.in b/data/gdm.schemas.in.in +index 8ad203101..003f92c63 100644 +--- a/data/gdm.schemas.in.in ++++ b/data/gdm.schemas.in.in +@@ -102,32 +102,37 @@ + + xdmcp/DisplaysPerHost + i + 1 + + + xdmcp/Port + i + 177 + + + xdmcp/HonorIndirect + b + true + + + xdmcp/MaxWaitIndirect + i + 30 + + + xdmcp/PingIntervalSeconds + i + 0 + + + xdmcp/Willing + s + @gdmconfdir@/Xwilling + ++ ++ xdmcp/AllowMultipleSessionsPerUser ++ b ++ false ++ + + +-- +2.21.0 + diff --git a/SOURCES/0001-manager-don-t-kill-timed-login-session-immediately-a.patch b/SOURCES/0001-manager-don-t-kill-timed-login-session-immediately-a.patch new file mode 100644 index 0000000..6a4f22b --- /dev/null +++ b/SOURCES/0001-manager-don-t-kill-timed-login-session-immediately-a.patch @@ -0,0 +1,87 @@ +From ecd37ba6d56a49dd896613f68d1e1754633b9f0c Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Wed, 6 Feb 2019 16:14:52 -0500 +Subject: [PATCH 1/4] manager: don't kill timed login session immediately after + it starts + +At the moment GDM is misidentifying timed login sessions as if +they are automatic login sessions. That leads to their displays +getting killed sometimes shortly after log in. + +This commit corrects the check, so that timed login sessions aren't +treated as autologin sessions. +--- + daemon/gdm-manager.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c +index 2118c5834..b2d0578f5 100644 +--- a/daemon/gdm-manager.c ++++ b/daemon/gdm-manager.c +@@ -1841,61 +1841,62 @@ on_start_user_session (StartUserSessionOperation *operation) + 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) { ++ 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); + } + + 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, +-- +2.21.0 + diff --git a/SOURCES/0001-session-worker-expose-worker-state-enum-to-type-syst.patch b/SOURCES/0001-session-worker-expose-worker-state-enum-to-type-syst.patch new file mode 100644 index 0000000..3de78e9 --- /dev/null +++ b/SOURCES/0001-session-worker-expose-worker-state-enum-to-type-syst.patch @@ -0,0 +1,470 @@ +From 521ff70fe447558461dd38cdec62a7c0a5a74f7a Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Mon, 24 Jun 2019 14:48:23 -0400 +Subject: [PATCH 1/3] session-worker: expose worker state enum to type system + +We're going to need to access the worker state as a property on +the worker object. + +This commit hooks it up to glib-mkenums so the requisite goo can +get generated +--- + daemon/Makefile.am | 8 +++++ + daemon/gdm-session-worker-enum-types.c.in | 42 +++++++++++++++++++++++ + daemon/gdm-session-worker-enum-types.h.in | 24 +++++++++++++ + daemon/gdm-session-worker.c | 16 +++------ + daemon/gdm-session-worker.h | 12 +++++++ + 5 files changed, 90 insertions(+), 12 deletions(-) + create mode 100644 daemon/gdm-session-worker-enum-types.c.in + create mode 100644 daemon/gdm-session-worker-enum-types.h.in + +diff --git a/daemon/Makefile.am b/daemon/Makefile.am +index b77c9276e..86a8ee32f 100644 +--- a/daemon/Makefile.am ++++ b/daemon/Makefile.am +@@ -14,69 +14,76 @@ AM_CPPFLAGS = \ + -DLIBEXECDIR=\"$(libexecdir)\" \ + -DLOCALSTATEDIR=\"$(localstatedir)\" \ + -DLOGDIR=\"$(logdir)\" \ + -DSBINDIR=\"$(sbindir)\" \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ + -DGDM_RUN_DIR=\"$(GDM_RUN_DIR)\" \ + -DGDM_XAUTH_DIR=\"$(GDM_XAUTH_DIR)\" \ + -DGDM_SCREENSHOT_DIR=\"$(GDM_SCREENSHOT_DIR)\" \ + -DGDM_CACHE_DIR=\""$(localstatedir)/cache/gdm"\" \ + -DGDM_SESSION_DEFAULT_PATH=\"$(GDM_SESSION_DEFAULT_PATH)\" \ + $(DISABLE_DEPRECATED_CFLAGS) \ + $(DAEMON_CFLAGS) \ + $(XLIB_CFLAGS) \ + $(WARN_CFLAGS) \ + $(DEBUG_CFLAGS) \ + $(SYSTEMD_CFLAGS) \ + $(JOURNALD_CFLAGS) \ + $(LIBSELINUX_CFLAGS) \ + -DLANG_CONFIG_FILE=\"$(LANG_CONFIG_FILE)\" \ + $(NULL) + + BUILT_SOURCES = \ + gdm-display-glue.h \ + gdm-manager-glue.h \ + gdm-local-display-glue.h \ + gdm-local-display-factory-glue.h \ + gdm-session-glue.h \ + gdm-session-worker-glue.h \ + gdm-session-enum-types.h \ ++ gdm-session-worker-enum-types.h \ + 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-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 \ +@@ -128,60 +135,61 @@ 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-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) + + gdm_x_session_SOURCES = \ + gdm-manager-glue.h \ + gdm-manager-glue.c \ + gdm-x-session.c \ + $(NULL) + +diff --git a/daemon/gdm-session-worker-enum-types.c.in b/daemon/gdm-session-worker-enum-types.c.in +new file mode 100644 +index 000000000..c02869076 +--- /dev/null ++++ b/daemon/gdm-session-worker-enum-types.c.in +@@ -0,0 +1,42 @@ ++/*** BEGIN file-header ***/ ++ ++#include ++ ++/*** END file-header ***/ ++ ++/*** BEGIN file-production ***/ ++#include "@filename@" ++/* enumerations from "@filename@" */ ++/*** END file-production ***/ ++ ++/*** BEGIN value-header ***/ ++GType @enum_name@_get_type (void) G_GNUC_CONST; ++ ++GType ++@enum_name@_get_type (void) ++{ ++ static GType etype = 0; ++ ++ if (G_UNLIKELY(etype == 0)) { ++ static const G@Type@Value values[] = { ++/*** END value-header ***/ ++ ++/*** BEGIN value-production ***/ ++ { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, ++/*** END value-production ***/ ++ ++/*** BEGIN value-tail ***/ ++ { 0, NULL, NULL } ++ }; ++ ++ etype = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); ++ } ++ ++ return etype; ++} ++ ++/*** END value-tail ***/ ++ ++/*** BEGIN file-tail ***/ ++ /**/ ++/*** END file-tail ***/ +diff --git a/daemon/gdm-session-worker-enum-types.h.in b/daemon/gdm-session-worker-enum-types.h.in +new file mode 100644 +index 000000000..64f4b4bb6 +--- /dev/null ++++ b/daemon/gdm-session-worker-enum-types.h.in +@@ -0,0 +1,24 @@ ++/*** BEGIN file-header ***/ ++#ifndef GDM_SESSION_WORKER_ENUM_TYPES_H ++#define GDM_SESSION_WORKER_ENUM_TYPES_H ++ ++#include ++ ++G_BEGIN_DECLS ++/*** END file-header ***/ ++ ++/*** BEGIN file-production ***/ ++ ++/* enumerations from "@filename@" */ ++/*** END file-production ***/ ++ ++/*** BEGIN value-header ***/ ++GType @enum_name@_get_type (void) G_GNUC_CONST; ++#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) ++/*** END value-header ***/ ++ ++/*** BEGIN file-tail ***/ ++G_END_DECLS ++ ++#endif /* GDM_SESSION_WORKER_ENUM_TYPES_H */ ++/*** END file-tail ***/ +diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c +index ae86d28ac..f6935ab1d 100644 +--- a/daemon/gdm-session-worker.c ++++ b/daemon/gdm-session-worker.c +@@ -83,83 +83,72 @@ + #define GDM_SESSION_WORKER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SESSION_WORKER, GdmSessionWorkerPrivate)) + + #define GDM_SESSION_DBUS_PATH "/org/gnome/DisplayManager/Session" + #define GDM_SESSION_DBUS_NAME "org.gnome.DisplayManager.Session" + #define GDM_SESSION_DBUS_ERROR_CANCEL "org.gnome.DisplayManager.Session.Error.Cancel" + + #define GDM_WORKER_DBUS_PATH "/org/gnome/DisplayManager/Worker" + + #ifndef GDM_PASSWD_AUXILLARY_BUFFER_SIZE + #define GDM_PASSWD_AUXILLARY_BUFFER_SIZE 1024 + #endif + + #ifndef GDM_SESSION_DEFAULT_PATH + #define GDM_SESSION_DEFAULT_PATH "/usr/local/bin:/usr/bin:/bin" + #endif + + #ifndef GDM_SESSION_ROOT_UID + #define GDM_SESSION_ROOT_UID 0 + #endif + + #ifndef GDM_SESSION_LOG_FILENAME + #define GDM_SESSION_LOG_FILENAME "session.log" + #endif + + #define MAX_FILE_SIZE 65536 + #define MAX_LOGS 5 + + #define RELEASE_DISPLAY_SIGNAL (SIGRTMAX) + #define ACQUIRE_DISPLAY_SIGNAL (SIGRTMAX - 1) + +-enum { +- GDM_SESSION_WORKER_STATE_NONE = 0, +- GDM_SESSION_WORKER_STATE_SETUP_COMPLETE, +- GDM_SESSION_WORKER_STATE_AUTHENTICATED, +- GDM_SESSION_WORKER_STATE_AUTHORIZED, +- GDM_SESSION_WORKER_STATE_ACCREDITED, +- GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED, +- GDM_SESSION_WORKER_STATE_SESSION_OPENED, +- GDM_SESSION_WORKER_STATE_SESSION_STARTED +-}; +- + typedef struct + { + GdmSessionWorker *worker; + GdmSession *session; + GPid pid_of_caller; + uid_t uid_of_caller; + + } ReauthenticationRequest; + + struct GdmSessionWorkerPrivate + { +- int state; ++ GdmSessionWorkerState state; + + int exit_code; + + pam_handle_t *pam_handle; + + GPid child_pid; + guint child_watch_id; + + /* from Setup */ + char *service; + char *x11_display_name; + char *x11_authority_file; + char *display_device; + char *display_seat_id; + char *hostname; + char *username; + char *log_file; + char *session_id; + uid_t uid; + gid_t gid; + gboolean password_is_required; + char **extensions; + + int cred_flags; + int login_vt; + int session_vt; + int session_tty_fd; + + char **arguments; + guint32 cancelled : 1; +@@ -2455,60 +2444,63 @@ gdm_session_worker_set_property (GObject *object, + switch (prop_id) { + case PROP_SERVER_ADDRESS: + gdm_session_worker_set_server_address (self, g_value_get_string (value)); + break; + case PROP_IS_REAUTH_SESSION: + gdm_session_worker_set_is_reauth_session (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } + + static void + gdm_session_worker_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) + { + GdmSessionWorker *self; + + self = GDM_SESSION_WORKER (object); + + switch (prop_id) { + case PROP_SERVER_ADDRESS: + g_value_set_string (value, self->priv->server_address); + break; + case PROP_IS_REAUTH_SESSION: + g_value_set_boolean (value, self->priv->is_reauth_session); + break; ++ case PROP_STATE: ++ g_value_set_int (value, self->priv->state); ++ break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } + + static gboolean + gdm_session_worker_handle_set_environment_variable (GdmDBusWorker *object, + GDBusMethodInvocation *invocation, + const char *key, + const char *value) + { + GdmSessionWorker *worker = GDM_SESSION_WORKER (object); + gdm_session_worker_set_environment_variable (worker, key, value); + gdm_dbus_worker_complete_set_environment_variable (object, invocation); + return TRUE; + } + + static gboolean + gdm_session_worker_handle_set_session_name (GdmDBusWorker *object, + GDBusMethodInvocation *invocation, + const char *session_name) + { + GdmSessionWorker *worker = GDM_SESSION_WORKER (object); + g_debug ("GdmSessionWorker: session name set to %s", session_name); + if (worker->priv->user_settings != NULL) + gdm_session_settings_set_session_name (worker->priv->user_settings, + session_name); + gdm_dbus_worker_complete_set_session_name (object, invocation); + return TRUE; +diff --git a/daemon/gdm-session-worker.h b/daemon/gdm-session-worker.h +index 5603e80e0..2814eab4d 100644 +--- a/daemon/gdm-session-worker.h ++++ b/daemon/gdm-session-worker.h +@@ -1,56 +1,68 @@ + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2006 Ray Strode + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + #ifndef __GDM_SESSION_WORKER_H + #define __GDM_SESSION_WORKER_H + + #include + + #include "gdm-session-worker-glue.h" + #include "gdm-session-worker-common.h" ++#include "gdm-session-worker-enum-types.h" + + G_BEGIN_DECLS + + #define GDM_TYPE_SESSION_WORKER (gdm_session_worker_get_type ()) + #define GDM_SESSION_WORKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDM_TYPE_SESSION_WORKER, GdmSessionWorker)) + #define GDM_SESSION_WORKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_SESSION_WORKER, GdmSessionWorkerClass)) + #define GDM_IS_SESSION_WORKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDM_TYPE_SESSION_WORKER)) + #define GDM_IS_SESSION_WORKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_SESSION_WORKER)) + #define GDM_SESSION_WORKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_SESSION_WORKER, GdmSessionWorkerClass)) + ++typedef enum { ++ GDM_SESSION_WORKER_STATE_NONE = 0, ++ GDM_SESSION_WORKER_STATE_SETUP_COMPLETE, ++ GDM_SESSION_WORKER_STATE_AUTHENTICATED, ++ GDM_SESSION_WORKER_STATE_AUTHORIZED, ++ GDM_SESSION_WORKER_STATE_ACCREDITED, ++ GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED, ++ GDM_SESSION_WORKER_STATE_SESSION_OPENED, ++ GDM_SESSION_WORKER_STATE_SESSION_STARTED ++} GdmSessionWorkerState; ++ + typedef struct GdmSessionWorkerPrivate GdmSessionWorkerPrivate; + + typedef struct + { + GdmDBusWorkerSkeleton parent; + GdmSessionWorkerPrivate *priv; + } GdmSessionWorker; + + typedef struct + { + GdmDBusWorkerSkeletonClass parent_class; + } GdmSessionWorkerClass; + + GType gdm_session_worker_get_type (void); + + GdmSessionWorker * gdm_session_worker_new (const char *server_address, + gboolean is_for_reauth) G_GNUC_MALLOC; + G_END_DECLS + #endif /* GDM_SESSION_WORKER_H */ +-- +2.18.1 + diff --git a/SOURCES/0002-manager-session-Add-some-debugging-around-starting-r.patch b/SOURCES/0002-manager-session-Add-some-debugging-around-starting-r.patch new file mode 100644 index 0000000..bb217a4 --- /dev/null +++ b/SOURCES/0002-manager-session-Add-some-debugging-around-starting-r.patch @@ -0,0 +1,1015 @@ +From d3b60b5211d804e23c663d053c5b511dede22a28 Mon Sep 17 00:00:00 2001 +From: Iain Lane +Date: Thu, 31 Jan 2019 10:52:35 +0000 +Subject: [PATCH 2/4] manager,session: Add some debugging around starting + reauthentication + +There's a bug right now dealing with timed login and reauthentication, +but it's not clear what's going on by looking at the logs. + +This commit sprinkles some more logging throughout the code, to make +the bug easier to track. +--- + daemon/gdm-manager.c | 46 ++++++++++++++++++++++++++++++++++++++------ + daemon/gdm-session.c | 25 ++++++++++++++++++++---- + 2 files changed, 61 insertions(+), 10 deletions(-) + +diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c +index b2d0578f5..0cc06a978 100644 +--- a/daemon/gdm-manager.c ++++ b/daemon/gdm-manager.c +@@ -340,77 +340,94 @@ session_unlock (GdmManager *manager, + "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; + } + + static GdmSession * + find_session_for_user_on_seat (GdmManager *manager, + const char *username, + const char *seat_id, + GdmSession *dont_count_session) + { + GList *node; + + for (node = manager->priv->user_sessions; node != NULL; node = node->next) { + GdmSession *candidate_session = node->data; +- const char *candidate_username, *candidate_seat_id; ++ const char *candidate_username, *candidate_seat_id, *candidate_session_id; + +- if (candidate_session == dont_count_session) ++ candidate_session_id = gdm_session_get_session_id (candidate_session); ++ ++ if (candidate_session == dont_count_session) { ++ g_debug ("GdmSession: Ignoring session %s as requested", ++ candidate_session_id); + continue; ++ } + +- if (!gdm_session_is_running (candidate_session)) ++ if (!gdm_session_is_running (candidate_session)) { ++ g_debug ("GdmSession: Ignoring session %s as it isn't running", ++ candidate_session_id); + continue; ++ } + + candidate_username = gdm_session_get_username (candidate_session); + candidate_seat_id = gdm_session_get_display_seat_id (candidate_session); + ++ g_debug ("GdmManager: Considering session %s on seat %s belonging to user %s", ++ candidate_session_id, ++ candidate_seat_id, ++ 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) { + 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; + } + +@@ -840,62 +857,66 @@ gdm_manager_handle_open_session (GdmDBusManager *manager, + 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 + if (GDM_IS_XDMCP_CHOOSER_DISPLAY (display)) { + GdmLaunchEnvironment *launch_environment; + + g_object_get (display, "launch-environment", &launch_environment, NULL); + + if (launch_environment != NULL) { + session = gdm_launch_environment_get_session (launch_environment); + } + + if (session == NULL) { + g_dbus_method_invocation_return_error_literal (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + _("Chooser session unavailable")); + return TRUE; + } + } + #endif + if (session == NULL) { + session = get_user_session_for_display (display); ++ g_debug ("GdmSession: Considering session %s for username %s", ++ gdm_session_get_session_id (session), ++ gdm_session_get_username (session)); + + if (gdm_session_is_running (session)) { ++ g_debug ("GdmSession: the session is running, and therefore can't be used"); + g_dbus_method_invocation_return_error_literal (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + _("Can only be called before user is logged in")); + return TRUE; + } + } + + allowed_user = gdm_session_get_allowed_user (session); + + if (uid != allowed_user) { + g_dbus_method_invocation_return_error_literal (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + _("Caller not GDM")); + return TRUE; + } + + address = gdm_session_get_server_address (session); + + if (address == NULL) { + g_dbus_method_invocation_return_error_literal (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + _("Unable to open private communication channel")); + return TRUE; + } + + gdm_dbus_manager_complete_open_session (GDM_DBUS_MANAGER (manager), + invocation, +@@ -1017,60 +1038,64 @@ open_temporary_reauthentication_channel (GdmManager *self, + char *seat_id, + char *session_id, + GPid pid, + uid_t uid, + gboolean is_remote) + { + GdmSession *session; + char **environment; + const char *display, *auth_file; + const char *address; + + /* Note we're just using a minimal environment here rather than the + * session's environment because the caller is unprivileged and the + * associated worker will be privileged */ + environment = g_get_environ (); + display = ""; + auth_file = "/dev/null"; + + session = gdm_session_new (GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE, + uid, + display, + NULL, + NULL, + seat_id, + auth_file, + is_remote == FALSE, + (const char * const *) + environment); + g_strfreev (environment); + ++ g_debug ("GdmSession: Created session for temporary reauthentication channel for user %d (seat %s)", ++ (int) uid, ++ seat_id); ++ + g_object_set_data_full (G_OBJECT (session), + "caller-session-id", + g_strdup (session_id), + (GDestroyNotify) + g_free); + g_object_set_data (G_OBJECT (session), + "caller-pid", + GUINT_TO_POINTER (pid)); + g_hash_table_insert (self->priv->transient_sessions, + GINT_TO_POINTER (pid), + session); + + g_signal_connect (session, + "client-connected", + G_CALLBACK (on_reauthentication_client_connected), + self); + g_signal_connect (session, + "client-disconnected", + G_CALLBACK (on_reauthentication_client_disconnected), + self); + g_signal_connect (session, + "client-rejected", + G_CALLBACK (on_reauthentication_client_rejected), + self); + g_signal_connect (session, + "cancelled", + G_CALLBACK (on_reauthentication_cancelled), + self); + g_signal_connect (session, + "conversation-started", +@@ -1096,65 +1121,67 @@ gdm_manager_handle_open_reauthentication_channel (GdmDBusManager *manager + const char *username) + { + GdmManager *self = GDM_MANAGER (manager); + const char *sender; + GdmDisplay *display = NULL; + GdmSession *session; + GDBusConnection *connection; + char *seat_id = NULL; + char *session_id = NULL; + GPid pid = 0; + uid_t uid = (uid_t) -1; + gboolean is_login_screen = FALSE; + gboolean is_remote = FALSE; + + g_debug ("GdmManager: trying to open reauthentication channel for user %s", username); + + sender = g_dbus_method_invocation_get_sender (invocation); + connection = g_dbus_method_invocation_get_connection (invocation); + get_display_and_details_for_bus_sender (self, connection, sender, &display, &seat_id, &session_id, NULL, &pid, &uid, &is_login_screen, &is_remote); + + if (session_id == NULL || pid == 0 || uid == (uid_t) -1) { + g_dbus_method_invocation_return_error_literal (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + _("No session available")); + + return TRUE; + } + + if (is_login_screen) { ++ g_debug ("GdmManager: looking for login screen session for user %s on seat %s", username, seat_id); + session = find_session_for_user_on_seat (self, + username, + seat_id, + NULL); + } else { ++ g_debug ("GdmManager: looking for user session on display"); + session = get_user_session_for_display (display); + } + + if (session != NULL && gdm_session_is_running (session)) { + gdm_session_start_reauthentication (session, pid, uid); + g_hash_table_insert (self->priv->open_reauthentication_requests, + GINT_TO_POINTER (pid), + invocation); + } else 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; + } +@@ -2087,107 +2114,107 @@ on_session_client_ready_for_session_to_start (GdmSession *session, + if (client_is_ready) { + g_debug ("GdmManager: Will start session when ready"); + } else { + g_debug ("GdmManager: Will start session when ready and told"); + } + + waiting_to_start_user_session = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (session), + "waiting-to-start")); + + g_object_set_data (G_OBJECT (session), + "start-when-ready", + GINT_TO_POINTER (client_is_ready)); + + if (client_is_ready && waiting_to_start_user_session) { + start_user_session_if_ready (manager, session, service_name); + } + } + + static void + on_session_client_connected (GdmSession *session, + GCredentials *credentials, + GPid pid_of_client, + GdmManager *manager) + { + GdmDisplay *display; + char *username; + int delay; + gboolean enabled; + gboolean allow_timed_login = FALSE; + +- g_debug ("GdmManager: client connected"); ++ g_debug ("GdmManager: client with pid %d connected", (int) pid_of_client); + + display = get_display_for_user_session (session); + + if (display == NULL) { + return; + } + + if (!display_is_on_seat0 (display)) { + return; + } + + #ifdef WITH_PLYMOUTH + if (manager->priv->plymouth_is_running) { + plymouth_quit_with_transition (); + manager->priv->plymouth_is_running = FALSE; + } + #endif + + g_object_get (G_OBJECT (display), "allow-timed-login", &allow_timed_login, NULL); + + if (!allow_timed_login) { + return; + } + + enabled = get_timed_login_details (manager, &username, &delay); + + if (! enabled) { + return; + } + + gdm_session_set_timed_login_details (session, username, delay); + + g_debug ("GdmManager: Starting automatic login conversation (for timed login)"); + gdm_session_start_conversation (session, "gdm-autologin"); + + g_free (username); + + } + + static void + on_session_client_disconnected (GdmSession *session, + GCredentials *credentials, + GPid pid_of_client, + GdmManager *manager) + { +- g_debug ("GdmManager: client disconnected"); ++ g_debug ("GdmManager: client with pid %d disconnected", (int) pid_of_client); + } + + typedef struct + { + GdmManager *manager; + GdmSession *session; + guint idle_id; + } ResetSessionOperation; + + static void + destroy_reset_session_operation (ResetSessionOperation *operation) + { + g_object_set_data (G_OBJECT (operation->session), + "reset-session-operation", + NULL); + g_object_unref (operation->session); + g_slice_free (ResetSessionOperation, operation); + } + + static gboolean + on_reset_session (ResetSessionOperation *operation) + { + gdm_session_reset (operation->session); + + destroy_reset_session_operation (operation); + + return G_SOURCE_REMOVE; + } + + static void +@@ -2200,63 +2227,64 @@ queue_session_reset (GdmManager *manager, + + if (operation != NULL) { + return; + } + + operation = g_slice_new0 (ResetSessionOperation); + operation->manager = manager; + operation->session = g_object_ref (session); + operation->idle_id = g_idle_add ((GSourceFunc) on_reset_session, operation); + + g_object_set_data (G_OBJECT (session), "reset-session-operation", operation); + } + + static void + on_session_cancelled (GdmSession *session, + GdmManager *manager) + { + g_debug ("GdmManager: Session was cancelled"); + queue_session_reset (manager, session); + } + + static void + on_session_conversation_started (GdmSession *session, + const char *service_name, + GdmManager *manager) + { + GdmDisplay *display; + gboolean enabled; + char *username; + +- g_debug ("GdmManager: session conversation started for service %s", service_name); ++ g_debug ("GdmManager: session conversation started for service %s on session", service_name); + + if (g_strcmp0 (service_name, "gdm-autologin") != 0) { ++ g_debug ("GdmManager: ignoring session conversation since its not automatic login conversation"); + return; + } + + display = get_display_for_user_session (session); + + if (display == NULL) { + g_debug ("GdmManager: conversation has no associated display"); + return; + } + + if (!display_is_on_seat0 (display)) { + return; + } + + enabled = get_automatic_login_details (manager, &username); + + if (! enabled) { + return; + } + + g_debug ("GdmManager: begin auto login for user '%s'", username); + + /* service_name will be "gdm-autologin" + */ + gdm_session_setup_for_user (session, service_name, username); + + g_free (username); + } + + static void +@@ -2312,60 +2340,66 @@ create_user_session_for_display (GdmManager *manager, + 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); + + session = gdm_session_new (GDM_SESSION_VERIFICATION_MODE_LOGIN, + allowed_user, + display_name, + remote_hostname, + display_device, + display_seat_id, + display_auth_file, + display_is_local, + NULL); ++ ++ g_debug ("GdmSession: Created user session for user %d on display %s (seat %s)", ++ (int) allowed_user, ++ display_id, ++ display_seat_id); ++ + g_free (display_name); + g_free (remote_hostname); + g_free (display_auth_file); + g_free (display_seat_id); + + g_signal_connect (session, + "reauthentication-started", + G_CALLBACK (on_session_reauthentication_started), + manager); + g_signal_connect (session, + "reauthenticated", + G_CALLBACK (on_session_reauthenticated), + manager); + g_signal_connect (session, + "client-ready-for-session-to-start", + G_CALLBACK (on_session_client_ready_for_session_to_start), + manager); + g_signal_connect (session, + "client-connected", + G_CALLBACK (on_session_client_connected), + manager); + g_signal_connect (session, + "client-disconnected", + G_CALLBACK (on_session_client_disconnected), + manager); + g_signal_connect (session, + "cancelled", + G_CALLBACK (on_session_cancelled), + manager); + g_signal_connect (session, +diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c +index 0f821e390..f23a83c5e 100644 +--- a/daemon/gdm-session.c ++++ b/daemon/gdm-session.c +@@ -624,61 +624,64 @@ get_fallback_session_name (GdmSession *self) + + static const char * + get_default_session_name (GdmSession *self) + { + if (self->priv->saved_session != NULL) { + return self->priv->saved_session; + } + + return get_fallback_session_name (self); + } + + static void + gdm_session_defaults_changed (GdmSession *self) + { + + update_session_type (self); + + if (self->priv->greeter_interface != NULL) { + gdm_dbus_greeter_emit_default_language_name_changed (self->priv->greeter_interface, + get_default_language_name (self)); + gdm_dbus_greeter_emit_default_session_name_changed (self->priv->greeter_interface, + get_default_session_name (self)); + } + } + + void + gdm_session_select_user (GdmSession *self, + const char *text) + { + +- g_debug ("GdmSession: Setting user: '%s'", text); ++ g_debug ("GdmSession: selecting user '%s' for session '%s' (%p)", ++ text, ++ gdm_session_get_session_id (self), ++ self); + + g_free (self->priv->selected_user); + self->priv->selected_user = g_strdup (text); + + g_free (self->priv->saved_session); + self->priv->saved_session = NULL; + + g_free (self->priv->saved_session_type); + self->priv->saved_session_type = NULL; + + g_free (self->priv->saved_language); + self->priv->saved_language = NULL; + } + + static void + cancel_pending_query (GdmSessionConversation *conversation) + { + if (conversation->pending_invocation == NULL) { + return; + } + + g_debug ("GdmSession: Cancelling pending query"); + + g_dbus_method_invocation_return_dbus_error (conversation->pending_invocation, + GDM_SESSION_DBUS_ERROR_CANCEL, + "Operation cancelled"); + conversation->pending_invocation = NULL; + } + + static void +@@ -1416,117 +1419,121 @@ gdm_session_handle_client_cancel (GdmDBusUserVerifier *user_verifier_interfac + gdm_dbus_user_verifier_complete_cancel (user_verifier_interface, + invocation); + gdm_session_cancel (self); + return TRUE; + } + + static gboolean + gdm_session_handle_client_select_session (GdmDBusGreeter *greeter_interface, + GDBusMethodInvocation *invocation, + const char *session, + GdmSession *self) + { + if (self->priv->greeter_interface != NULL) { + gdm_dbus_greeter_complete_select_session (greeter_interface, + invocation); + } + gdm_session_select_session (self, session); + return TRUE; + } + + static gboolean + gdm_session_handle_client_select_user (GdmDBusGreeter *greeter_interface, + GDBusMethodInvocation *invocation, + const char *username, + GdmSession *self) + { + if (self->priv->greeter_interface != NULL) { + gdm_dbus_greeter_complete_select_user (greeter_interface, + invocation); + } ++ g_debug ("GdmSession: client selected user '%s' on session (%p)", username, self); + gdm_session_select_user (self, username); + return TRUE; + } + + static gboolean + gdm_session_handle_client_start_session_when_ready (GdmDBusGreeter *greeter_interface, + GDBusMethodInvocation *invocation, + const char *service_name, + gboolean client_is_ready, + GdmSession *self) + { + + if (self->priv->greeter_interface != NULL) { + gdm_dbus_greeter_complete_start_session_when_ready (greeter_interface, + invocation); + } + g_signal_emit (G_OBJECT (self), + signals [CLIENT_READY_FOR_SESSION_TO_START], + 0, + service_name, + client_is_ready); + return TRUE; + } + + static gboolean + gdm_session_handle_get_timed_login_details (GdmDBusGreeter *greeter_interface, + GDBusMethodInvocation *invocation, + GdmSession *self) + { + + if (self->priv->greeter_interface != NULL) { + gdm_dbus_greeter_complete_get_timed_login_details (greeter_interface, + invocation, + self->priv->timed_login_username != NULL, + self->priv->timed_login_username != NULL? self->priv->timed_login_username : "", + self->priv->timed_login_delay); + if (self->priv->timed_login_username != NULL) { + gdm_dbus_greeter_emit_timed_login_requested (self->priv->greeter_interface, + self->priv->timed_login_username, + self->priv->timed_login_delay); + } + } + return TRUE; + } + + static gboolean + gdm_session_handle_client_begin_auto_login (GdmDBusGreeter *greeter_interface, + GDBusMethodInvocation *invocation, + const char *username, + GdmSession *self) + { + if (self->priv->greeter_interface != NULL) { + gdm_dbus_greeter_complete_begin_auto_login (greeter_interface, + invocation); + } + +- g_debug ("GdmSession: begin auto login for user '%s'", username); ++ g_debug ("GdmSession: client requesting automatic login for user '%s' on session '%s' (%p)", ++ username, ++ gdm_session_get_session_id (self), ++ self); + + gdm_session_setup_for_user (self, "gdm-autologin", username); + + return TRUE; + } + + static void + export_user_verifier_interface (GdmSession *self, + GDBusConnection *connection) + { + GdmDBusUserVerifier *user_verifier_interface; + user_verifier_interface = GDM_DBUS_USER_VERIFIER (gdm_dbus_user_verifier_skeleton_new ()); + + g_object_set_data (G_OBJECT (connection), "gdm-session", self); + + g_signal_connect (user_verifier_interface, + "handle-enable-extensions", + G_CALLBACK (gdm_session_handle_client_enable_extensions), + connection); + g_signal_connect (user_verifier_interface, + "handle-begin-verification", + G_CALLBACK (gdm_session_handle_client_begin_verification), + self); + g_signal_connect (user_verifier_interface, + "handle-begin-verification-for-user", + G_CALLBACK (gdm_session_handle_client_begin_verification_for_user), + self); + g_signal_connect (user_verifier_interface, + "handle-answer-query", + G_CALLBACK (gdm_session_handle_client_answer_query), +@@ -1775,61 +1782,63 @@ allow_user_function (GDBusAuthObserver *observer, + { + uid_t client_uid; + GPid pid_of_client; + + client_uid = g_credentials_get_unix_user (credentials, NULL); + if (client_uid == self->priv->allowed_user) { + return TRUE; + } + + g_debug ("GdmSession: User not allowed"); + + pid_of_client = g_credentials_get_unix_pid (credentials, NULL); + g_signal_emit (G_OBJECT (self), + signals [CLIENT_REJECTED], + 0, + credentials, + (guint) + pid_of_client); + + + return FALSE; + } + + static void + setup_outside_server (GdmSession *self) + { + GDBusAuthObserver *observer; + GDBusServer *server; + GError *error = NULL; + +- g_debug ("GdmSession: Creating D-Bus server for greeters and such"); ++ g_debug ("GdmSession: Creating D-Bus server for greeters and such for session %s (%p)", ++ gdm_session_get_session_id (self), ++ self); + + observer = g_dbus_auth_observer_new (); + g_signal_connect_object (observer, + "authorize-authenticated-peer", + G_CALLBACK (allow_user_function), + self, + 0); + + server = gdm_dbus_setup_private_server (observer, &error); + g_object_unref (observer); + + if (server == NULL) { + g_warning ("Cannot create greeter D-Bus server for the session: %s", + error->message); + return; + } + + g_signal_connect_object (server, + "new-connection", + G_CALLBACK (handle_connection_from_outside), + self, + 0); + self->priv->outside_server = server; + + g_dbus_server_start (server); + + g_debug ("GdmSession: D-Bus server for greeters listening on %s", + g_dbus_server_get_client_address (self->priv->outside_server)); + } + +@@ -2160,61 +2169,61 @@ stop_conversation_now (GdmSessionConversation *conversation) + void + gdm_session_set_ignore_wayland (GdmSession *self, + gboolean ignore_wayland) + { + self->priv->ignore_wayland = ignore_wayland; + } + #endif + + gboolean + gdm_session_start_conversation (GdmSession *self, + const char *service_name) + { + GdmSessionConversation *conversation; + + g_return_val_if_fail (GDM_IS_SESSION (self), FALSE); + + conversation = g_hash_table_lookup (self->priv->conversations, + service_name); + + if (conversation != NULL) { + if (!conversation->is_stopping) { + g_warning ("GdmSession: conversation %s started more than once", service_name); + return FALSE; + } + g_debug ("GdmSession: stopping old conversation %s", service_name); + gdm_session_worker_job_stop_now (conversation->job); + g_object_unref (conversation->job); + conversation->job = NULL; + } + +- g_debug ("GdmSession: starting conversation %s", service_name); ++ g_debug ("GdmSession: starting conversation %s for session (%p)", service_name, self); + + conversation = start_conversation (self, service_name); + + g_hash_table_insert (self->priv->conversations, + g_strdup (service_name), conversation); + return TRUE; + } + + void + gdm_session_stop_conversation (GdmSession *self, + const char *service_name) + { + GdmSessionConversation *conversation; + + g_return_if_fail (GDM_IS_SESSION (self)); + + g_debug ("GdmSession: stopping conversation %s", service_name); + + conversation = find_conversation_by_name (self, service_name); + + if (conversation != NULL) { + stop_conversation (conversation); + } + } + + static void + on_initialization_complete_cb (GdmDBusWorker *proxy, + GAsyncResult *res, + gpointer user_data) + { +@@ -2319,60 +2328,64 @@ initialize (GdmSession *self, + } + + g_free (extensions); + } + + void + gdm_session_setup (GdmSession *self, + const char *service_name) + { + + g_return_if_fail (GDM_IS_SESSION (self)); + + update_session_type (self); + + initialize (self, service_name, NULL, NULL); + gdm_session_defaults_changed (self); + } + + + void + gdm_session_setup_for_user (GdmSession *self, + const char *service_name, + const char *username) + { + + g_return_if_fail (GDM_IS_SESSION (self)); + g_return_if_fail (username != NULL); + + update_session_type (self); + ++ g_debug ("GdmSession: Set up service %s for username %s on session (%p)", ++ service_name, ++ username, ++ self); + gdm_session_select_user (self, username); + + self->priv->is_program_session = FALSE; + initialize (self, service_name, self->priv->selected_user, NULL); + gdm_session_defaults_changed (self); + } + + void + gdm_session_setup_for_program (GdmSession *self, + const char *service_name, + const char *username, + const char *log_file) + { + + g_return_if_fail (GDM_IS_SESSION (self)); + + self->priv->is_program_session = TRUE; + initialize (self, service_name, username, log_file); + } + + void + gdm_session_authenticate (GdmSession *self, + const char *service_name) + { + GdmSessionConversation *conversation; + + g_return_if_fail (GDM_IS_SESSION (self)); + + conversation = find_conversation_by_name (self, service_name); + if (conversation != NULL) { +@@ -2968,60 +2981,64 @@ gdm_session_set_timed_login_details (GdmSession *self, + + gboolean + gdm_session_is_running (GdmSession *self) + { + return self->priv->session_pid > 0; + } + + gboolean + gdm_session_client_is_connected (GdmSession *self) + { + g_return_val_if_fail (GDM_IS_SESSION (self), FALSE); + + return self->priv->outside_connections != NULL; + } + + uid_t + gdm_session_get_allowed_user (GdmSession *self) + { + return self->priv->allowed_user; + } + + void + gdm_session_start_reauthentication (GdmSession *session, + GPid pid_of_caller, + uid_t uid_of_caller) + { + GdmSessionConversation *conversation = session->priv->session_conversation; + + g_return_if_fail (conversation != NULL); + ++ g_debug ("GdmSession: starting reauthentication for session %s for client with pid %d", ++ conversation->session_id, ++ (int) uid_of_caller); ++ + conversation->reauth_pid_of_caller = pid_of_caller; + + gdm_dbus_worker_call_start_reauthentication (conversation->worker_proxy, + (int) pid_of_caller, + (int) uid_of_caller, + conversation->worker_cancellable, + (GAsyncReadyCallback) on_reauthentication_started_cb, + conversation); + } + + const char * + gdm_session_get_server_address (GdmSession *self) + { + g_return_val_if_fail (GDM_IS_SESSION (self), NULL); + + return g_dbus_server_get_client_address (self->priv->outside_server); + } + + const char * + gdm_session_get_username (GdmSession *self) + { + g_return_val_if_fail (GDM_IS_SESSION (self), NULL); + + return self->priv->selected_user; + } + + const char * + gdm_session_get_display_device (GdmSession *self) + { + g_return_val_if_fail (GDM_IS_SESSION (self), NULL); +-- +2.21.0 + diff --git a/SOURCES/0002-session-worker-kill-user-sessions-when-stop-gdm-serv.patch b/SOURCES/0002-session-worker-kill-user-sessions-when-stop-gdm-serv.patch new file mode 100644 index 0000000..85175ea --- /dev/null +++ b/SOURCES/0002-session-worker-kill-user-sessions-when-stop-gdm-serv.patch @@ -0,0 +1,922 @@ +From 4db5bf628396a7191f2392e7d09ab9bbd7c2b533 Mon Sep 17 00:00:00 2001 +From: Xiaoguang Wang +Date: Thu, 16 May 2019 13:26:16 +0800 +Subject: [PATCH 2/3] session-worker: kill user sessions when stop gdm service + +At the moment the session worker exits as soon as it gets SIGTERM. +That means it may fail to stop the user session (which only happens +in the orderly shutdown path). + +This commit sets up a SIGTERM handler that integrates with and +quits the main loop after the session is started. + +It still retains the _exit-on-SIGTERM behavior before the session +is started, to ensure a stuck pam module doesn't prevent the +process from dying. + +Some small changes to commit by Ray Strode. + +Closes #400 +--- + daemon/gdm-session-worker.c | 39 +++++++++++++++++++++++++++--------- + daemon/session-worker-main.c | 33 ++++++++++++++++++++++++++++++ + 2 files changed, 63 insertions(+), 9 deletions(-) + +diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c +index f6935ab1d..aa288ac8e 100644 +--- a/daemon/gdm-session-worker.c ++++ b/daemon/gdm-session-worker.c +@@ -159,60 +159,61 @@ struct GdmSessionWorkerPrivate + guint32 display_is_initial : 1; + guint state_change_idle_id; + GdmSessionDisplayMode display_mode; + + char *server_address; + GDBusConnection *connection; + GdmDBusWorkerManager *manager; + + GHashTable *reauthentication_requests; + + GdmSessionAuditor *auditor; + GdmSessionSettings *user_settings; + + GDBusMethodInvocation *pending_invocation; + }; + + #ifdef SUPPORTS_PAM_EXTENSIONS + static char gdm_pam_extension_environment_block[_POSIX_ARG_MAX]; + + static const char * const + gdm_supported_pam_extensions[] = { + GDM_PAM_EXTENSION_CHOICE_LIST, + NULL + }; + #endif + + enum { + PROP_0, + PROP_SERVER_ADDRESS, + PROP_IS_REAUTH_SESSION, ++ PROP_STATE, + }; + + static void gdm_session_worker_class_init (GdmSessionWorkerClass *klass); + static void gdm_session_worker_init (GdmSessionWorker *session_worker); + static void gdm_session_worker_finalize (GObject *object); + + static void gdm_session_worker_set_environment_variable (GdmSessionWorker *worker, + const char *key, + const char *value); + + static void queue_state_change (GdmSessionWorker *worker); + + static void worker_interface_init (GdmDBusWorkerIface *iface); + + + typedef int (* GdmSessionWorkerPamNewMessagesFunc) (int, + const struct pam_message **, + struct pam_response **, + gpointer); + + G_DEFINE_TYPE_WITH_CODE (GdmSessionWorker, + gdm_session_worker, + GDM_DBUS_TYPE_WORKER_SKELETON, + G_IMPLEMENT_INTERFACE (GDM_DBUS_TYPE_WORKER, + worker_interface_init)) + + /* adapted from glib script_execute */ + static void + script_execute (const gchar *file, + char **argv, +@@ -971,100 +972,111 @@ jump_to_vt (GdmSessionWorker *worker, + + g_debug ("GdmSessionWorker: first setting graphics mode to prevent flicker"); + if (ioctl (fd, KDSETMODE, KD_GRAPHICS) < 0) { + g_debug ("GdmSessionWorker: couldn't set graphics mode: %m"); + } + + /* It's possible that the current VT was left in a broken + * combination of states (KD_GRAPHICS with VT_AUTO), that + * can't be switched away from. This call makes sure things + * are set in a way that VT_ACTIVATE should work and + * VT_WAITACTIVE shouldn't hang. + */ + fix_terminal_vt_mode (worker, active_vt_tty_fd); + } else { + fd = active_vt_tty_fd; + } + + handle_terminal_vt_switches (worker, fd); + + if (ioctl (fd, VT_ACTIVATE, vt_number) < 0) { + g_debug ("GdmSessionWorker: couldn't initiate jump to VT %d: %m", + vt_number); + } else if (ioctl (fd, VT_WAITACTIVE, vt_number) < 0) { + g_debug ("GdmSessionWorker: couldn't finalize jump to VT %d: %m", + vt_number); + } + + close (active_vt_tty_fd); + } + ++static void ++gdm_session_worker_set_state (GdmSessionWorker *worker, ++ GdmSessionWorkerState state) ++{ ++ if (worker->priv->state == state) ++ return; ++ ++ worker->priv->state = state; ++ g_object_notify (G_OBJECT (worker), "state"); ++} ++ + static void + gdm_session_worker_uninitialize_pam (GdmSessionWorker *worker, + int status) + { + g_debug ("GdmSessionWorker: uninitializing PAM"); + + if (worker->priv->pam_handle == NULL) + return; + + gdm_session_worker_get_username (worker, NULL); + + if (worker->priv->state >= GDM_SESSION_WORKER_STATE_SESSION_OPENED) { + pam_close_session (worker->priv->pam_handle, 0); + gdm_session_auditor_report_logout (worker->priv->auditor); + } else { + gdm_session_auditor_report_login_failure (worker->priv->auditor, + status, + pam_strerror (worker->priv->pam_handle, status)); + } + + if (worker->priv->state >= GDM_SESSION_WORKER_STATE_ACCREDITED) { + pam_setcred (worker->priv->pam_handle, PAM_DELETE_CRED); + } + + pam_end (worker->priv->pam_handle, status); + worker->priv->pam_handle = NULL; + + gdm_session_worker_stop_auditor (worker); + + if (g_strcmp0 (worker->priv->display_seat_id, "seat0") == 0) { + if (worker->priv->login_vt != worker->priv->session_vt) { + jump_to_vt (worker, worker->priv->login_vt); + } + } + + worker->priv->login_vt = 0; + worker->priv->session_vt = 0; + + g_debug ("GdmSessionWorker: state NONE"); +- worker->priv->state = GDM_SESSION_WORKER_STATE_NONE; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_NONE); + } + + static char * + _get_tty_for_pam (const char *x11_display_name, + const char *display_device) + { + #ifdef __sun + return g_strdup (display_device); + #else + return g_strdup (x11_display_name); + #endif + } + + #ifdef PAM_XAUTHDATA + static struct pam_xauth_data * + _get_xauth_for_pam (const char *x11_authority_file) + { + FILE *fh; + Xauth *auth = NULL; + struct pam_xauth_data *retval = NULL; + gsize len = sizeof (*retval) + 1; + + fh = fopen (x11_authority_file, "r"); + if (fh) { + auth = XauReadAuth (fh); + fclose (fh); + } + if (auth) { + len += auth->name_length + auth->data_length; + retval = g_malloc0 (len); +@@ -1173,61 +1185,61 @@ gdm_session_worker_initialize_pam (GdmSessionWorker *worker, + goto out; + } + } + + /* set RHOST */ + if (hostname != NULL && hostname[0] != '\0') { + error_code = pam_set_item (worker->priv->pam_handle, PAM_RHOST, hostname); + g_debug ("error informing authentication system of user's hostname %s: %s", + hostname, + pam_strerror (worker->priv->pam_handle, error_code)); + + if (error_code != PAM_SUCCESS) { + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_AUTHENTICATING, + "%s", ""); + goto out; + } + } + + /* set seat ID */ + if (seat_id != NULL && seat_id[0] != '\0') { + gdm_session_worker_set_environment_variable (worker, "XDG_SEAT", seat_id); + } + + if (strcmp (service, "gdm-launch-environment") == 0) { + gdm_session_worker_set_environment_variable (worker, "XDG_SESSION_CLASS", "greeter"); + } + + g_debug ("GdmSessionWorker: state SETUP_COMPLETE"); +- worker->priv->state = GDM_SESSION_WORKER_STATE_SETUP_COMPLETE; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE); + + /* Temporarily set PAM_TTY with the currently active VT (login screen) + PAM_TTY will be reset with the users VT right before the user session is opened */ + ensure_login_vt (worker); + g_snprintf (tty_string, 256, "/dev/tty%d", worker->priv->login_vt); + pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string); + if (!display_is_local) + worker->priv->password_is_required = TRUE; + + out: + if (error_code != PAM_SUCCESS) { + gdm_session_worker_uninitialize_pam (worker, error_code); + return FALSE; + } + + return TRUE; + } + + static gboolean + gdm_session_worker_authenticate_user (GdmSessionWorker *worker, + gboolean password_is_required, + GError **error) + { + int error_code; + int authentication_flags; + + g_debug ("GdmSessionWorker: authenticating user %s", worker->priv->username); + + authentication_flags = 0; + +@@ -1238,61 +1250,61 @@ gdm_session_worker_authenticate_user (GdmSessionWorker *worker, + /* blocking call, does the actual conversation */ + error_code = pam_authenticate (worker->priv->pam_handle, authentication_flags); + + if (error_code == PAM_AUTHINFO_UNAVAIL) { + g_debug ("GdmSessionWorker: authentication service unavailable"); + + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE, + "%s", ""); + goto out; + } else if (error_code != PAM_SUCCESS) { + g_debug ("GdmSessionWorker: authentication returned %d: %s", error_code, pam_strerror (worker->priv->pam_handle, error_code)); + + /* + * Do not display a different message for user unknown versus + * a failed password for a valid user. + */ + if (error_code == PAM_USER_UNKNOWN) { + error_code = PAM_AUTH_ERR; + } + + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_AUTHENTICATING, + "%s", get_friendly_error_message (error_code)); + goto out; + } + + g_debug ("GdmSessionWorker: state AUTHENTICATED"); +- worker->priv->state = GDM_SESSION_WORKER_STATE_AUTHENTICATED; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_AUTHENTICATED); + + out: + if (error_code != PAM_SUCCESS) { + gdm_session_worker_uninitialize_pam (worker, error_code); + return FALSE; + } + + return TRUE; + } + + static gboolean + gdm_session_worker_authorize_user (GdmSessionWorker *worker, + gboolean password_is_required, + GError **error) + { + int error_code; + int authentication_flags; + + g_debug ("GdmSessionWorker: determining if authenticated user (password required:%d) is authorized to session", + password_is_required); + + authentication_flags = 0; + + if (password_is_required) { + authentication_flags |= PAM_DISALLOW_NULL_AUTHTOK; + } + + /* check that the account isn't disabled or expired + */ + error_code = pam_acct_mgmt (worker->priv->pam_handle, authentication_flags); +@@ -1303,61 +1315,61 @@ gdm_session_worker_authorize_user (GdmSessionWorker *worker, + g_debug ("GdmSessionWorker: authenticated user requires new auth token"); + error_code = pam_chauthtok (worker->priv->pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK); + + gdm_session_worker_get_username (worker, NULL); + + if (error_code != PAM_SUCCESS) { + gdm_session_auditor_report_password_change_failure (worker->priv->auditor); + } else { + gdm_session_auditor_report_password_changed (worker->priv->auditor); + } + } + + /* If the user is reauthenticating, then authorization isn't required to + * proceed, the user is already logged in after all. + */ + if (worker->priv->is_reauth_session) { + error_code = PAM_SUCCESS; + } + + if (error_code != PAM_SUCCESS) { + g_debug ("GdmSessionWorker: user is not authorized to log in: %s", + pam_strerror (worker->priv->pam_handle, error_code)); + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_AUTHORIZING, + "%s", get_friendly_error_message (error_code)); + goto out; + } + + g_debug ("GdmSessionWorker: state AUTHORIZED"); +- worker->priv->state = GDM_SESSION_WORKER_STATE_AUTHORIZED; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_AUTHORIZED); + + out: + if (error_code != PAM_SUCCESS) { + gdm_session_worker_uninitialize_pam (worker, error_code); + return FALSE; + } + + return TRUE; + } + + static void + gdm_session_worker_set_environment_variable (GdmSessionWorker *worker, + const char *key, + const char *value) + { + int error_code; + char *environment_entry; + + if (value != NULL) { + environment_entry = g_strdup_printf ("%s=%s", key, value); + } else { + /* empty value means "remove from environment" */ + environment_entry = g_strdup (key); + } + + error_code = pam_putenv (worker->priv->pam_handle, + environment_entry); + + if (error_code != PAM_SUCCESS) { + g_warning ("cannot put %s in pam environment: %s\n", +@@ -1716,61 +1728,61 @@ gdm_session_worker_accredit_user (GdmSessionWorker *worker, + + /* If the user is reauthenticating and they've made it this far, then there + * is no reason we should lock them out of their session. They've already + * proved they are they same person who logged in, and that's all we care + * about. + */ + if (worker->priv->is_reauth_session) { + error_code = PAM_SUCCESS; + } + + if (error_code != PAM_SUCCESS) { + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_GIVING_CREDENTIALS, + "%s", + pam_strerror (worker->priv->pam_handle, error_code)); + goto out; + } + + ret = TRUE; + + out: + g_free (home); + g_free (shell); + if (ret) { + g_debug ("GdmSessionWorker: state ACCREDITED"); + ret = TRUE; + + gdm_session_worker_get_username (worker, NULL); + gdm_session_auditor_report_user_accredited (worker->priv->auditor); +- worker->priv->state = GDM_SESSION_WORKER_STATE_ACCREDITED; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_ACCREDITED); + } else { + gdm_session_worker_uninitialize_pam (worker, error_code); + } + + return ret; + } + + static const char * const * + gdm_session_worker_get_environment (GdmSessionWorker *worker) + { + return (const char * const *) pam_getenvlist (worker->priv->pam_handle); + } + + static gboolean + run_script (GdmSessionWorker *worker, + const char *dir) + { + /* scripts are for non-program sessions only */ + if (worker->priv->is_program_session) { + return TRUE; + } + + return gdm_run_script (dir, + worker->priv->username, + worker->priv->x11_display_name, + worker->priv->display_is_local? NULL : worker->priv->hostname, + worker->priv->x11_authority_file); + } + + static void +@@ -2145,61 +2157,61 @@ gdm_session_worker_start_session (GdmSessionWorker *worker, + (char **) + environment, + TRUE); + + gdm_log_init (); + g_debug ("GdmSessionWorker: child '%s' could not be started: %s", + worker->priv->arguments[0], + g_strerror (errno)); + + _exit (EXIT_FAILURE); + } + + if (worker->priv->session_tty_fd > 0) { + close (worker->priv->session_tty_fd); + worker->priv->session_tty_fd = -1; + } + + /* If we end up execing again, make sure we don't use the executable context set up + * by pam_selinux durin pam_open_session + */ + #ifdef HAVE_SELINUX + setexeccon (NULL); + #endif + + worker->priv->child_pid = session_pid; + + g_debug ("GdmSessionWorker: session opened creating reply..."); + g_assert (sizeof (GPid) <= sizeof (int)); + + g_debug ("GdmSessionWorker: state SESSION_STARTED"); +- worker->priv->state = GDM_SESSION_WORKER_STATE_SESSION_STARTED; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SESSION_STARTED); + + gdm_session_worker_watch_child (worker); + + out: + if (error_code != PAM_SUCCESS) { + gdm_session_worker_uninitialize_pam (worker, error_code); + return FALSE; + } + + return TRUE; + } + + static gboolean + set_up_for_new_vt (GdmSessionWorker *worker) + { + int fd; + char vt_string[256], tty_string[256]; + int session_vt = 0; + + fd = open ("/dev/tty0", O_RDWR | O_NOCTTY); + + if (fd < 0) { + g_debug ("GdmSessionWorker: couldn't open VT master: %m"); + return FALSE; + } + + if (worker->priv->display_is_initial) { + session_vt = atoi (GDM_INITIAL_VT); + } else { + if (ioctl(fd, VT_OPENQRY, &session_vt) < 0) { +@@ -2368,61 +2380,61 @@ gdm_session_worker_open_session (GdmSessionWorker *worker, + break; + case GDM_SESSION_DISPLAY_MODE_NEW_VT: + case GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED: + if (!set_up_for_new_vt (worker)) { + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_OPENING_SESSION, + "Unable to open VT"); + return FALSE; + } + break; + } + + flags = 0; + + if (worker->priv->is_program_session) { + flags |= PAM_SILENT; + } + + error_code = pam_open_session (worker->priv->pam_handle, flags); + + if (error_code != PAM_SUCCESS) { + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_OPENING_SESSION, + "%s", pam_strerror (worker->priv->pam_handle, error_code)); + goto out; + } + + g_debug ("GdmSessionWorker: state SESSION_OPENED"); +- worker->priv->state = GDM_SESSION_WORKER_STATE_SESSION_OPENED; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SESSION_OPENED); + + session_id = gdm_session_worker_get_environment_variable (worker, "XDG_SESSION_ID"); + + if (session_id != NULL) { + g_free (worker->priv->session_id); + worker->priv->session_id = session_id; + } + + out: + if (error_code != PAM_SUCCESS) { + gdm_session_worker_uninitialize_pam (worker, error_code); + return FALSE; + } + + gdm_session_worker_get_username (worker, NULL); + gdm_session_auditor_report_login (worker->priv->auditor); + + return TRUE; + } + + static void + gdm_session_worker_set_server_address (GdmSessionWorker *worker, + const char *address) + { + g_free (worker->priv->server_address); + worker->priv->server_address = g_strdup (address); + } + + static void + gdm_session_worker_set_is_reauth_session (GdmSessionWorker *worker, +@@ -2445,61 +2457,61 @@ gdm_session_worker_set_property (GObject *object, + case PROP_SERVER_ADDRESS: + gdm_session_worker_set_server_address (self, g_value_get_string (value)); + break; + case PROP_IS_REAUTH_SESSION: + gdm_session_worker_set_is_reauth_session (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } + + static void + gdm_session_worker_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) + { + GdmSessionWorker *self; + + self = GDM_SESSION_WORKER (object); + + switch (prop_id) { + case PROP_SERVER_ADDRESS: + g_value_set_string (value, self->priv->server_address); + break; + case PROP_IS_REAUTH_SESSION: + g_value_set_boolean (value, self->priv->is_reauth_session); + break; + case PROP_STATE: +- g_value_set_int (value, self->priv->state); ++ g_value_set_enum (value, self->priv->state); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } + + static gboolean + gdm_session_worker_handle_set_environment_variable (GdmDBusWorker *object, + GDBusMethodInvocation *invocation, + const char *key, + const char *value) + { + GdmSessionWorker *worker = GDM_SESSION_WORKER (object); + gdm_session_worker_set_environment_variable (worker, key, value); + gdm_dbus_worker_complete_set_environment_variable (object, invocation); + return TRUE; + } + + static gboolean + gdm_session_worker_handle_set_session_name (GdmDBusWorker *object, + GDBusMethodInvocation *invocation, + const char *session_name) + { + GdmSessionWorker *worker = GDM_SESSION_WORKER (object); + g_debug ("GdmSessionWorker: session name set to %s", session_name); + if (worker->priv->user_settings != NULL) + gdm_session_settings_set_session_name (worker->priv->user_settings, + session_name); + gdm_dbus_worker_complete_set_session_name (object, invocation); +@@ -2646,61 +2658,61 @@ do_authorize (GdmSessionWorker *worker) + g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error); + } + worker->priv->pending_invocation = NULL; + } + + static void + do_accredit (GdmSessionWorker *worker) + { + GError *error; + gboolean res; + + /* get kerberos tickets, setup group lists, etc + */ + error = NULL; + res = gdm_session_worker_accredit_user (worker, &error); + + if (res) { + gdm_dbus_worker_complete_establish_credentials (GDM_DBUS_WORKER (worker), worker->priv->pending_invocation); + } else { + g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error); + } + worker->priv->pending_invocation = NULL; + } + + static void + save_account_details_now (GdmSessionWorker *worker) + { + g_assert (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCREDITED); + + g_debug ("GdmSessionWorker: saving account details for user %s", worker->priv->username); +- worker->priv->state = GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED; ++ gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED); + if (worker->priv->user_settings != NULL) { + if (!gdm_session_settings_save (worker->priv->user_settings, + worker->priv->username)) { + g_warning ("could not save session and language settings"); + } + } + queue_state_change (worker); + } + + static void + on_settings_is_loaded_changed (GdmSessionSettings *user_settings, + GParamSpec *pspec, + GdmSessionWorker *worker) + { + if (!gdm_session_settings_is_loaded (worker->priv->user_settings)) { + return; + } + + /* These signal handlers should be disconnected after the loading, + * so that gdm_session_settings_set_* APIs don't cause the emitting + * of Saved*NameRead D-Bus signals any more. + */ + g_signal_handlers_disconnect_by_func (worker->priv->user_settings, + G_CALLBACK (on_saved_session_name_read), + worker); + + g_signal_handlers_disconnect_by_func (worker->priv->user_settings, + G_CALLBACK (on_saved_language_name_read), + worker); + +@@ -3461,60 +3473,69 @@ worker_interface_init (GdmDBusWorkerIface *interface) + interface->handle_start_reauthentication = gdm_session_worker_handle_start_reauthentication; + } + + static void + gdm_session_worker_class_init (GdmSessionWorkerClass *klass) + { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = gdm_session_worker_get_property; + object_class->set_property = gdm_session_worker_set_property; + object_class->constructor = gdm_session_worker_constructor; + object_class->finalize = gdm_session_worker_finalize; + + g_type_class_add_private (klass, sizeof (GdmSessionWorkerPrivate)); + + g_object_class_install_property (object_class, + PROP_SERVER_ADDRESS, + g_param_spec_string ("server-address", + "server address", + "server address", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, + PROP_IS_REAUTH_SESSION, + g_param_spec_boolean ("is-reauth-session", + "is reauth session", + "is reauth session", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); ++ ++ g_object_class_install_property (object_class, ++ PROP_STATE, ++ g_param_spec_enum ("state", ++ "state", ++ "state", ++ GDM_TYPE_SESSION_WORKER_STATE, ++ GDM_SESSION_WORKER_STATE_NONE, ++ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + } + + static void + reauthentication_request_free (ReauthenticationRequest *request) + { + + g_signal_handlers_disconnect_by_func (request->session, + G_CALLBACK (on_reauthentication_client_connected), + request); + g_signal_handlers_disconnect_by_func (request->session, + G_CALLBACK (on_reauthentication_client_disconnected), + request); + g_signal_handlers_disconnect_by_func (request->session, + G_CALLBACK (on_reauthentication_cancelled), + request); + g_signal_handlers_disconnect_by_func (request->session, + G_CALLBACK (on_reauthentication_conversation_started), + request); + g_signal_handlers_disconnect_by_func (request->session, + G_CALLBACK (on_reauthentication_conversation_stopped), + request); + g_signal_handlers_disconnect_by_func (request->session, + G_CALLBACK (on_reauthentication_verification_complete), + request); + g_clear_object (&request->session); + g_slice_free (ReauthenticationRequest, request); + } + + static void + gdm_session_worker_init (GdmSessionWorker *worker) +diff --git a/daemon/session-worker-main.c b/daemon/session-worker-main.c +index 4a3a8ebbe..d96844d2d 100644 +--- a/daemon/session-worker-main.c ++++ b/daemon/session-worker-main.c +@@ -37,104 +37,137 @@ + #include + + #include "gdm-common.h" + #include "gdm-log.h" + #include "gdm-session-worker.h" + + #include "gdm-settings.h" + #include "gdm-settings-direct.h" + #include "gdm-settings-keys.h" + + static GdmSettings *settings = NULL; + + static gboolean + on_sigusr1_cb (gpointer user_data) + { + g_debug ("Got USR1 signal"); + + gdm_log_toggle_debug (); + + return TRUE; + } + + static gboolean + is_debug_set (void) + { + gboolean debug; + gdm_settings_direct_get_boolean (GDM_KEY_DEBUG, &debug); + return debug; + } + ++static gboolean ++on_shutdown_signal_cb (gpointer user_data) ++{ ++ GMainLoop *mainloop = user_data; ++ ++ g_main_loop_quit (mainloop); ++ ++ return FALSE; ++} ++ ++static void ++on_state_changed (GdmSessionWorker *worker, ++ GParamSpec *pspec, ++ GMainLoop *main_loop) ++{ ++ GdmSessionWorkerState state; ++ ++ g_object_get (G_OBJECT (worker), "state", &state, NULL); ++ ++ if (state != GDM_SESSION_WORKER_STATE_SESSION_STARTED) ++ return; ++ ++ g_unix_signal_add (SIGTERM, on_shutdown_signal_cb, main_loop); ++} ++ + static void + on_sigterm_cb (int signal_number) + { + _exit (EXIT_SUCCESS); + } + + int + main (int argc, + char **argv) + { + GMainLoop *main_loop; + GOptionContext *context; + GdmSessionWorker *worker; + const char *address; + gboolean is_for_reauth; + static GOptionEntry entries [] = { + { NULL } + }; + + signal (SIGTERM, on_sigterm_cb); + + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + textdomain (GETTEXT_PACKAGE); + setlocale (LC_ALL, ""); + + /* Translators: worker is a helper process that does the work + of starting up a session */ + context = g_option_context_new (_("GNOME Display Manager Session Worker")); + g_option_context_add_main_entries (context, entries, NULL); + + g_option_context_parse (context, &argc, &argv, NULL); + g_option_context_free (context); + + gdm_log_init (); + + settings = gdm_settings_new (); + if (settings == NULL) { + g_warning ("Unable to initialize settings"); + exit (EXIT_FAILURE); + } + + if (! gdm_settings_direct_init (settings, DATADIR "/gdm/gdm.schemas", "/")) { + g_warning ("Unable to initialize settings"); + exit (EXIT_FAILURE); + } + + gdm_log_set_debug (is_debug_set ()); + + address = g_getenv ("GDM_SESSION_DBUS_ADDRESS"); + if (address == NULL) { + g_warning ("GDM_SESSION_DBUS_ADDRESS not set"); + exit (EXIT_FAILURE); + } + + is_for_reauth = g_getenv ("GDM_SESSION_FOR_REAUTH") != NULL; + + worker = gdm_session_worker_new (address, is_for_reauth); + + main_loop = g_main_loop_new (NULL, FALSE); + ++ g_signal_connect (G_OBJECT (worker), ++ "notify::state", ++ G_CALLBACK (on_state_changed), ++ main_loop); ++ + g_unix_signal_add (SIGUSR1, on_sigusr1_cb, NULL); + + g_main_loop_run (main_loop); + + if (worker != NULL) { ++ g_signal_handlers_disconnect_by_func (worker, ++ G_CALLBACK (on_state_changed), ++ main_loop); + g_object_unref (worker); + } + + g_main_loop_unref (main_loop); + + g_debug ("Worker finished"); + + return 0; + } +-- +2.18.1 + diff --git a/SOURCES/0003-session-Don-t-allow-greeter-operations-on-an-running.patch b/SOURCES/0003-session-Don-t-allow-greeter-operations-on-an-running.patch new file mode 100644 index 0000000..cc60c6f --- /dev/null +++ b/SOURCES/0003-session-Don-t-allow-greeter-operations-on-an-running.patch @@ -0,0 +1,227 @@ +From 7b83c1dc9645cabadfeb253d7eca427f6a26d10f Mon Sep 17 00:00:00 2001 +From: Iain Lane +Date: Thu, 31 Jan 2019 17:51:52 +0000 +Subject: [PATCH 3/4] session: Don't allow greeter operations on an running + session + +If a client has a reference to a session that starts running, +refuse to allow further operations on the session. + +CVE-2019-3825 +--- + daemon/gdm-session.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 75 insertions(+) + +diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c +index f23a83c5e..a8263ba11 100644 +--- a/daemon/gdm-session.c ++++ b/daemon/gdm-session.c +@@ -1401,130 +1401,205 @@ gdm_session_handle_client_begin_verification_for_user (GdmDBusUserVerifier *u + static gboolean + gdm_session_handle_client_answer_query (GdmDBusUserVerifier *user_verifier_interface, + GDBusMethodInvocation *invocation, + const char *service_name, + const char *answer, + GdmSession *self) + { + gdm_dbus_user_verifier_complete_answer_query (user_verifier_interface, + invocation); + gdm_session_answer_query (self, service_name, answer); + return TRUE; + } + + static gboolean + gdm_session_handle_client_cancel (GdmDBusUserVerifier *user_verifier_interface, + GDBusMethodInvocation *invocation, + GdmSession *self) + { + gdm_dbus_user_verifier_complete_cancel (user_verifier_interface, + invocation); + gdm_session_cancel (self); + return TRUE; + } + + static gboolean + gdm_session_handle_client_select_session (GdmDBusGreeter *greeter_interface, + GDBusMethodInvocation *invocation, + const char *session, + GdmSession *self) + { ++ if (gdm_session_is_running (self)) { ++ const char *username; ++ ++ username = gdm_session_get_username (self); ++ g_debug ("GdmSession: refusing to select session %s since it's already running (for user %s)", ++ session, ++ username); ++ g_dbus_method_invocation_return_error (invocation, ++ G_DBUS_ERROR, ++ G_DBUS_ERROR_INVALID_ARGS, ++ "Session already running for user %s", ++ username); ++ return TRUE; ++ } ++ + if (self->priv->greeter_interface != NULL) { + gdm_dbus_greeter_complete_select_session (greeter_interface, + invocation); + } + gdm_session_select_session (self, session); + return TRUE; + } + + static gboolean + gdm_session_handle_client_select_user (GdmDBusGreeter *greeter_interface, + GDBusMethodInvocation *invocation, + const char *username, + GdmSession *self) + { ++ if (gdm_session_is_running (self)) { ++ const char *session_username; ++ ++ session_username = gdm_session_get_username (self); ++ g_debug ("GdmSession: refusing to select user %s, since session (%p) already running (for user %s)", ++ username, ++ self, ++ session_username); ++ g_dbus_method_invocation_return_error (invocation, ++ G_DBUS_ERROR, ++ G_DBUS_ERROR_INVALID_ARGS, ++ "Session already running for user %s", ++ session_username); ++ return TRUE; ++ } ++ + if (self->priv->greeter_interface != NULL) { + gdm_dbus_greeter_complete_select_user (greeter_interface, + invocation); + } + g_debug ("GdmSession: client selected user '%s' on session (%p)", username, self); + gdm_session_select_user (self, username); + return TRUE; + } + + static gboolean + gdm_session_handle_client_start_session_when_ready (GdmDBusGreeter *greeter_interface, + GDBusMethodInvocation *invocation, + const char *service_name, + gboolean client_is_ready, + GdmSession *self) + { ++ if (gdm_session_is_running (self)) { ++ const char *username; ++ ++ username = gdm_session_get_username (self); ++ g_debug ("GdmSession: refusing to start session (%p), since it's already running (for user %s)", ++ self, ++ username); ++ g_dbus_method_invocation_return_error (invocation, ++ G_DBUS_ERROR, ++ G_DBUS_ERROR_INVALID_ARGS, ++ "Session already running for user %s", ++ username); ++ return TRUE; ++ } + + if (self->priv->greeter_interface != NULL) { + gdm_dbus_greeter_complete_start_session_when_ready (greeter_interface, + invocation); + } + g_signal_emit (G_OBJECT (self), + signals [CLIENT_READY_FOR_SESSION_TO_START], + 0, + service_name, + client_is_ready); + return TRUE; + } + + static gboolean + gdm_session_handle_get_timed_login_details (GdmDBusGreeter *greeter_interface, + GDBusMethodInvocation *invocation, + GdmSession *self) + { ++ if (gdm_session_is_running (self)) { ++ const char *username; ++ ++ username = gdm_session_get_username (self); ++ g_debug ("GdmSession: refusing to give timed login details, session (%p) already running (for user %s)", ++ self, ++ username); ++ g_dbus_method_invocation_return_error (invocation, ++ G_DBUS_ERROR, ++ G_DBUS_ERROR_INVALID_ARGS, ++ "Session already running for user %s", ++ username); ++ return TRUE; ++ } + + if (self->priv->greeter_interface != NULL) { + gdm_dbus_greeter_complete_get_timed_login_details (greeter_interface, + invocation, + self->priv->timed_login_username != NULL, + self->priv->timed_login_username != NULL? self->priv->timed_login_username : "", + self->priv->timed_login_delay); + if (self->priv->timed_login_username != NULL) { + gdm_dbus_greeter_emit_timed_login_requested (self->priv->greeter_interface, + self->priv->timed_login_username, + self->priv->timed_login_delay); + } + } + return TRUE; + } + + static gboolean + gdm_session_handle_client_begin_auto_login (GdmDBusGreeter *greeter_interface, + GDBusMethodInvocation *invocation, + const char *username, + GdmSession *self) + { ++ const char *session_username; ++ ++ if (gdm_session_is_running (self)) { ++ session_username = gdm_session_get_username (self); ++ g_debug ("GdmSession: refusing auto login operation, session (%p) already running for user %s (%s requested)", ++ self, ++ session_username, ++ username); ++ g_dbus_method_invocation_return_error (invocation, ++ G_DBUS_ERROR, ++ G_DBUS_ERROR_INVALID_ARGS, ++ "Session already owned by user %s", ++ session_username); ++ return TRUE; ++ } ++ + if (self->priv->greeter_interface != NULL) { + gdm_dbus_greeter_complete_begin_auto_login (greeter_interface, + invocation); + } + + g_debug ("GdmSession: client requesting automatic login for user '%s' on session '%s' (%p)", + username, + gdm_session_get_session_id (self), + self); + + gdm_session_setup_for_user (self, "gdm-autologin", username); + + return TRUE; + } + + static void + export_user_verifier_interface (GdmSession *self, + GDBusConnection *connection) + { + GdmDBusUserVerifier *user_verifier_interface; + user_verifier_interface = GDM_DBUS_USER_VERIFIER (gdm_dbus_user_verifier_skeleton_new ()); + + g_object_set_data (G_OBJECT (connection), "gdm-session", self); + + g_signal_connect (user_verifier_interface, + "handle-enable-extensions", + G_CALLBACK (gdm_session_handle_client_enable_extensions), + connection); + g_signal_connect (user_verifier_interface, + "handle-begin-verification", +-- +2.21.0 + diff --git a/SOURCES/0003-session-worker-uninitialize-pam-if-worker-is-killed.patch b/SOURCES/0003-session-worker-uninitialize-pam-if-worker-is-killed.patch new file mode 100644 index 0000000..e79e546 --- /dev/null +++ b/SOURCES/0003-session-worker-uninitialize-pam-if-worker-is-killed.patch @@ -0,0 +1,85 @@ +From 1987a539495f38ade3efc561f65b56316080356e Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Mon, 24 Jun 2019 16:21:59 -0400 +Subject: [PATCH 3/3] session-worker: uninitialize pam if worker is killed + +Right nowe don't uninitialize pam or switch back to the +starting VT if the worker is killed before the session. + +This commit fixes that. +--- + daemon/gdm-session-worker.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c +index aa288ac8e..0322037e0 100644 +--- a/daemon/gdm-session-worker.c ++++ b/daemon/gdm-session-worker.c +@@ -3552,60 +3552,64 @@ gdm_session_worker_init (GdmSessionWorker *worker) + static void + gdm_session_worker_unwatch_child (GdmSessionWorker *worker) + { + if (worker->priv->child_watch_id == 0) + return; + + g_source_remove (worker->priv->child_watch_id); + worker->priv->child_watch_id = 0; + } + + + static void + gdm_session_worker_finalize (GObject *object) + { + GdmSessionWorker *worker; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_SESSION_WORKER (object)); + + worker = GDM_SESSION_WORKER (object); + + g_return_if_fail (worker->priv != NULL); + + gdm_session_worker_unwatch_child (worker); + + if (worker->priv->child_pid > 0) { + gdm_signal_pid (worker->priv->child_pid, SIGTERM); + gdm_wait_on_pid (worker->priv->child_pid); + } + ++ if (worker->priv->pam_handle != NULL) { ++ gdm_session_worker_uninitialize_pam (worker, PAM_SUCCESS); ++ } ++ + g_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); + } +-- +2.18.1 + diff --git a/SOURCES/0004-GdmManager-Don-t-perform-timed-login-if-session-gets.patch b/SOURCES/0004-GdmManager-Don-t-perform-timed-login-if-session-gets.patch new file mode 100644 index 0000000..158e15a --- /dev/null +++ b/SOURCES/0004-GdmManager-Don-t-perform-timed-login-if-session-gets.patch @@ -0,0 +1,105 @@ +From 15a19ac7856c539aa9cfbf76997d18b0275aae35 Mon Sep 17 00:00:00 2001 +From: Iain Lane +Date: Mon, 4 Feb 2019 15:12:38 +0000 +Subject: [PATCH 4/4] GdmManager: Don't perform timed login if session gets + started + +At the moment it's possible for the login screen to initiate +a timed login operation shortly after a user successfully starts +their session. + +GDM won't complete the timed login operation, since a session is +already running, but will erroneously overwrite the username +associated with the session, misattributing the users session +to the timed login user. + +Later, attempts to log in as the timed user will instead unlock the +session for the other user, since that session is now associated +with the timed login user. + +This commit refuses timed login requests on sessions that are +already running, so the username doesn't get corrupted. + +CVE-2019-3825 + +Closes https://gitlab.gnome.org/GNOME/gdm/issues/460 +--- + daemon/gdm-manager.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c +index 0cc06a978..056560b20 100644 +--- a/daemon/gdm-manager.c ++++ b/daemon/gdm-manager.c +@@ -2116,60 +2116,68 @@ on_session_client_ready_for_session_to_start (GdmSession *session, + } else { + g_debug ("GdmManager: Will start session when ready and told"); + } + + waiting_to_start_user_session = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (session), + "waiting-to-start")); + + g_object_set_data (G_OBJECT (session), + "start-when-ready", + GINT_TO_POINTER (client_is_ready)); + + if (client_is_ready && waiting_to_start_user_session) { + start_user_session_if_ready (manager, session, service_name); + } + } + + static void + on_session_client_connected (GdmSession *session, + GCredentials *credentials, + GPid pid_of_client, + GdmManager *manager) + { + GdmDisplay *display; + char *username; + int delay; + gboolean enabled; + gboolean allow_timed_login = FALSE; + + g_debug ("GdmManager: client with pid %d connected", (int) pid_of_client); + ++ if (gdm_session_is_running (session)) { ++ const char *session_username; ++ session_username = gdm_session_get_username (session); ++ g_debug ("GdmManager: ignoring connection, since session already running (for user %s)", ++ session_username); ++ return; ++ } ++ + display = get_display_for_user_session (session); + + if (display == NULL) { + return; + } + + if (!display_is_on_seat0 (display)) { + return; + } + + #ifdef WITH_PLYMOUTH + if (manager->priv->plymouth_is_running) { + plymouth_quit_with_transition (); + manager->priv->plymouth_is_running = FALSE; + } + #endif + + g_object_get (G_OBJECT (display), "allow-timed-login", &allow_timed_login, NULL); + + if (!allow_timed_login) { + return; + } + + enabled = get_timed_login_details (manager, &username, &delay); + + if (! enabled) { + return; + } + + gdm_session_set_timed_login_details (session, username, delay); +-- +2.21.0 + diff --git a/SOURCES/0004-data-reap-gdm-sessions-on-shutdown.patch b/SOURCES/0004-data-reap-gdm-sessions-on-shutdown.patch new file mode 100644 index 0000000..d0c0451 --- /dev/null +++ b/SOURCES/0004-data-reap-gdm-sessions-on-shutdown.patch @@ -0,0 +1,28 @@ +From f32adbe9bf26d502cb055b3a6cb98fc57e06bf13 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Fri, 26 Jul 2019 14:06:16 -0400 +Subject: [PATCH 4/4] data: reap gdm sessions on shutdown + +If GDM gets shutdown we should make sure all sessions get shutdown too. + +This is a bit of a safety net in case any processes in the session are +lingering after the orderly shutdown. +--- + data/gdm.service.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/data/gdm.service.in b/data/gdm.service.in +index 72201c1fd..202ab6753 100644 +--- a/data/gdm.service.in ++++ b/data/gdm.service.in +@@ -21,6 +21,7 @@ OnFailure=plymouth-quit.service + + [Service] + ExecStart=@sbindir@/gdm ++ExecStopPost=-/usr/bin/bash -c 'for f in /run/systemd/sessions/*; do [ -f $f ] && /usr/bin/fgrep -q SERVICE=gdm $f && loginctl terminate-session $(basename $f); done' + KillMode=mixed + Restart=always + IgnoreSIGPIPE=no +-- +2.18.1 + diff --git a/SPECS/gdm.spec b/SPECS/gdm.spec index 3197b94..bfb96b1 100644 --- a/SPECS/gdm.spec +++ b/SPECS/gdm.spec @@ -10,35 +10,53 @@ Name: gdm Epoch: 1 Version: 3.28.3 -Release: 20%{?dist} +Release: 28%{?dist} Summary: The GNOME Display Manager License: GPLv2+ URL: https://wiki.gnome.org/Projects/GDM Source0: http://download.gnome.org/sources/gdm/3.28/gdm-%{version}.tar.xz Source1: org.gnome.login-screen.gschema.override -Patch0: 0001-Honor-initial-setup-being-disabled-by-distro-install.patch +Patch00001: 0001-Honor-initial-setup-being-disabled-by-distro-install.patch -Patch11: 0001-utils-add-new-gdm-disable-wayland-binary.patch +Patch10001: 0001-utils-add-new-gdm-disable-wayland-binary.patch -Patch31: 0001-display-access-file-drop-unused-function.patch +Patch20001: 0001-display-access-file-drop-unused-function.patch -Patch41: 0001-data-disable-wayland-for-proprietary-nvidia-machines.patch -Patch42: 0001-data-disable-wayland-for-legacy-QXL-VMs.patch -Patch43: 0001-data-disable-wayland-on-server-chips-and-dual-gpu-se.patch +Patch30001: 0001-data-disable-wayland-for-proprietary-nvidia-machines.patch +Patch30002: 0001-data-disable-wayland-on-server-chips-and-dual-gpu-se.patch +Patch30003: 0001-data-enable-wayland-on-cirrus.patch +Patch30004: 0001-data-only-disable-wayland-on-passthrough-virt-setups.patch -Patch51: 0001-local-display-factory-pause-for-a-few-seconds-before.patch +Patch40001: 0001-local-display-factory-pause-for-a-few-seconds-before.patch -Patch61: 0001-manager-ensure-is-initial-is-transfered-to-autologin.patch +Patch50001: 0001-manager-ensure-is-initial-is-transfered-to-autologin.patch -Patch71: 0001-session-ensure-login-screen-over-XDMCP-connects-to-i.patch +Patch60001: 0001-session-ensure-login-screen-over-XDMCP-connects-to-i.patch -Patch81: 0001-worker-don-t-load-user-settings-for-program-sessions.patch -Patch82: 0002-session-support-new-accountsservice-Session-and-Sess.patch -Patch83: 0003-daemon-save-os-release-in-accountsservice.patch -Patch84: 0004-daemon-handle-upgrades-from-RHEL-7.patch +Patch70001: 0001-worker-don-t-load-user-settings-for-program-sessions.patch +Patch70002: 0002-session-support-new-accountsservice-Session-and-Sess.patch +Patch70003: 0003-daemon-save-os-release-in-accountsservice.patch +Patch70004: 0004-daemon-handle-upgrades-from-RHEL-7.patch -Patch99: system-dconf.patch +Patch80001: 0001-session-worker-expose-worker-state-enum-to-type-syst.patch +Patch80002: 0002-session-worker-kill-user-sessions-when-stop-gdm-serv.patch +Patch80003: 0003-session-worker-uninitialize-pam-if-worker-is-killed.patch +Patch80004: 0004-data-reap-gdm-sessions-on-shutdown.patch + +# CVE-2019-3825 +Patch90001: 0001-manager-don-t-kill-timed-login-session-immediately-a.patch +Patch90002: 0002-manager-session-Add-some-debugging-around-starting-r.patch +Patch90003: 0003-session-Don-t-allow-greeter-operations-on-an-running.patch +Patch90004: 0004-GdmManager-Don-t-perform-timed-login-if-session-gets.patch + +Patch100001: 0001-manager-allow-multiple-xdmcp-logins-for-the-same-use.patch + +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 BuildRequires: pam-devel >= 0:%{pam_version} BuildRequires: desktop-file-utils >= %{desktop_file_utils_version} @@ -192,6 +210,8 @@ mkdir -p %{buildroot}%{_datadir}/gdm/autostart/LoginWindow mkdir -p %{buildroot}/run/gdm +rm -f %{buildroot}%{_bindir}/gdm-screenshot + find %{buildroot} -name '*.a' -delete find %{buildroot} -name '*.la' -delete @@ -293,7 +313,6 @@ fi %{_libexecdir}/gdm-x-session %{_sbindir}/gdm %{_bindir}/gdmflexiserver -%{_bindir}/gdm-screenshot %dir %{_datadir}/dconf %dir %{_datadir}/dconf/profile %{_datadir}/dconf/profile/gdm @@ -337,6 +356,43 @@ fi %{_libdir}/pkgconfig/gdm-pam-extensions.pc %changelog +* Sun Dec 15 2019 Ray Strode - 3.28.3-28 +- Correct wayland session detection logic when deciding + whether or not to run Xsession script + Resolves: #1728330 + +* Sun Dec 15 2019 Ray Strode - 3.28.3-27 +- Don't run initial-setup for machines enrolled in IPA setup. + Resolves: #1750516 + +* Fri Dec 13 2019 Ray Strode - 3.28.3-26 +- Forward port RHEL 7 patch to allow multiple logins for the + same user with XDMCP connections. + Resolves: #1710882 + +* Thu Dec 12 2019 Ray Strode - 3.28.3-25 +- Reenable wayland on hybrid setups (except virt pass through) + Resolves: #1749960 +- Reenable wayland on qxl + Resolves: #1744452 + +* Fri Dec 06 2019 Ray Strode - 3.28.3-24 +- Reenable wayland on cirrus + Resolves: #1744527 + +* Thu Nov 21 2019 Ray Strode - 3.28.3-23 +- Correct timedlogin based screenlock bypass + Resolves: #1672829 + +* Mon Jun 24 2019 Ray Strode - 3.28.3-22 +- Ensure user session is killed with its worker and that all + user sessions are cleaned up on shutdown + Resolves: #1690714 + +* Mon Jun 17 2019 Ray Strode - 3.28.3-21 +- Drop gdm-screenshot + Resolves: #1680164 + * Mon Feb 11 2019 Ray Strode - 3.28.3-20 - Disable wayland on hybrid gpu machines, and server machines again