Blame SOURCES/0043-gdm-session-worker-Drop-login_vt-assuming-it-is-GDM_.patch

c90517
From 9d3d6d5b4ebe604959d2d718cefd658a85195409 Mon Sep 17 00:00:00 2001
c90517
From: Benjamin Berg <bberg@redhat.com>
c90517
Date: Wed, 25 Sep 2019 14:51:40 +0200
c90517
Subject: [PATCH 43/48] gdm-session-worker: Drop login_vt assuming it is
c90517
 GDM_INITIAL_VT
c90517
c90517
When a session ends, its "session worker" is closed. Since
c90517
3e8220921bb608afd06ed677104fd2244b901a28 (3.33.4), we uninitialise PAM
c90517
when this happens. As part of this procedure, we jump back to the login
c90517
screen, if the screen being killed is not itself the login screen.
c90517
c90517
This has broken fast user switching. It goes like this - this
c90517
explanation is a bit complicated, bear with us:
c90517
c90517
We want to jump back to the login screen when a normal user session
c90517
ends, so that people can log in again. We do not want to do this when a
c90517
login screen itself ends. When session workers start up, they query for
c90517
the *currently active VT* and save this in `login_vt`. Then later on, we
c90517
check if our session ID is the same as `login_vt`, and jump to
c90517
`login_vt` if they are different - this means that it was a user session
c90517
not a login session. Querying the currently active VT is fine for the
c90517
first greeter, but when initiating a user switch it's wrong as this
c90517
gives the user VT.
c90517
c90517
GDM greeters are killed once they have spawned a session. They are
c90517
associated with a logind session, and therefore a PAM session. There are
c90517
some actions performed when unregistering PAM sessions, including the
c90517
previously mentioned VT jump. Before
c90517
3e8220921bb608afd06ed677104fd2244b901a28 we only uninitialised PAM when
c90517
the session itself exited so the bug was masked, but now (since this
c90517
commit), if the login screen's *worker* exits first - as happens in the
c90517
normal case when GDM kills it - we also do this uninitialisation. Since
c90517
we falsely recorded the login screen as the first user's VT, this means
c90517
that checking `login_vt != session_vt` returns `TRUE` and we jump back
c90517
to the previous user's session immediately after logging into the new
c90517
session: fast user switching is broken.
c90517
c90517
Since the work on shutting down the GDM session has been finished, we
c90517
can assume that the login_vt is always on GDM_INITIAL_VT (see
c90517
example c71bc5d6c3bc2ec448b5c72ce9a811d9c0c7905e
c90517
"local-display-factory: Remove initial VT is in use check" and
c90517
39fb4ff64e6a0653e70a3bfab31da47b49227d59 "manager: don't run autologin
c90517
display on tty1"). So simply replace all usages of login_vt with
c90517
GDM_INITIAL_VT to solve the above problem.
c90517
c90517
Note that in the case where ENABLE_USER_DISPLAY_SERVER is not enabled,
c90517
the login_vt is always the same as the session_vt. We can simply remove
c90517
the VT switching magic there and everything should be working as
c90517
expected.
c90517
c90517
This is a simpler version of the patch by Iain Lane <iainl@gnome.org>,
c90517
taking into account that we can make the assumption about the login_vt.
c90517
c90517
Closes #515
c90517
---
c90517
 daemon/gdm-session-worker.c | 43 +++++++++----------------------------
c90517
 1 file changed, 10 insertions(+), 33 deletions(-)
c90517
c90517
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
c90517
index b4befaa83..0bd78cfaf 100644
c90517
--- a/daemon/gdm-session-worker.c
c90517
+++ b/daemon/gdm-session-worker.c
c90517
@@ -119,61 +119,60 @@ typedef struct
c90517
 
c90517
 } ReauthenticationRequest;
c90517
 
c90517
 struct GdmSessionWorkerPrivate
