Blame SOURCES/0002-session-worker-kill-user-sessions-when-stopping-gdm-.patch

c4edd0
From 35a4d47385d043cf4df62c2723508e4edce4dfb4 Mon Sep 17 00:00:00 2001
c4edd0
From: Xiaoguang Wang <xwang@suse.com>
c4edd0
Date: Thu, 16 May 2019 13:26:16 +0800
c4edd0
Subject: [PATCH 2/7] session-worker: kill user sessions when stopping gdm
c4edd0
 service
c4edd0
c4edd0
At the moment the session worker exits as soon as it gets SIGTERM.
c4edd0
That means it may fail to stop the user session (which only happens
c4edd0
in the orderly shutdown path).
c4edd0
c4edd0
This commit sets up a SIGTERM handler that integrates with and
c4edd0
quits the main loop after the session is started.
c4edd0
c4edd0
It still retains the _exit-on-SIGTERM behavior before the session
c4edd0
is started, to ensure a stuck pam module doesn't prevent the
c4edd0
process from dying.
c4edd0
c4edd0
Some small changes to commit by Ray Strode.
c4edd0
c4edd0
Closes #400
c4edd0
---
c4edd0
 daemon/gdm-session-worker.c  | 38 +++++++++++++++++++++++++++---------
c4edd0
 daemon/session-worker-main.c | 33 +++++++++++++++++++++++++++++++
c4edd0
 2 files changed, 62 insertions(+), 9 deletions(-)
c4edd0
c4edd0
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
c4edd0
index d897779f3..e526fa5db 100644
c4edd0
--- a/daemon/gdm-session-worker.c
c4edd0
+++ b/daemon/gdm-session-worker.c
c4edd0
@@ -159,60 +159,61 @@ struct GdmSessionWorkerPrivate
c4edd0
         guint32           display_is_initial : 1;
c4edd0
         guint             state_change_idle_id;
c4edd0
         GdmSessionDisplayMode display_mode;
c4edd0
 
c4edd0
         char                 *server_address;
c4edd0
         GDBusConnection      *connection;
c4edd0
         GdmDBusWorkerManager *manager;
c4edd0
 
c4edd0
         GHashTable         *reauthentication_requests;
c4edd0
 
c4edd0
         GdmSessionAuditor  *auditor;
c4edd0
         GdmSessionSettings *user_settings;
c4edd0
 
c4edd0
         GDBusMethodInvocation *pending_invocation;
c4edd0
 };
c4edd0
 
c4edd0
 #ifdef SUPPORTS_PAM_EXTENSIONS
c4edd0
 static char gdm_pam_extension_environment_block[_POSIX_ARG_MAX];
c4edd0
 
c4edd0
 static const char * const
c4edd0
 gdm_supported_pam_extensions[] = {
c4edd0
         GDM_PAM_EXTENSION_CHOICE_LIST,
c4edd0
         NULL
c4edd0
 };
c4edd0
 #endif
c4edd0
 
c4edd0
 enum {
c4edd0
         PROP_0,
c4edd0
         PROP_SERVER_ADDRESS,
c4edd0
         PROP_IS_REAUTH_SESSION,
c4edd0
+        PROP_STATE,
c4edd0
 };
c4edd0
 
c4edd0
 static void     gdm_session_worker_class_init   (GdmSessionWorkerClass *klass);
c4edd0
 static void     gdm_session_worker_init         (GdmSessionWorker      *session_worker);
c4edd0
 static void     gdm_session_worker_finalize     (GObject               *object);
c4edd0
 
c4edd0
 static void     gdm_session_worker_set_environment_variable (GdmSessionWorker *worker,
c4edd0
                                                              const char       *key,
c4edd0
                                                              const char       *value);
c4edd0
 
c4edd0
 static void     queue_state_change              (GdmSessionWorker      *worker);
c4edd0
 
c4edd0
 static void     worker_interface_init           (GdmDBusWorkerIface *iface);
c4edd0
 
c4edd0
 
c4edd0
 typedef int (* GdmSessionWorkerPamNewMessagesFunc) (int,
c4edd0
                                                     const struct pam_message **,
c4edd0
                                                     struct pam_response **,
c4edd0
                                                     gpointer);
c4edd0
 
c4edd0
 G_DEFINE_TYPE_WITH_CODE (GdmSessionWorker,
c4edd0
                          gdm_session_worker,
c4edd0
                          GDM_DBUS_TYPE_WORKER_SKELETON,
c4edd0
                          G_IMPLEMENT_INTERFACE (GDM_DBUS_TYPE_WORKER,
c4edd0
                                                 worker_interface_init))
c4edd0
 
c4edd0
 /* adapted from glib script_execute */
c4edd0
 static void
