[gdm/wip/kill-user-session: 2/3] session-worker: kill user sessions when stopping gdm service



commit 039e3422f4764dbdf105244a174da061d4e38344
Author: Xiaoguang Wang <xwang suse com>
Date:   Thu May 16 13:26:16 2019 +0800

    session-worker: kill user sessions when stopping 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 27d1ff5e..584183bc 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -186,6 +186,7 @@ enum {
         PROP_0,
         PROP_SERVER_ADDRESS,
         PROP_IS_REAUTH_SESSION,
+        PROP_STATE,
 };
 
 static void     gdm_session_worker_class_init   (GdmSessionWorkerClass *klass);
@@ -1010,6 +1011,17 @@ jump_to_vt (GdmSessionWorker  *worker,
         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)
@@ -1049,7 +1061,7 @@ gdm_session_worker_uninitialize_pam (GdmSessionWorker *worker,
         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 *
@@ -1212,7 +1224,7 @@ gdm_session_worker_initialize_pam (GdmSessionWorker   *worker,
         }
 
         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 */
@@ -1278,7 +1290,7 @@ gdm_session_worker_authenticate_user (GdmSessionWorker *worker,
         }
 
         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) {
@@ -1343,7 +1355,7 @@ gdm_session_worker_authorize_user (GdmSessionWorker *worker,
         }
 
         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) {
@@ -1756,7 +1768,7 @@ gdm_session_worker_accredit_user (GdmSessionWorker  *worker,
 
                 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);
         }
@@ -2185,7 +2197,7 @@ gdm_session_worker_start_session (GdmSessionWorker  *worker,
         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);
 
@@ -2408,7 +2420,7 @@ gdm_session_worker_open_session (GdmSessionWorker  *worker,
         }
 
         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");
 
@@ -2485,7 +2497,7 @@ gdm_session_worker_get_property (GObject    *object,
                 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);
@@ -2670,7 +2682,7 @@ 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 (!gdm_session_settings_save (worker->priv->user_settings,
                                         worker->priv->username)) {
                 g_warning ("could not save session and language settings");
@@ -3463,6 +3475,15 @@ gdm_session_worker_class_init (GdmSessionWorkerClass *klass)
                                                                "is reauth session",
                                                               FALSE,
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT | 
G_PARAM_STATIC_STRINGS));
+
+        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
diff --git a/daemon/session-worker-main.c b/daemon/session-worker-main.c
index 4a3a8ebb..d96844d2 100644
--- a/daemon/session-worker-main.c
+++ b/daemon/session-worker-main.c
@@ -64,6 +64,31 @@ is_debug_set (void)
         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)
 {
@@ -124,11 +149,19 @@ main (int    argc,
 
         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);
         }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]