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

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