From ab06d95076705cdaee9945adb2e22ac75be72952 Mon Sep 17 00:00:00 2001 From: Ray Strode 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