c90517
 {
c90517
         GdmSessionWorkerState state;
c90517
 
c90517
         int               exit_code;
c90517
 
c90517
         pam_handle_t     *pam_handle;
c90517
 
c90517
         GPid              child_pid;
c90517
         guint             child_watch_id;
c90517
 
c90517
         /* from Setup */
c90517
         char             *service;
c90517
         char             *x11_display_name;
c90517
         char             *x11_authority_file;
c90517
         char             *display_device;
c90517
         char             *display_seat_id;
c90517
         char             *hostname;
c90517
         char             *username;
c90517
         char             *log_file;
c90517
         char             *session_id;
c90517
         uid_t             uid;
c90517
         gid_t             gid;
c90517
         gboolean          password_is_required;
c90517
         char            **extensions;
c90517
 
c90517
         int               cred_flags;
c90517
-        int               login_vt;
c90517
         int               session_vt;
c90517
         int               session_tty_fd;
c90517
 
c90517
         char            **arguments;
c90517
         guint32           cancelled : 1;
c90517
         guint32           timed_out : 1;
c90517
         guint32           is_program_session : 1;
c90517
         guint32           is_reauth_session : 1;
c90517
         guint32           display_is_local : 1;
c90517
         guint32           display_is_initial : 1;
c90517
         guint             state_change_idle_id;
c90517
         GdmSessionDisplayMode display_mode;
c90517
 
c90517
         char                 *server_address;
c90517
         GDBusConnection      *connection;
c90517
         GdmDBusWorkerManager *manager;
c90517
 
c90517
         GHashTable         *reauthentication_requests;
c90517
 
c90517
         GdmSessionAuditor  *auditor;
c90517
         GdmSessionSettings *user_settings;
c90517
 
c90517
         GDBusMethodInvocation *pending_invocation;
c90517
 };
c90517
 
c90517
 #ifdef SUPPORTS_PAM_EXTENSIONS
c90517
 static char gdm_pam_extension_environment_block[_POSIX_ARG_MAX];
c90517
 
c90517
 static const char * const