c4edd0
 script_execute (const gchar *file,
c4edd0
                 char       **argv,
c4edd0
@@ -966,100 +967,111 @@ jump_to_vt (GdmSessionWorker  *worker,
c4edd0
 
c4edd0
                 g_debug ("GdmSessionWorker: first setting graphics mode to prevent flicker");
c4edd0
                 if (ioctl (fd, KDSETMODE, KD_GRAPHICS) < 0) {
c4edd0
                         g_debug ("GdmSessionWorker: couldn't set graphics mode: %m");
c4edd0
                 }
c4edd0
 
c4edd0
                 /* It's possible that the current VT was left in a broken
c4edd0
                  * combination of states (KD_GRAPHICS with VT_AUTO), that
c4edd0
                  * can't be switched away from.  This call makes sure things
c4edd0
                  * are set in a way that VT_ACTIVATE should work and
c4edd0
                  * VT_WAITACTIVE shouldn't hang.
c4edd0
                  */
c4edd0
                 fix_terminal_vt_mode (worker, active_vt_tty_fd);
c4edd0
         } else {
c4edd0
                 fd = active_vt_tty_fd;
c4edd0
         }
c4edd0
 
c4edd0
         handle_terminal_vt_switches (worker, fd);
c4edd0
 
c4edd0
         if (ioctl (fd, VT_ACTIVATE, vt_number) < 0) {
c4edd0
                 g_debug ("GdmSessionWorker: couldn't initiate jump to VT %d: %m",
c4edd0
                          vt_number);
c4edd0
         } else if (ioctl (fd, VT_WAITACTIVE, vt_number) < 0) {
c4edd0
                 g_debug ("GdmSessionWorker: couldn't finalize jump to VT %d: %m",
c4edd0
                          vt_number);
c4edd0
         }
c4edd0
 
c4edd0
         close (active_vt_tty_fd);
c4edd0
 }
c4edd0
 
c4edd0
+static void
c4edd0
+gdm_session_worker_set_state (GdmSessionWorker      *worker,
c4edd0
+                              GdmSessionWorkerState  state)
c4edd0
+{
c4edd0
+        if (worker->priv->state == state)
c4edd0
+                return;
c4edd0
+
c4edd0
+        worker->priv->state = state;
c4edd0
+        g_object_notify (G_OBJECT (worker), "state");
c4edd0
+}
c4edd0
+
c4edd0
 static void
c4edd0
 gdm_session_worker_uninitialize_pam (GdmSessionWorker *worker,
c4edd0
                                      int               status)
c4edd0
 {
c4edd0
         g_debug ("GdmSessionWorker: uninitializing PAM");
c4edd0
 
c4edd0
         if (worker->priv->pam_handle == NULL)
c4edd0
                 return;
c4edd0
 
c4edd0
         gdm_session_worker_get_username (worker, NULL);
c4edd0
 
c4edd0
         if (worker->priv->state >= GDM_SESSION_WORKER_STATE_SESSION_OPENED) {
c4edd0
                 pam_close_session (worker->priv->pam_handle, 0);
c4edd0
                 gdm_session_auditor_report_logout (worker->priv->auditor);
c4edd0
         } else {
c4edd0
                 gdm_session_auditor_report_login_failure (worker->priv->auditor,
c4edd0
                                                           status,
c4edd0
                                                           pam_strerror (worker->priv->pam_handle, status));
c4edd0
         }
c4edd0
 
c4edd0
         if (worker->priv->state >= GDM_SESSION_WORKER_STATE_ACCREDITED) {
c4edd0
                 pam_setcred (worker->priv->pam_handle, PAM_DELETE_CRED);
c4edd0
         }
c4edd0
 
c4edd0
         pam_end (worker->priv->pam_handle, status);
c4edd0
         worker->priv->pam_handle = NULL;
c4edd0
 
c4edd0
         gdm_session_worker_stop_auditor (worker);
c4edd0
 
c4edd0
         if (g_strcmp0 (worker->priv->display_seat_id, "seat0") == 0) {
c4edd0
                 if (worker->priv->login_vt != worker->priv->session_vt) {
c4edd0
                         jump_to_vt (worker, worker->priv->login_vt);
c4edd0
                 }
c4edd0
         }
c4edd0
 
c4edd0
         worker->priv->login_vt = 0;
c4edd0
         worker->priv->session_vt = 0;
c4edd0
 
c4edd0
         g_debug ("GdmSessionWorker: state NONE");
c4edd0
-        worker->priv->state = GDM_SESSION_WORKER_STATE_NONE;
c4edd0
+        gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_NONE);
c4edd0
 }
c4edd0
 
c4edd0
 static char *
c4edd0
 _get_tty_for_pam (const char *x11_display_name,
c4edd0
                   const char *display_device)
c4edd0
 {
c4edd0
 #ifdef __sun
c4edd0
         return g_strdup (display_device);
c4edd0
 #else
c4edd0
         return g_strdup (x11_display_name);
c4edd0
 #endif
c4edd0
 }
c4edd0
 
c4edd0
 #ifdef PAM_XAUTHDATA
c4edd0
 static struct pam_xauth_data *
c4edd0
 _get_xauth_for_pam (const char *x11_authority_file)
