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

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