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

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