c90517
 gdm_supported_pam_extensions[] = {
c90517
@@ -1029,141 +1028,120 @@ gdm_session_worker_set_state (GdmSessionWorker      *worker,
c90517
 
c90517
 static void
c90517
 gdm_session_worker_uninitialize_pam (GdmSessionWorker *worker,
c90517
                                      int               status)
c90517
 {
c90517
         g_debug ("GdmSessionWorker: uninitializing PAM");
c90517
 
c90517
         if (worker->priv->pam_handle == NULL)
c90517
                 return;
c90517
 
c90517
         gdm_session_worker_get_username (worker, NULL);
c90517
 
c90517
         if (worker->priv->state >= GDM_SESSION_WORKER_STATE_SESSION_OPENED) {
c90517
                 pam_close_session (worker->priv->pam_handle, 0);
c90517
                 gdm_session_auditor_report_logout (worker->priv->auditor);
c90517
         } else {
c90517
                 gdm_session_auditor_report_login_failure (worker->priv->auditor,
c90517
                                                           status,
c90517
                                                           pam_strerror (worker->priv->pam_handle, status));
c90517
         }
c90517
 
c90517
         if (worker->priv->state >= GDM_SESSION_WORKER_STATE_ACCREDITED) {
c90517
                 pam_setcred (worker->priv->pam_handle, PAM_DELETE_CRED);
c90517
         }
c90517
 
c90517
         pam_end (worker->priv->pam_handle, status);
c90517
         worker->priv->pam_handle = NULL;
c90517
 
c90517
         gdm_session_worker_stop_auditor (worker);
c90517
 
c90517
+        /* If user-display-server is not enabled the login_vt is always
c90517
+         * identical to the session_vt. So in that case we never need to
c90517
+         * do a VT switch. */
c90517
+#ifdef ENABLE_USER_DISPLAY_SERVER
c90517
         if (g_strcmp0 (worker->priv->display_seat_id, "seat0") == 0) {
c90517
-                if (worker->priv->login_vt != worker->priv->session_vt) {
c90517
-                        jump_to_vt (worker, worker->priv->login_vt);
c90517
+                /* Switch to the login VT if we are not the login screen. */
c90517
+                if (worker->priv->session_vt != GDM_INITIAL_VT) {
c90517
+                        jump_to_vt (worker, GDM_INITIAL_VT);
c90517
                 }
c90517
         }
c90517
+#endif
c90517
 
c90517
-        worker->priv->login_vt = 0;
c90517
         worker->priv->session_vt = 0;
c90517
 
c90517
         g_debug ("GdmSessionWorker: state NONE");
c90517
         gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_NONE);
c90517
 }
c90517
 
c90517
 static char *
c90517
 _get_tty_for_pam (const char *x11_display_name,
c90517
                   const char *display_device)
c90517
 {
c90517
 #ifdef __sun
c90517
         return g_strdup (display_device);
c90517
 #else
c90517
         return g_strdup (x11_display_name);
c90517
 #endif
c90517
 }
c90517
 
c90517
 #ifdef PAM_XAUTHDATA
c90517
 static struct pam_xauth_data *
c90517
 _get_xauth_for_pam (const char *x11_authority_file)
c90517
 {
c90517
         FILE                  *fh;
c90517
         Xauth                 *auth = NULL;
c90517
         struct pam_xauth_data *retval = NULL;
c90517
         gsize                  len = sizeof (*retval) + 1;
c90517
 
c90517
         fh = fopen (x11_authority_file, "r");
c90517
         if (fh) {
c90517
                 auth = XauReadAuth (fh);
c90517
                 fclose (fh);
c90517
         }
c90517
         if (auth) {
c90517
                 len += auth->name_length + auth->data_length;
c90517
                 retval = g_malloc0 (len);
c90517
         }
c90517
         if (retval) {
c90517
                 retval->namelen = auth->name_length;
c90517
                 retval->name = (char *) (retval + 1);
c90517
                 memcpy (retval->name, auth->name, auth->name_length);
c90517
                 retval->datalen = auth->data_length;
c90517
                 retval->data = retval->name + auth->name_length + 1;
c90517
                 memcpy (retval->data, auth->data, auth->data_length);
c90517
         }
c90517
         XauDisposeAuth (auth);
c90517
         return retval;
c90517
 }
c90517
 #endif
c90517
 
c90517
-static gboolean
c90517
-ensure_login_vt (GdmSessionWorker *worker)
c90517
-{
c90517
-        int fd;
c90517
-        struct vt_stat vt_state = { 0 };
c90517
-        gboolean got_login_vt = FALSE;
c90517
-
c90517
-        fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
c90517
-
c90517
-        if (fd < 0) {
c90517
-                g_debug ("GdmSessionWorker: couldn't open VT master: %m");
c90517
-                return FALSE;
c90517
-        }
c90517
-
c90517
-        if (ioctl (fd, VT_GETSTATE, &vt_state) < 0) {
c90517
-                g_debug ("GdmSessionWorker: couldn't get current VT: %m");
c90517
-                goto out;
c90517
-        }
c90517
-
c90517
-        worker->priv->login_vt = vt_state.v_active;
c90517
-        got_login_vt = TRUE;
c90517
-out:
c90517
-        close (fd);
c90517
-        return got_login_vt;
c90517
-}
c90517
-
c90517
 static gboolean
c90517
 gdm_session_worker_initialize_pam (GdmSessionWorker   *worker,
c90517
                                    const char         *service,
c90517
                                    const char * const *extensions,
c90517
                                    const char         *username,
c90517
                                    const char         *hostname,
c90517
                                    gboolean            display_is_local,
c90517
                                    const char         *x11_display_name,
c90517
                                    const char         *x11_authority_file,
c90517
                                    const char         *display_device,
c90517
                                    const char         *seat_id,
c90517
                                    GError            **error)
c90517
 {
c90517
         struct pam_conv        pam_conversation;
c90517
         int                    error_code;
c90517
         char tty_string[256];
c90517
 
c90517
         g_assert (worker->priv->pam_handle == NULL);
c90517
 
c90517
         g_debug ("GdmSessionWorker: initializing PAM; service=%s username=%s seat=%s",
c90517
                  service ? service : "(null)",
c90517
                  username ? username : "(null)",
c90517
                  seat_id ? seat_id : "(null)");
c90517
 
c90517
 #ifdef SUPPORTS_PAM_EXTENSIONS
c90517
         if (extensions != NULL) {
c90517
                 GDM_PAM_EXTENSION_ADVERTISE_SUPPORTED_EXTENSIONS (gdm_pam_extension_environment_block, extensions);
c90517
         }
c90517
 #endif
c90517
 
c90517
@@ -1204,64 +1182,63 @@ gdm_session_worker_initialize_pam (GdmSessionWorker   *worker,
c90517
         }
c90517
 
c90517
         /* set RHOST */
c90517
         if (hostname != NULL && hostname[0] != '\0') {
c90517
                 error_code = pam_set_item (worker->priv->pam_handle, PAM_RHOST, hostname);
c90517
                 g_debug ("error informing authentication system of user's hostname %s: %s",
c90517
                          hostname,
c90517
                          pam_strerror (worker->priv->pam_handle, error_code));
c90517
 
c90517
                 if (error_code != PAM_SUCCESS) {
c90517
                         g_set_error (error,
c90517
                                      GDM_SESSION_WORKER_ERROR,
c90517
                                      GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
c90517
                                      "%s", "");
c90517
                         goto out;
c90517
                 }
c90517
         }
c90517
 
c90517
         /* set seat ID */
c90517
         if (seat_id != NULL && seat_id[0] != '\0') {
c90517
                 gdm_session_worker_set_environment_variable (worker, "XDG_SEAT", seat_id);
c90517
         }
c90517
 
c90517
         if (strcmp (service, "gdm-launch-environment") == 0) {
c90517
                 gdm_session_worker_set_environment_variable (worker, "XDG_SESSION_CLASS", "greeter");
c90517
         }
c90517
 
c90517
         g_debug ("GdmSessionWorker: state SETUP_COMPLETE");
c90517
         gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE);
c90517
 
c90517
-        /* Temporarily set PAM_TTY with the currently active VT (login screen) 
c90517
+        /* Temporarily set PAM_TTY with the login VT,
c90517
            PAM_TTY will be reset with the users VT right before the user session is opened */
c90517
-        ensure_login_vt (worker);
c90517
-        g_snprintf (tty_string, 256, "/dev/tty%d", worker->priv->login_vt);
c90517
+        g_snprintf (tty_string, 256, "/dev/tty%d", GDM_INITIAL_VT);
c90517
         pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string);
c90517
         if (!display_is_local)
c90517
                 worker->priv->password_is_required = TRUE;
c90517
 
c90517
  out:
c90517
         if (error_code != PAM_SUCCESS) {
c90517
                 gdm_session_worker_uninitialize_pam (worker, error_code);
c90517
                 return FALSE;
c90517
         }
c90517
 
c90517
         return TRUE;
c90517
 }
c90517
 
c90517
 static gboolean
c90517
 gdm_session_worker_authenticate_user (GdmSessionWorker *worker,
c90517
                                       gboolean          password_is_required,
c90517
                                       GError          **error)
c90517
 {
c90517
         int error_code;
c90517
         int authentication_flags;
c90517
 
c90517
         g_debug ("GdmSessionWorker: authenticating user %s", worker->priv->username);
c90517
 
c90517
         authentication_flags = 0;
c90517
 
c90517
         if (password_is_required) {
c90517
                 authentication_flags |= PAM_DISALLOW_NULL_AUTHTOK;
c90517
         }
c90517
 
c90517
         /* blocking call, does the actual conversation */
c90517
-- 
c90517
2.26.0
c90517