c4edd0
 {
c4edd0
         FILE                  *fh;
c4edd0
         Xauth                 *auth = NULL;
c4edd0
         struct pam_xauth_data *retval = NULL;
c4edd0
         gsize                  len = sizeof (*retval) + 1;
c4edd0
 
c4edd0
         fh = fopen (x11_authority_file, "r");
c4edd0
         if (fh) {
c4edd0
                 auth = XauReadAuth (fh);
c4edd0
                 fclose (fh);
c4edd0
         }
c4edd0
         if (auth) {
c4edd0
                 len += auth->name_length + auth->data_length;
c4edd0
                 retval = g_malloc0 (len);
c4edd0
@@ -1168,61 +1180,61 @@ gdm_session_worker_initialize_pam (GdmSessionWorker   *worker,
c4edd0
                         goto out;
c4edd0
                 }
c4edd0
         }
c4edd0
 
c4edd0
         /* set RHOST */
c4edd0
         if (hostname != NULL && hostname[0] != '\0') {
c4edd0
                 error_code = pam_set_item (worker->priv->pam_handle, PAM_RHOST, hostname);
c4edd0
                 g_debug ("error informing authentication system of user's hostname %s: %s",
c4edd0
                          hostname,
c4edd0
                          pam_strerror (worker->priv->pam_handle, error_code));
c4edd0
 
c4edd0
                 if (error_code != PAM_SUCCESS) {
c4edd0
                         g_set_error (error,
c4edd0
                                      GDM_SESSION_WORKER_ERROR,
c4edd0
                                      GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
c4edd0
                                      "%s", "");
c4edd0
                         goto out;
c4edd0
                 }
c4edd0
         }
c4edd0
 
c4edd0
         /* set seat ID */
c4edd0
         if (seat_id != NULL && seat_id[0] != '\0') {
c4edd0
                 gdm_session_worker_set_environment_variable (worker, "XDG_SEAT", seat_id);
c4edd0
         }
c4edd0
 
c4edd0
         if (strcmp (service, "gdm-launch-environment") == 0) {
c4edd0
                 gdm_session_worker_set_environment_variable (worker, "XDG_SESSION_CLASS", "greeter");
c4edd0
         }
c4edd0
 
c4edd0
         g_debug ("GdmSessionWorker: state SETUP_COMPLETE");
c4edd0
-        worker->priv->state = GDM_SESSION_WORKER_STATE_SETUP_COMPLETE;
c4edd0
+        gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE);
c4edd0
 
c4edd0
         /* Temporarily set PAM_TTY with the currently active VT (login screen) 
c4edd0
            PAM_TTY will be reset with the users VT right before the user session is opened */
c4edd0
         ensure_login_vt (worker);
c4edd0
         g_snprintf (tty_string, 256, "/dev/tty%d", worker->priv->login_vt);
c4edd0
         pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string);
c4edd0
         if (!display_is_local)
c4edd0
                 worker->priv->password_is_required = TRUE;
c4edd0
 
c4edd0
  out:
c4edd0
         if (error_code != PAM_SUCCESS) {
c4edd0
                 gdm_session_worker_uninitialize_pam (worker, error_code);
c4edd0
                 return FALSE;
c4edd0
         }
c4edd0
 
c4edd0
         return TRUE;
c4edd0
 }
c4edd0
 
c4edd0
 static gboolean
c4edd0
 gdm_session_worker_authenticate_user (GdmSessionWorker *worker,
c4edd0
                                       gboolean          password_is_required,
c4edd0
                                       GError          **error)
c4edd0
 {
c4edd0
         int error_code;
c4edd0
         int authentication_flags;
c4edd0
 
c4edd0
         g_debug ("GdmSessionWorker: authenticating user %s", worker->priv->username);
c4edd0
 
c4edd0
         authentication_flags = 0;
c4edd0
 
c4edd0
@@ -1233,61 +1245,61 @@ gdm_session_worker_authenticate_user (GdmSessionWorker *worker,
c4edd0
         /* blocking call, does the actual conversation */
c4edd0
         error_code = pam_authenticate (worker->priv->pam_handle, authentication_flags);
c4edd0
 
c4edd0
         if (error_code == PAM_AUTHINFO_UNAVAIL) {
c4edd0
                 g_debug ("GdmSessionWorker: authentication service unavailable");
c4edd0
 
c4edd0
                 g_set_error (error,
c4edd0
                              GDM_SESSION_WORKER_ERROR,
c4edd0
                              GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE,
c4edd0
                              "%s", "");
c4edd0
                 goto out;
c4edd0
         } else if (error_code != PAM_SUCCESS) {
c4edd0
                 g_debug ("GdmSessionWorker: authentication returned %d: %s", error_code, pam_strerror (worker->priv->pam_handle, error_code));
c4edd0
 
c4edd0
                 /*
c4edd0
                  * Do not display a different message for user unknown versus
c4edd0
                  * a failed password for a valid user.
c4edd0
                  */
c4edd0
                 if (error_code == PAM_USER_UNKNOWN) {
c4edd0
                         error_code = PAM_AUTH_ERR;
c4edd0
                 }
c4edd0
 
c4edd0
                 g_set_error (error,
c4edd0
                              GDM_SESSION_WORKER_ERROR,
c4edd0
                              GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
c4edd0
                              "%s", get_friendly_error_message (error_code));
c4edd0
                 goto out;
c4edd0
         }
c4edd0
 
c4edd0
         g_debug ("GdmSessionWorker: state AUTHENTICATED");
c4edd0
-        worker->priv->state = GDM_SESSION_WORKER_STATE_AUTHENTICATED;
c4edd0
+        gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_AUTHENTICATED);
c4edd0
 
c4edd0
  out:
c4edd0
         if (error_code != PAM_SUCCESS) {
c4edd0
                 gdm_session_worker_uninitialize_pam (worker, error_code);
c4edd0
                 return FALSE;
c4edd0
         }
c4edd0
 
c4edd0
         return TRUE;
c4edd0
 }
c4edd0
 
c4edd0
 static gboolean
c4edd0
 gdm_session_worker_authorize_user (GdmSessionWorker *worker,
c4edd0
                                    gboolean          password_is_required,
c4edd0
                                    GError          **error)
