Blob Blame History Raw
From ab06d95076705cdaee9945adb2e22ac75be72952 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 29 Aug 2019 09:34:04 -0400
Subject: [PATCH 7/7] daemon: run PostSession script from mnager not worker

After a user logs out, the session worker baby sitting
the session, may optionally run admin provided PostSession
scripts.

Those scripts aren't getting reliably run on reboots, because
systemd kills the worker prematurely.

There's no easy way to prevent this... the worker is part of
the user session and user sessions are terminated immediately
at shutdown time.

This commit moves PostSession handling to the daemon process,
where it can happen unimpeded by session bring down.

This also makes the scripts more reliable in other potential
cases where the worker is killed explicitly.
---
 daemon/gdm-manager.c        | 40 +++++++++++++++++++++++++++++++++++++
 daemon/gdm-session-worker.c |  3 ---
 2 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 779b716be..d31c9d718 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1933,70 +1933,107 @@ on_user_session_opened (GdmSession       *session,
                                                       g_object_ref (session));
         if (g_strcmp0 (service_name, "gdm-autologin") == 0 &&
             !gdm_session_client_is_connected (session)) {
                 /* If we're auto logging in then don't wait for the go-ahead from a greeter,
                  * (since there is no greeter) */
                 g_object_set_data (G_OBJECT (session), "start-when-ready", GINT_TO_POINTER (TRUE));
         }
 
         start_user_session_if_ready (manager, session, service_name);
 }
 
 static void
 on_user_session_started (GdmSession      *session,
                          const char      *service_name,
                          GPid             pid,
                          GdmManager      *manager)
 {
         g_debug ("GdmManager: session started %d", pid);
         add_session_record (manager, session, pid, SESSION_RECORD_LOGIN);
 
 #ifdef WITH_PLYMOUTH
         if (g_strcmp0 (service_name, "gdm-autologin") == 0) {
                 if (manager->priv->plymouth_is_running) {
                         g_timeout_add_seconds (20, (GSourceFunc) plymouth_quit_with_transition, NULL);
                         manager->priv->plymouth_is_running = FALSE;
                 }
         }
 #endif
 }
 
