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