c4edd0
 {
c4edd0
         int error_code;
c4edd0
         int authentication_flags;
c4edd0
 
c4edd0
         g_debug ("GdmSessionWorker: determining if authenticated user (password required:%d) is authorized to session",
c4edd0
                  password_is_required);
c4edd0
 
c4edd0
         authentication_flags = 0;
c4edd0
 
c4edd0
         if (password_is_required) {
c4edd0
                 authentication_flags |= PAM_DISALLOW_NULL_AUTHTOK;
c4edd0
         }
c4edd0
 
c4edd0
         /* check that the account isn't disabled or expired
c4edd0
          */
c4edd0
         error_code = pam_acct_mgmt (worker->priv->pam_handle, authentication_flags);
c4edd0
@@ -1298,61 +1310,61 @@ gdm_session_worker_authorize_user (GdmSessionWorker *worker,
c4edd0
                 g_debug ("GdmSessionWorker: authenticated user requires new auth token");
c4edd0
                 error_code = pam_chauthtok (worker->priv->pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
c4edd0
 
c4edd0
                 gdm_session_worker_get_username (worker, NULL);
c4edd0
 
c4edd0
                 if (error_code != PAM_SUCCESS) {
c4edd0
                         gdm_session_auditor_report_password_change_failure (worker->priv->auditor);
c4edd0
                 } else {
c4edd0
                         gdm_session_auditor_report_password_changed (worker->priv->auditor);
c4edd0
                 }
c4edd0
         }
c4edd0
 
c4edd0
         /* If the user is reauthenticating, then authorization isn't required to
c4edd0
          * proceed, the user is already logged in after all.
c4edd0
          */
c4edd0
         if (worker->priv->is_reauth_session) {
c4edd0
                 error_code = PAM_SUCCESS;
c4edd0
         }
c4edd0
 
c4edd0
         if (error_code != PAM_SUCCESS) {
c4edd0
                 g_debug ("GdmSessionWorker: user is not authorized to log in: %s",
c4edd0
                          pam_strerror (worker->priv->pam_handle, error_code));
c4edd0
                 g_set_error (error,
c4edd0
                              GDM_SESSION_WORKER_ERROR,
c4edd0
                              GDM_SESSION_WORKER_ERROR_AUTHORIZING,
c4edd0
                              "%s", get_friendly_error_message (error_code));
c4edd0
                 goto out;
c4edd0
         }
c4edd0
 
c4edd0
         g_debug ("GdmSessionWorker: state AUTHORIZED");
c4edd0
-        worker->priv->state = GDM_SESSION_WORKER_STATE_AUTHORIZED;
c4edd0
+        gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_AUTHORIZED);
c4edd0
 
c4edd0
  out:
c4edd0
         if (error_code != PAM_SUCCESS) {
c4edd0
                 gdm_session_worker_uninitialize_pam (worker, error_code);
c4edd0
                 return FALSE;
c4edd0
         }
c4edd0
 
c4edd0
         return TRUE;
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 gdm_session_worker_set_environment_variable (GdmSessionWorker *worker,
c4edd0
                                              const char       *key,
c4edd0
                                              const char       *value)
c4edd0
 {
c4edd0
         int error_code;
c4edd0
         char *environment_entry;
c4edd0
 
c4edd0
         if (value != NULL) {
c4edd0
                 environment_entry = g_strdup_printf ("%s=%s", key, value);
c4edd0
         } else {
c4edd0
                 /* empty value means "remove from environment" */
c4edd0
                 environment_entry = g_strdup (key);
c4edd0
         }
c4edd0
 
c4edd0
         error_code = pam_putenv (worker->priv->pam_handle,
c4edd0
                                  environment_entry);
c4edd0
 
c4edd0
         if (error_code != PAM_SUCCESS) {
c4edd0
                 g_warning ("cannot put %s in pam environment: %s\n",
c4edd0
@@ -1710,61 +1722,61 @@ gdm_session_worker_accredit_user (GdmSessionWorker  *worker,
c4edd0
 
c4edd0
         /* If the user is reauthenticating and they've made it this far, then there
c4edd0
          * is no reason we should lock them out of their session.  They've already
c4edd0
          * proved they are they same person who logged in, and that's all we care
c4edd0
          * about.
c4edd0
          */
c4edd0
         if (worker->priv->is_reauth_session) {
c4edd0
                 error_code = PAM_SUCCESS;
c4edd0
         }
c4edd0
 
c4edd0
         if (error_code != PAM_SUCCESS) {
c4edd0
                 g_set_error (error,
c4edd0
                              GDM_SESSION_WORKER_ERROR,
c4edd0
                              GDM_SESSION_WORKER_ERROR_GIVING_CREDENTIALS,
c4edd0
                              "%s",
c4edd0
                              pam_strerror (worker->priv->pam_handle, error_code));
c4edd0
                 goto out;
c4edd0
         }
c4edd0
 
c4edd0
         ret = TRUE;
c4edd0
 
c4edd0
  out:
c4edd0
         g_free (home);
c4edd0
         g_free (shell);
c4edd0
         if (ret) {
c4edd0
                 g_debug ("GdmSessionWorker: state ACCREDITED");
c4edd0
                 ret = TRUE;
c4edd0
 
c4edd0
                 gdm_session_worker_get_username (worker, NULL);
c4edd0
                 gdm_session_auditor_report_user_accredited (worker->priv->auditor);
c4edd0
-                worker->priv->state = GDM_SESSION_WORKER_STATE_ACCREDITED;
c4edd0
+                gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_ACCREDITED);
c4edd0
         } else {
c4edd0
                 gdm_session_worker_uninitialize_pam (worker, error_code);
c4edd0
         }
c4edd0
 
c4edd0
         return ret;
c4edd0
 }
c4edd0
 
c4edd0
 static const char * const *
c4edd0
 gdm_session_worker_get_environment (GdmSessionWorker *worker)
c4edd0
 {
c4edd0
         return (const char * const *) pam_getenvlist (worker->priv->pam_handle);
c4edd0
 }
c4edd0
 
c4edd0
 static gboolean
c4edd0
 run_script (GdmSessionWorker *worker,
c4edd0
             const char       *dir)
c4edd0
 {
c4edd0
         /* scripts are for non-program sessions only */
c4edd0
         if (worker->priv->is_program_session) {
c4edd0
                 return TRUE;
c4edd0
         }
c4edd0
 
c4edd0
         return gdm_run_script (dir,
c4edd0
                                worker->priv->username,
c4edd0
                                worker->priv->x11_display_name,
c4edd0
                                worker->priv->display_is_local? NULL : worker->priv->hostname,
c4edd0
                                worker->priv->x11_authority_file);
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
@@ -2154,61 +2166,61 @@ gdm_session_worker_start_session (GdmSessionWorker  *worker,
c4edd0
                                      (char **)
c4edd0
                                      environment,
c4edd0
                                      TRUE);
c4edd0
 
c4edd0
                 gdm_log_init ();
c4edd0
                 g_debug ("GdmSessionWorker: child '%s' could not be started: %s",
c4edd0
                          worker->priv->arguments[0],
c4edd0
                          g_strerror (errno));
c4edd0
 
c4edd0
                 _exit (EXIT_FAILURE);
c4edd0
         }
c4edd0
 
c4edd0
         if (worker->priv->session_tty_fd > 0) {
c4edd0
                 close (worker->priv->session_tty_fd);
c4edd0
                 worker->priv->session_tty_fd = -1;
c4edd0
         }
c4edd0
 
c4edd0
         /* If we end up execing again, make sure we don't use the executable context set up
c4edd0
          * by pam_selinux durin pam_open_session
c4edd0
          */
c4edd0
 #ifdef HAVE_SELINUX
c4edd0
         setexeccon (NULL);
c4edd0
 #endif
c4edd0
 
c4edd0
         worker->priv->child_pid = session_pid;
c4edd0
 
c4edd0
         g_debug ("GdmSessionWorker: session opened creating reply...");
c4edd0
         g_assert (sizeof (GPid) <= sizeof (int));
c4edd0
 
c4edd0
         g_debug ("GdmSessionWorker: state SESSION_STARTED");
c4edd0
-        worker->priv->state = GDM_SESSION_WORKER_STATE_SESSION_STARTED;
c4edd0
+        gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SESSION_STARTED);
c4edd0
 
c4edd0
         gdm_session_worker_watch_child (worker);
c4edd0
 
c4edd0
  out:
c4edd0
         if (error_code != PAM_SUCCESS) {
c4edd0
                 gdm_session_worker_uninitialize_pam (worker, error_code);
c4edd0
                 return FALSE;
c4edd0
         }
c4edd0
 
c4edd0
         return TRUE;
c4edd0
 }
c4edd0
 
c4edd0
 static gboolean
c4edd0
 set_up_for_new_vt (GdmSessionWorker *worker)
c4edd0
 {
c4edd0
         int fd;
c4edd0
         char vt_string[256], tty_string[256];
c4edd0
         int session_vt = 0;
c4edd0
 
c4edd0
         fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
c4edd0
 
c4edd0
         if (fd < 0) {
c4edd0
                 g_debug ("GdmSessionWorker: couldn't open VT master: %m");
c4edd0
                 return FALSE;
c4edd0
         }
c4edd0
 
c4edd0
         if (worker->priv->display_is_initial) {
c4edd0
                 session_vt = atoi (GDM_INITIAL_VT);
c4edd0
         } else {
c4edd0
                 if (ioctl(fd, VT_OPENQRY, &session_vt) < 0) {
c4edd0
@@ -2377,61 +2389,61 @@ gdm_session_worker_open_session (GdmSessionWorker  *worker,
c4edd0
                 break;
c4edd0
         case GDM_SESSION_DISPLAY_MODE_NEW_VT:
c4edd0
         case GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED:
c4edd0
                 if (!set_up_for_new_vt (worker)) {
c4edd0
                         g_set_error (error,
c4edd0
                                      GDM_SESSION_WORKER_ERROR,
c4edd0
                                      GDM_SESSION_WORKER_ERROR_OPENING_SESSION,
c4edd0
                                      "Unable to open VT");
c4edd0
                         return FALSE;
c4edd0
                 }
c4edd0
                 break;
c4edd0
         }
c4edd0
 
c4edd0
         flags = 0;
c4edd0
 
c4edd0
         if (worker->priv->is_program_session) {
c4edd0
                 flags |= PAM_SILENT;
c4edd0
         }
c4edd0
 
c4edd0
         error_code = pam_open_session (worker->priv->pam_handle, flags);
c4edd0
 
c4edd0
         if (error_code != PAM_SUCCESS) {
c4edd0
                 g_set_error (error,
c4edd0
                              GDM_SESSION_WORKER_ERROR,
c4edd0
                              GDM_SESSION_WORKER_ERROR_OPENING_SESSION,
c4edd0
                              "%s", pam_strerror (worker->priv->pam_handle, error_code));
c4edd0
                 goto out;
c4edd0
         }
c4edd0
 
c4edd0
         g_debug ("GdmSessionWorker: state SESSION_OPENED");
c4edd0
-        worker->priv->state = GDM_SESSION_WORKER_STATE_SESSION_OPENED;
c4edd0
+        gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SESSION_OPENED);
c4edd0
 
c4edd0
         session_id = gdm_session_worker_get_environment_variable (worker, "XDG_SESSION_ID");
c4edd0
 
c4edd0
         if (session_id != NULL) {
c4edd0
                 g_free (worker->priv->session_id);
c4edd0
                 worker->priv->session_id = session_id;
c4edd0
         }
c4edd0
 
c4edd0
  out:
c4edd0
         if (error_code != PAM_SUCCESS) {
c4edd0
                 gdm_session_worker_uninitialize_pam (worker, error_code);
c4edd0
                 return FALSE;
c4edd0
         }
c4edd0
 
c4edd0
         gdm_session_worker_get_username (worker, NULL);
c4edd0
         gdm_session_auditor_report_login (worker->priv->auditor);
c4edd0
 
c4edd0
         return TRUE;
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 gdm_session_worker_set_server_address (GdmSessionWorker *worker,
c4edd0
                                        const char       *address)
c4edd0
 {
c4edd0
         g_free (worker->priv->server_address);
c4edd0
         worker->priv->server_address = g_strdup (address);
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 gdm_session_worker_set_is_reauth_session (GdmSessionWorker *worker,
c4edd0
@@ -2454,61 +2466,61 @@ gdm_session_worker_set_property (GObject      *object,
c4edd0
         case PROP_SERVER_ADDRESS:
c4edd0
                 gdm_session_worker_set_server_address (self, g_value_get_string (value));
c4edd0
                 break;
c4edd0
         case PROP_IS_REAUTH_SESSION:
c4edd0
                 gdm_session_worker_set_is_reauth_session (self, g_value_get_boolean (value));
c4edd0
                 break;
c4edd0
         default:
c4edd0
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
c4edd0
                 break;
c4edd0
         }
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 gdm_session_worker_get_property (GObject    *object,
c4edd0
                                 guint       prop_id,
c4edd0
                                 GValue     *value,
c4edd0
                                 GParamSpec *pspec)
c4edd0
 {
c4edd0
         GdmSessionWorker *self;
c4edd0
 
c4edd0
         self = GDM_SESSION_WORKER (object);
c4edd0
 
c4edd0
         switch (prop_id) {
c4edd0
         case PROP_SERVER_ADDRESS:
c4edd0
                 g_value_set_string (value, self->priv->server_address);
c4edd0
                 break;
c4edd0
         case PROP_IS_REAUTH_SESSION:
c4edd0
                 g_value_set_boolean (value, self->priv->is_reauth_session);
c4edd0
                 break;
c4edd0
         case PROP_STATE:
c4edd0
-                g_value_set_int (value, self->priv->state);
c4edd0
+                g_value_set_enum (value, self->priv->state);
c4edd0
                 break;
c4edd0
         default:
c4edd0
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
c4edd0
                 break;
c4edd0
         }
c4edd0
 }
c4edd0
 
c4edd0
 static gboolean
c4edd0
 gdm_session_worker_handle_set_environment_variable (GdmDBusWorker         *object,
c4edd0
                                                     GDBusMethodInvocation *invocation,
c4edd0
                                                     const char            *key,
c4edd0
                                                     const char            *value)
c4edd0
 {
c4edd0
         GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
c4edd0
         gdm_session_worker_set_environment_variable (worker, key, value);
c4edd0
         gdm_dbus_worker_complete_set_environment_variable (object, invocation);
c4edd0
         return TRUE;
c4edd0
 }
c4edd0
 
c4edd0
 static gboolean
c4edd0
 gdm_session_worker_handle_set_session_name (GdmDBusWorker         *object,
c4edd0
                                             GDBusMethodInvocation *invocation,
c4edd0
                                             const char            *session_name)
c4edd0
 {
c4edd0
         GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
c4edd0
         g_debug ("GdmSessionWorker: session name set to %s", session_name);
c4edd0
         gdm_session_settings_set_session_name (worker->priv->user_settings,
c4edd0
                                                session_name);
c4edd0
         gdm_dbus_worker_complete_set_session_name (object, invocation);
c4edd0
         return TRUE;
c4edd0
@@ -2639,61 +2651,61 @@ do_authorize (GdmSessionWorker *worker)
c4edd0
                 g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error);
c4edd0
         }
c4edd0
         worker->priv->pending_invocation = NULL;
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 do_accredit (GdmSessionWorker *worker)
c4edd0
 {
c4edd0
         GError  *error;
c4edd0
         gboolean res;
c4edd0
 
c4edd0
         /* get kerberos tickets, setup group lists, etc
c4edd0
          */
c4edd0
         error = NULL;
c4edd0
         res = gdm_session_worker_accredit_user (worker, &error);
c4edd0
 
c4edd0
         if (res) {
c4edd0
                 gdm_dbus_worker_complete_establish_credentials (GDM_DBUS_WORKER (worker), worker->priv->pending_invocation);
c4edd0
         } else {
c4edd0
                 g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error);
c4edd0
         }
c4edd0
         worker->priv->pending_invocation = NULL;
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 save_account_details_now (GdmSessionWorker *worker)
c4edd0
 {
c4edd0
         g_assert (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCREDITED);
c4edd0
 
c4edd0
         g_debug ("GdmSessionWorker: saving account details for user %s", worker->priv->username);
c4edd0
-        worker->priv->state = GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED;
c4edd0
+        gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED);
c4edd0
         if (!gdm_session_settings_save (worker->priv->user_settings,
c4edd0
                                         worker->priv->username)) {
c4edd0
                 g_warning ("could not save session and language settings");
c4edd0
         }
c4edd0
         queue_state_change (worker);
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 on_settings_is_loaded_changed (GdmSessionSettings *user_settings,
c4edd0
                                GParamSpec         *pspec,
c4edd0
                                GdmSessionWorker   *worker)
c4edd0
 {
c4edd0
         if (!gdm_session_settings_is_loaded (worker->priv->user_settings)) {
c4edd0
                 return;
c4edd0
         }
c4edd0
 
c4edd0
         /* These signal handlers should be disconnected after the loading,
c4edd0
          * so that gdm_session_settings_set_* APIs don't cause the emitting
c4edd0
          * of Saved*NameRead D-Bus signals any more.
c4edd0
          */
c4edd0
         g_signal_handlers_disconnect_by_func (worker->priv->user_settings,
c4edd0
                                               G_CALLBACK (on_saved_session_name_read),
c4edd0
                                               worker);
c4edd0
 
c4edd0
         g_signal_handlers_disconnect_by_func (worker->priv->user_settings,
c4edd0
                                               G_CALLBACK (on_saved_language_name_read),
c4edd0
                                               worker);
c4edd0
 
c4edd0
         if (worker->priv->state == GDM_SESSION_WORKER_STATE_NONE) {
c4edd0
                 g_debug ("GdmSessionWorker: queuing setup for user: %s %s",
c4edd0
@@ -3443,60 +3455,68 @@ worker_interface_init (GdmDBusWorkerIface *interface)
c4edd0
         interface->handle_start_reauthentication = gdm_session_worker_handle_start_reauthentication;
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 gdm_session_worker_class_init (GdmSessionWorkerClass *klass)
c4edd0
 {
c4edd0
         GObjectClass    *object_class = G_OBJECT_CLASS (klass);
c4edd0
 
c4edd0
         object_class->get_property = gdm_session_worker_get_property;
c4edd0
         object_class->set_property = gdm_session_worker_set_property;
c4edd0
         object_class->constructor = gdm_session_worker_constructor;
c4edd0
         object_class->finalize = gdm_session_worker_finalize;
c4edd0
 
c4edd0
         g_type_class_add_private (klass, sizeof (GdmSessionWorkerPrivate));
c4edd0
 
c4edd0
         g_object_class_install_property (object_class,
c4edd0
                                          PROP_SERVER_ADDRESS,
c4edd0
                                          g_param_spec_string ("server-address",
c4edd0
                                                               "server address",
c4edd0
                                                               "server address",
c4edd0
                                                               NULL,
c4edd0
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
c4edd0
 
c4edd0
         g_object_class_install_property (object_class,
c4edd0
                                          PROP_IS_REAUTH_SESSION,
c4edd0
                                          g_param_spec_boolean ("is-reauth-session",
c4edd0
                                                                "is reauth session",
c4edd0
                                                                "is reauth session",
c4edd0
                                                               FALSE,
c4edd0
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
c4edd0
+        g_object_class_install_property (object_class,
c4edd0
+                                         PROP_STATE,
c4edd0
+                                         g_param_spec_enum ("state",
c4edd0
+                                                            "state",
c4edd0
+                                                            "state",
c4edd0
+                                                            GDM_TYPE_SESSION_WORKER_STATE,
c4edd0
+                                                            GDM_SESSION_WORKER_STATE_NONE,
c4edd0
+                                                            G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 reauthentication_request_free (ReauthenticationRequest *request)
c4edd0
 {
c4edd0
 
c4edd0
         g_signal_handlers_disconnect_by_func (request->session,
c4edd0
                                               G_CALLBACK (on_reauthentication_client_connected),
c4edd0
                                               request);
c4edd0
         g_signal_handlers_disconnect_by_func (request->session,
c4edd0
                                               G_CALLBACK (on_reauthentication_client_disconnected),
c4edd0
                                               request);
c4edd0
         g_signal_handlers_disconnect_by_func (request->session,
c4edd0
                                               G_CALLBACK (on_reauthentication_cancelled),
c4edd0
                                               request);
c4edd0
         g_signal_handlers_disconnect_by_func (request->session,
c4edd0
                                               G_CALLBACK (on_reauthentication_conversation_started),
c4edd0
                                               request);
c4edd0
         g_signal_handlers_disconnect_by_func (request->session,
c4edd0
                                               G_CALLBACK (on_reauthentication_conversation_stopped),
c4edd0
                                               request);
c4edd0
         g_signal_handlers_disconnect_by_func (request->session,
c4edd0
                                               G_CALLBACK (on_reauthentication_verification_complete),
c4edd0
                                               request);
c4edd0
         g_clear_object (&request->session);
c4edd0
         g_slice_free (ReauthenticationRequest, request);
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 gdm_session_worker_init (GdmSessionWorker *worker)
c4edd0
diff --git a/daemon/session-worker-main.c b/daemon/session-worker-main.c
c4edd0
index 4a3a8ebbe..d96844d2d 100644
c4edd0
--- a/daemon/session-worker-main.c
c4edd0
+++ b/daemon/session-worker-main.c
c4edd0
@@ -37,104 +37,137 @@
c4edd0
 #include <glib-object.h>
c4edd0
 
c4edd0
 #include "gdm-common.h"
c4edd0
 #include "gdm-log.h"
c4edd0
 #include "gdm-session-worker.h"
c4edd0
 
c4edd0
 #include "gdm-settings.h"
c4edd0
 #include "gdm-settings-direct.h"
c4edd0
 #include "gdm-settings-keys.h"
c4edd0
 
c4edd0
 static GdmSettings *settings = NULL;
c4edd0
 
c4edd0
 static gboolean
c4edd0
 on_sigusr1_cb (gpointer user_data)
c4edd0
 {
c4edd0
         g_debug ("Got USR1 signal");
c4edd0
 
c4edd0
         gdm_log_toggle_debug ();
c4edd0
 
c4edd0
         return TRUE;
c4edd0
 }
c4edd0
 
c4edd0
 static gboolean
c4edd0
 is_debug_set (void)
c4edd0
 {
c4edd0
         gboolean debug;
c4edd0
         gdm_settings_direct_get_boolean (GDM_KEY_DEBUG, &debug);
c4edd0
         return debug;
c4edd0
 }
c4edd0
 
c4edd0
+static gboolean
c4edd0
+on_shutdown_signal_cb (gpointer user_data)
c4edd0
+{
c4edd0
+        GMainLoop *mainloop = user_data;
c4edd0
+
c4edd0
+        g_main_loop_quit (mainloop);
c4edd0
+
c4edd0
+        return FALSE;
c4edd0
+}
c4edd0
+
c4edd0
+static void
c4edd0
+on_state_changed (GdmSessionWorker *worker,
c4edd0
+                  GParamSpec       *pspec,
c4edd0
+                  GMainLoop        *main_loop)
c4edd0
+{
c4edd0
+        GdmSessionWorkerState state;
c4edd0
+
c4edd0
+        g_object_get (G_OBJECT (worker), "state", &state, NULL);
c4edd0
+
c4edd0
+        if (state != GDM_SESSION_WORKER_STATE_SESSION_STARTED)
c4edd0
+                return;
c4edd0
+
c4edd0
+        g_unix_signal_add (SIGTERM, on_shutdown_signal_cb, main_loop);
c4edd0
+}
c4edd0
+
c4edd0
 static void
c4edd0
 on_sigterm_cb (int signal_number)
c4edd0
 {
c4edd0
         _exit (EXIT_SUCCESS);
c4edd0
 }
c4edd0
 
c4edd0
 int
c4edd0
 main (int    argc,
c4edd0
       char **argv)
c4edd0
 {
c4edd0
         GMainLoop        *main_loop;
c4edd0
         GOptionContext   *context;
c4edd0
         GdmSessionWorker *worker;
c4edd0
         const char       *address;
c4edd0
         gboolean          is_for_reauth;
c4edd0
         static GOptionEntry entries []   = {
c4edd0
                 { NULL }
c4edd0
         };
c4edd0
 
c4edd0
         signal (SIGTERM, on_sigterm_cb);
c4edd0
 
c4edd0
         bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
c4edd0
         textdomain (GETTEXT_PACKAGE);
c4edd0
         setlocale (LC_ALL, "");
c4edd0
 
c4edd0
         /* Translators: worker is a helper process that does the work
c4edd0
            of starting up a session */
c4edd0
         context = g_option_context_new (_("GNOME Display Manager Session Worker"));
c4edd0
         g_option_context_add_main_entries (context, entries, NULL);
c4edd0
 
c4edd0
         g_option_context_parse (context, &argc, &argv, NULL);
c4edd0
         g_option_context_free (context);
c4edd0
 
c4edd0
         gdm_log_init ();
c4edd0
 
c4edd0
         settings = gdm_settings_new ();
c4edd0
         if (settings == NULL) {
c4edd0
                 g_warning ("Unable to initialize settings");
c4edd0
                 exit (EXIT_FAILURE);
c4edd0
         }
c4edd0
 
c4edd0
         if (! gdm_settings_direct_init (settings, DATADIR "/gdm/gdm.schemas", "/")) {
c4edd0
                 g_warning ("Unable to initialize settings");
c4edd0
                 exit (EXIT_FAILURE);
c4edd0
         }
c4edd0
 
c4edd0
         gdm_log_set_debug (is_debug_set ());
c4edd0
 
c4edd0
         address = g_getenv ("GDM_SESSION_DBUS_ADDRESS");
c4edd0
         if (address == NULL) {
c4edd0
                 g_warning ("GDM_SESSION_DBUS_ADDRESS not set");
c4edd0
                 exit (EXIT_FAILURE);
c4edd0
         }
c4edd0
 
c4edd0
         is_for_reauth = g_getenv ("GDM_SESSION_FOR_REAUTH") != NULL;
c4edd0
 
c4edd0
         worker = gdm_session_worker_new (address, is_for_reauth);
c4edd0
 
c4edd0
         main_loop = g_main_loop_new (NULL, FALSE);
c4edd0
 
c4edd0
+        g_signal_connect (G_OBJECT (worker),
c4edd0
+                          "notify::state",
c4edd0
+                          G_CALLBACK (on_state_changed),
c4edd0
+                          main_loop);
c4edd0
+
c4edd0
         g_unix_signal_add (SIGUSR1, on_sigusr1_cb, NULL);
c4edd0
 
c4edd0
         g_main_loop_run (main_loop);
c4edd0
 
c4edd0
         if (worker != NULL) {
c4edd0
+                g_signal_handlers_disconnect_by_func (worker,
c4edd0
+                                                      G_CALLBACK (on_state_changed),
c4edd0
+                                                      main_loop);
c4edd0
                 g_object_unref (worker);
c4edd0
         }
c4edd0
 
c4edd0
         g_main_loop_unref (main_loop);
c4edd0
 
c4edd0
         g_debug ("Worker finished");
c4edd0
 
c4edd0
         return 0;
c4edd0
 }
c4edd0
-- 
c4edd0
2.21.0
c4edd0