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

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