+static void
+run_post_session_script (GdmSession *session)
+{
+        GPid pid;
+        GdmDisplay *display;
+        gboolean display_is_local = FALSE;
+        const char *username;
+        g_autofree char *display_name = NULL, *remote_hostname = NULL, *display_auth_file = NULL;
+
+        display = get_display_for_user_session (session);
+
+        if (display == NULL)
+                return;
+
+        pid = gdm_session_get_pid (session);
+
+        if (pid <= 0)
+                return;
+
+        username = gdm_session_get_username (session);
+
+        g_object_get (G_OBJECT (display),
+                      "x11-display-name", &display_name,
+                      "is-local", &display_is_local,
+                      "remote-hostname", &remote_hostname,
+                      "x11-authority-file", &display_auth_file,
+                      NULL);
+
+        gdm_run_script (GDMCONFDIR "/PostSession",
+                        username,
+                        display_name,
+                        display_is_local? NULL : remote_hostname,
+                        display_auth_file);
+}
+
 static void
 remove_user_session (GdmManager *manager,
                      GdmSession *session)
 {
         GList *node;
         GdmDisplay *display;
 
         display = get_display_for_user_session (session);
 
         if (display != NULL) {
+                run_post_session_script (session);
+
                 gdm_display_unmanage (display);
                 gdm_display_finish (display);
         }
 
         node = g_list_find (manager->priv->user_sessions, session);
 
         if (node != NULL) {
                 manager->priv->user_sessions = g_list_delete_link (manager->priv->user_sessions, node);
                 gdm_session_close (session);
                 g_object_unref (session);
         }
 }
 
 static void
 on_session_start_failed (GdmSession *session,
                          const char *service_name,
                          const char *message,
                          GdmManager *manager)
 {
         g_debug ("GdmManager: session failed to start: %s", message);
         remove_user_session (manager, session);
 }
 
 static void
 on_user_session_exited (GdmSession *session,
                         int         code,
                         GdmManager *manager)
 {
         GPid pid;
 
@@ -2753,60 +2790,63 @@ finish_display (const char *id,
         if (gdm_display_get_status (display) == GDM_DISPLAY_MANAGED)
                 gdm_display_unmanage (display);
         gdm_display_finish (display);
 }
 
 static void
 gdm_manager_dispose (GObject *object)
 {
         GdmManager *manager;
 
         g_return_if_fail (object != NULL);
         g_return_if_fail (GDM_IS_MANAGER (object));
 
         manager = GDM_MANAGER (object);
 
         g_return_if_fail (manager->priv != NULL);
 
         gdm_manager_stop (manager);
 
 #ifdef HAVE_LIBXDMCP
         g_clear_object (&manager->priv->xdmcp_factory);
 #endif
         g_clear_object (&manager->priv->local_factory);
         g_clear_pointer (&manager->priv->open_reauthentication_requests,
                          (GDestroyNotify)
                          g_hash_table_unref);
         g_clear_pointer (&manager->priv->transient_sessions,
                          (GDestroyNotify)
                          g_hash_table_unref);
 
+        g_list_foreach (manager->priv->user_sessions,
+                        (GFunc) run_post_session_script,
+                        NULL);
         g_list_foreach (manager->priv->user_sessions,
                         (GFunc) gdm_session_close,
                         NULL);
         g_list_free_full (manager->priv->user_sessions, (GDestroyNotify) g_object_unref);
         manager->priv->user_sessions = NULL;
 
         g_signal_handlers_disconnect_by_func (G_OBJECT (manager->priv->display_store),
                                               G_CALLBACK (on_display_added),
                                               manager);
         g_signal_handlers_disconnect_by_func (G_OBJECT (manager->priv->display_store),
                                               G_CALLBACK (on_display_removed),
                                               manager);
 
         if (!g_dbus_connection_is_closed (manager->priv->connection)) {
                 gdm_display_store_foreach (manager->priv->display_store,
                                            (GdmDisplayStoreFunc)unexport_display,
                                            manager);
                 g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (manager));
         }
 
         gdm_display_store_foreach (manager->priv->display_store,
                                    (GdmDisplayStoreFunc) finish_display,
                                    manager);
 
         gdm_display_store_clear (manager->priv->display_store);
 
         g_dbus_object_manager_server_set_connection (manager->priv->object_manager, NULL);
 
         g_clear_object (&manager->priv->connection);
         g_clear_object (&manager->priv->object_manager);
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 07117d857..b0861b971 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -1743,72 +1743,69 @@ gdm_session_worker_get_environment (GdmSessionWorker *worker)
 static gboolean
 run_script (GdmSessionWorker *worker,
             const char       *dir)
 {
         /* scripts are for non-program sessions only */
         if (worker->priv->is_program_session) {
                 return TRUE;
         }
 
         return gdm_run_script (dir,
                                worker->priv->username,
                                worker->priv->x11_display_name,
                                worker->priv->display_is_local? NULL : worker->priv->hostname,
                                worker->priv->x11_authority_file);
 }
 
 static void
 session_worker_child_watch (GPid              pid,
                             int               status,
                             GdmSessionWorker *worker)
 {
         g_debug ("GdmSessionWorker: child (pid:%d) done (%s:%d)",
                  (int) pid,
                  WIFEXITED (status) ? "status"
                  : WIFSIGNALED (status) ? "signal"
                  : "unknown",
                  WIFEXITED (status) ? WEXITSTATUS (status)
                  : WIFSIGNALED (status) ? WTERMSIG (status)
                  : -1);
 
-
         gdm_session_worker_uninitialize_pam (worker, PAM_SUCCESS);
 
         gdm_dbus_worker_emit_session_exited (GDM_DBUS_WORKER (worker),
                                              worker->priv->service,
                                              status);
-
         killpg (pid, SIGHUP);
 
         worker->priv->child_pid = -1;
         worker->priv->child_watch_id = 0;
-        run_script (worker, GDMCONFDIR "/PostSession");
 }
 
 static void
 gdm_session_worker_watch_child (GdmSessionWorker *worker)
 {
         g_debug ("GdmSession worker: watching pid %d", worker->priv->child_pid);
         worker->priv->child_watch_id = g_child_watch_add (worker->priv->child_pid,
                                                           (GChildWatchFunc)session_worker_child_watch,
                                                           worker);
 
 }
 
 static gboolean
 _is_loggable_file (const char* filename)
 {
         struct stat file_info;
 
         if (g_lstat (filename, &file_info) < 0) {
                 return FALSE;
         }
 
         return S_ISREG (file_info.st_mode) && g_access (filename, R_OK | W_OK) == 0;
 }
 
 static void
 rotate_logs (const char *path,
              guint       n_copies)
 {
         int i;
 
-- 
2.21.0