From 16adbf262b641ec722794a30a91097767d13fc16 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 12 Feb 2014 14:22:31 -0500
Subject: [PATCH 1/4] manager: explicitly disallow login screen from opening
reauth channel
It doesn't make sense for it to do, and right now the shell does it
up front, waits for the failure, and then does the "right" thing
(opens a new auth session) after.
This commit makes the failure explicit, so we can subsequently make
other cases where a reauth channel is requested work even if there is
no session to channel to by implicitly creating a transient one just
in time. That will come later.
---
daemon/gdm-manager.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 116 insertions(+), 6 deletions(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 6c0fe1d..6ce37e8 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -244,192 +244,302 @@ get_uid_for_session_id (GDBusConnection *connection,
if (LOGIND_RUNNING()) {
return get_uid_for_systemd_session_id (session_id, uid, error);
}
#endif
#ifdef WITH_CONSOLE_KIT
return get_uid_for_consolekit_session_id (connection, session_id, uid, error);
#endif
return FALSE;
}
static gboolean
lookup_by_session_id (const char *id,
GdmDisplay *display,
gpointer user_data)
{
const char *looking_for = user_data;
char *current;
gboolean res;
current = gdm_display_get_session_id (display);
res = g_strcmp0 (current, looking_for) == 0;
g_free (current);
return res;
}
+#ifdef WITH_CONSOLE_KIT
+static gboolean
+is_consolekit_login_session (GdmManager *self,
+ GDBusConnection *connection,
+ const char *session_id,
+ GError **error)
+{
+ GVariant *reply;
+ char *session_type = NULL;
+
+ reply = g_dbus_connection_call_sync (connection,
+ "org.freedesktop.ConsoleKit",
+ session_id,
+ "org.freedesktop.ConsoleKit.Session",
+ "GetSessionType",
+ NULL,
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ error);
+ if (reply == NULL) {
+ return FALSE;
+ }
+
+ g_variant_get (reply, "(s)", &session_type);
+ g_variant_unref (reply);
+
+ if (g_strcmp0 (session_type, "LoginWindow") != 0) {
+ g_free (session_type);
+
+ return FALSE;
+ }
+
+ g_free (session_type);
+ return TRUE;
+}
+#endif
+
+#ifdef WITH_SYSTEMD
+static gboolean
+is_systemd_login_session (GdmManager *self,
+ const char *session_id,
+ GError **error)
+{
+ char *session_class = NULL;
+ int ret;
+
+ ret = sd_session_get_class (session_id, &session_class);
+
+ if (ret < 0) {
+ g_set_error (error,
+ GDM_DISPLAY_ERROR,
+ GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
+ "Error getting class for session id %s from systemd: %s",
+ session_id,
+ g_strerror (-ret));
+ return FALSE;
+ }
+
+ if (g_strcmp0 (session_class, "greeter") != 0) {
+ g_free (session_class);
+ return FALSE;
+ }
+
+ g_free (session_class);
+ return TRUE;
+}
+#endif
+
+static gboolean
+is_login_session (GdmManager *self,
+ GDBusConnection *connection,
+ const char *session_id,
+ GError **error)
+{
+#ifdef WITH_SYSTEMD
+ if (LOGIND_RUNNING()) {
+ return is_systemd_login_session (self, session_id, error);
+ }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+ return is_consolekit_login_session (self, connection, session_id, error);
+#endif
+
+ return FALSE;
+}
+
static GdmDisplay *
get_display_and_details_for_bus_sender (GdmManager *self,
- GDBusConnection *connection,
- const char *sender,
- GPid *out_pid,
- uid_t *out_uid)
+ GDBusConnection *connection,
+ const char *sender,
+ GPid *out_pid,
+ uid_t *out_uid,
+ gboolean *out_is_login_screen)
{
GdmDisplay *display = NULL;
char *session_id = NULL;
GError *error = NULL;
int ret;
GPid pid;
uid_t caller_uid, session_uid;
ret = gdm_dbus_get_pid_for_name (sender, &pid, &error);
if (!ret) {
g_debug ("GdmManager: Error while retrieving pid for sender: %s",
error->message);
g_error_free (error);
goto out;
}
ret = gdm_dbus_get_uid_for_name (sender, &caller_uid, &error);
if (!ret) {
g_debug ("GdmManager: Error while retrieving uid for sender: %s",
error->message);
g_error_free (error);
goto out;
}
session_id = get_session_id_for_pid (connection, pid, &error);
if (session_id == NULL) {
g_debug ("GdmManager: Error while retrieving session id for sender: %s",
error->message);
g_error_free (error);
goto out;
}
+ if (out_is_login_screen != NULL) {
+ *out_is_login_screen = is_login_session (self, connection, session_id, &error);
+
+ if (error != NULL) {
+ g_debug ("GdmManager: Error while checking if sender is login screen: %s",
+ error->message);
+ g_error_free (error);
+ goto out;
+ }
+ }
+
if (!get_uid_for_session_id (connection, session_id, &session_uid, &error)) {
g_debug ("GdmManager: Error while retrieving uid for session: %s",
error->message);
g_error_free (error);
goto out;
}
if (caller_uid != session_uid) {
g_debug ("GdmManager: uid for sender and uid for session don't match");
goto out;
}
display = gdm_display_store_find (self->priv->display_store,
lookup_by_session_id,
(gpointer) session_id);
out:
g_free (session_id);
if (display != NULL) {
if (out_pid != NULL)
*out_pid = pid;
if (out_uid != NULL)
*out_uid = session_uid;
}
return display;
}
static gboolean
gdm_manager_handle_open_session (GdmDBusManager *manager,
GDBusMethodInvocation *invocation)
{
GdmManager *self = GDM_MANAGER (manager);
const char *sender = NULL;
GError *error = NULL;
GDBusConnection *connection;
GdmDisplay *display;
char *address;
GPid pid;
uid_t uid;
g_debug ("GdmManager: trying to open new session");
sender = g_dbus_method_invocation_get_sender (invocation);
connection = g_dbus_method_invocation_get_connection (invocation);
- display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid);
+ display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid, NULL);
if (display == NULL) {
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
_("No session available"));
return TRUE;
}
address = gdm_display_open_session_sync (display, pid, uid, NULL, &error);
if (address == NULL) {
g_dbus_method_invocation_return_gerror (invocation, error);
g_error_free (error);
return TRUE;
}
gdm_dbus_manager_complete_open_session (GDM_DBUS_MANAGER (manager),
invocation,
address);
g_free (address);
return TRUE;
}
static gboolean
gdm_manager_handle_open_reauthentication_channel (GdmDBusManager *manager,
GDBusMethodInvocation *invocation,
const char *username)
{
GdmManager *self = GDM_MANAGER (manager);
const char *sender = NULL;
GError *error = NULL;
GDBusConnection *connection;
GdmDisplay *display;
char *address;
GPid pid;
uid_t uid;
+ gboolean is_login_screen = FALSE;
g_debug ("GdmManager: trying to open reauthentication channel for user %s", username);
sender = g_dbus_method_invocation_get_sender (invocation);
connection = g_dbus_method_invocation_get_connection (invocation);
- display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid);
+ display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid, &is_login_screen);
+
+ if (is_login_screen) {
+ g_dbus_method_invocation_return_error_literal (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ _("Login screen not allow to open reauthentication channel"));
+ return TRUE;
+ }
if (display == NULL) {
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
_("No session available"));
return TRUE;
}
address = gdm_display_open_reauthentication_channel_sync (display,
username,
pid,
uid,
NULL,
&error);
if (address == NULL) {
g_dbus_method_invocation_return_gerror (invocation, error);
g_error_free (error);
return TRUE;
}
gdm_dbus_manager_complete_open_reauthentication_channel (GDM_DBUS_MANAGER (manager),
invocation,
address);
g_free (address);
return TRUE;
}
--
1.8.4.2
From 3a1330c93213a060c51b2d3021360e80a779814c Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 11 Mar 2014 23:46:35 -0400
Subject: [PATCH 2/4] worker: support authentication without X11 display
At the moment we unconditionally set PAM_XDISPLAY
and PAM_XAUTHDATA based on values passed to the worker.
In a future commit, those values are going to become
stubs, so as a first step, this commit makes PAM_XDISPLAY
and PAM_XAUTHDATA optional.
---
daemon/gdm-session-worker.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 79cf202..eb81450 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -1073,76 +1073,81 @@ gdm_session_worker_initialize_pam (GdmSessionWorker *worker,
/* set TTY */
pam_tty = _get_tty_for_pam (x11_display_name, display_device);
if (pam_tty != NULL && pam_tty[0] != '\0') {
error_code = pam_set_item (worker->priv->pam_handle, PAM_TTY, pam_tty);
}
g_free (pam_tty);
if (error_code != PAM_SUCCESS) {
g_set_error (error,
GDM_SESSION_WORKER_ERROR,
GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
_("error informing authentication system of user's console: %s"),
pam_strerror (worker->priv->pam_handle, error_code));
goto out;
}
#ifdef WITH_SYSTEMD
/* set seat ID */
if (seat_id != NULL && seat_id[0] != '\0' && LOGIND_RUNNING()) {
gdm_session_worker_set_environment_variable (worker, "XDG_SEAT", seat_id);
}
#endif
if (strcmp (service, "gdm-launch-environment") == 0) {
gdm_session_worker_set_environment_variable (worker, "XDG_SESSION_CLASS", "greeter");
}
#ifdef PAM_XDISPLAY
/* set XDISPLAY */
- error_code = pam_set_item (worker->priv->pam_handle, PAM_XDISPLAY, x11_display_name);
+ if (x11_display_name != NULL && x11_display_name[0] != '\0') {
+ error_code = pam_set_item (worker->priv->pam_handle, PAM_XDISPLAY, x11_display_name);
+ }
if (error_code != PAM_SUCCESS) {
g_set_error (error,
GDM_SESSION_WORKER_ERROR,
GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
_("error informing authentication system of display string: %s"),
pam_strerror (worker->priv->pam_handle, error_code));
goto out;
}
#endif
#ifdef PAM_XAUTHDATA
/* set XAUTHDATA */
pam_xauth = _get_xauth_for_pam (x11_authority_file);
- error_code = pam_set_item (worker->priv->pam_handle, PAM_XAUTHDATA, pam_xauth);
- g_free (pam_xauth);
+
+ if (pam_xauth != NULL) {
+ error_code = pam_set_item (worker->priv->pam_handle, PAM_XAUTHDATA, pam_xauth);
+ g_free (pam_xauth);
+ }
if (error_code != PAM_SUCCESS) {
g_set_error (error,
GDM_SESSION_WORKER_ERROR,
GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
_("error informing authentication system of display xauth credentials: %s"),
pam_strerror (worker->priv->pam_handle, error_code));
goto out;
}
#endif
g_debug ("GdmSessionWorker: state SETUP_COMPLETE");
worker->priv->state = GDM_SESSION_WORKER_STATE_SETUP_COMPLETE;
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;
--
1.8.4.2
From e8c249d57b744d61c3c119f55e26f1ff1c14a598 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 19 Feb 2014 10:54:56 -0500
Subject: [PATCH 3/4] manager: collect more details about bus sender
In the future we're going to need to know more details about the
sender to know how to move forward (such as seat id, session id,
if it's remote, etc) in order to create a transient session soley
for reauthentication.
To prepare for that future, this commit adds the necessary
functionality to get_display_and_details_for_bus_sender.
---
daemon/gdm-manager.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 209 insertions(+), 19 deletions(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 6ce37e8..4c47045 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -333,205 +333,395 @@ is_systemd_login_session (GdmManager *self,
if (g_strcmp0 (session_class, "greeter") != 0) {
g_free (session_class);
return FALSE;
}
g_free (session_class);
return TRUE;
}
#endif
static gboolean
is_login_session (GdmManager *self,
GDBusConnection *connection,
const char *session_id,
GError **error)
{
#ifdef WITH_SYSTEMD
if (LOGIND_RUNNING()) {
return is_systemd_login_session (self, session_id, error);
}
#endif
#ifdef WITH_CONSOLE_KIT
return is_consolekit_login_session (self, connection, session_id, error);
#endif
return FALSE;
}
-static GdmDisplay *
+#ifdef WITH_CONSOLE_KIT
+static gboolean
+is_consolekit_remote_session (GdmManager *self,
+ GDBusConnection *connection,
+ const char *session_id,
+ GError **error)
+{
+ GVariant *reply;
+ gboolean is_remote;
+
+ reply = g_dbus_connection_call_sync (connection,
+ "org.freedesktop.ConsoleKit",
+ session_id,
+ "org.freedesktop.ConsoleKit.Session",
+ "IsLocal",
+ NULL,
+ G_VARIANT_TYPE ("(b)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ error);
+ if (reply == NULL) {
+ return FALSE;
+ }
+
+ g_variant_get (reply, "(b)", &is_remote);
+ g_variant_unref (reply);
+
+ return is_remote;
+}
+#endif
+
+#ifdef WITH_SYSTEMD
+static gboolean
+is_systemd_remote_session (GdmManager *self,
+ const char *session_id,
+ GError **error)
+{
+ char *seat;
+ int ret;
+ gboolean is_remote;
+
+ /* FIXME: The next release of logind is going to have explicit api for
+ * checking remoteness.
+ */
+ seat = NULL;
+ ret = sd_session_get_seat (session_id, &seat);
+
+ if (ret < 0 && ret != -ENOENT) {
+ g_debug ("GdmManager: Error while retrieving seat for session %s: %s",
+ session_id, strerror (-ret));
+ }
+
+ if (seat != NULL) {
+ is_remote = FALSE;
+ free (seat);
+ } else {
+ is_remote = TRUE;
+ }
+
+ return is_remote;
+}
+#endif
+
+static gboolean
+is_remote_session (GdmManager *self,
+ GDBusConnection *connection,
+ const char *session_id,
+ GError **error)
+{
+#ifdef WITH_SYSTEMD
+ if (LOGIND_RUNNING()) {
+ return is_systemd_remote_session (self, session_id, error);
+ }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+ return is_consolekit_remote_session (self, connection, session_id, error);
+#endif
+
+ return FALSE;
+}
+
+#ifdef WITH_SYSTEMD
+static char *
+get_seat_id_for_systemd_session_id (const char *session_id,
+ GError **error)
+{
+ int ret;
+ char *seat, *out_seat;
+
+ seat = NULL;
+ ret = sd_session_get_seat (session_id, &seat);
+
+ if (ret == -ENOENT) {
+ out_seat = NULL;
+ } else if (ret < 0) {
+ g_set_error (error,
+ GDM_DISPLAY_ERROR,
+ GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
+ "Error getting uid for session id %s from systemd: %s",
+ session_id,
+ g_strerror (-ret));
+ out_seat = NULL;
+ } else {
+ out_seat = g_strdup (seat);
+ free (seat);
+ }
+
+ return out_seat;
+}
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+static char *
+get_seat_id_for_consolekit_session_id (GDBusConnection *connection,
+ const char *session_id,
+ GError **error)
+{
+ GVariant *reply;
+ char *retval;
+
+ reply = g_dbus_connection_call_sync (connection,
+ "org.freedesktop.ConsoleKit",
+ session_id,
+ "org.freedesktop.ConsoleKit.Session",
+ "GetSeatId",
+ NULL,
+ G_VARIANT_TYPE ("(o)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ error);
+ if (reply == NULL) {
+ return NULL;
+ }
+
+ g_variant_get (reply, "(o)", &retval);
+ g_variant_unref (reply);
+
+ return retval;
+}
+#endif
+
+static char *
+get_seat_id_for_session_id (GDBusConnection *connection,
+ const char *session_id,
+ GError **error)
+{
+#ifdef WITH_SYSTEMD
+ if (LOGIND_RUNNING()) {
+ return get_seat_id_for_systemd_session_id (session_id, error);
+ }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+ return get_seat_id_for_consolekit_session_id (connection, session_id, error);
+#endif
+
+ return NULL;
+}
+
+static void
get_display_and_details_for_bus_sender (GdmManager *self,
GDBusConnection *connection,
const char *sender,
+ GdmDisplay **out_display,
+ char **out_seat_id,
+ char **out_session_id,
GPid *out_pid,
uid_t *out_uid,
- gboolean *out_is_login_screen)
+ gboolean *out_is_login_screen,
+ gboolean *out_is_remote)
{
GdmDisplay *display = NULL;
char *session_id = NULL;
GError *error = NULL;
int ret;
GPid pid;
uid_t caller_uid, session_uid;
ret = gdm_dbus_get_pid_for_name (sender, &pid, &error);
if (!ret) {
g_debug ("GdmManager: Error while retrieving pid for sender: %s",
error->message);
g_error_free (error);
goto out;
}
+ if (out_pid != NULL)
+ *out_pid = pid;
+
ret = gdm_dbus_get_uid_for_name (sender, &caller_uid, &error);
if (!ret) {
g_debug ("GdmManager: Error while retrieving uid for sender: %s",
error->message);
g_error_free (error);
goto out;
}
session_id = get_session_id_for_pid (connection, pid, &error);
if (session_id == NULL) {
g_debug ("GdmManager: Error while retrieving session id for sender: %s",
error->message);
g_error_free (error);
goto out;
}
+ if (out_session_id != NULL) {
+ *out_session_id = g_strdup (session_id);
+ }
+
if (out_is_login_screen != NULL) {
*out_is_login_screen = is_login_session (self, connection, session_id, &error);
if (error != NULL) {
g_debug ("GdmManager: Error while checking if sender is login screen: %s",
error->message);
g_error_free (error);
goto out;
}
}
if (!get_uid_for_session_id (connection, session_id, &session_uid, &error)) {
g_debug ("GdmManager: Error while retrieving uid for session: %s",
error->message);
g_error_free (error);
goto out;
}
+ if (out_uid != NULL)
+ *out_uid = session_uid;
+
if (caller_uid != session_uid) {
g_debug ("GdmManager: uid for sender and uid for session don't match");
goto out;
}
+ if (out_seat_id != NULL) {
+ *out_seat_id = get_seat_id_for_session_id (connection, session_id, &error);
+
+ if (error != NULL) {
+ g_debug ("GdmManager: Error while retrieving seat id for session: %s",
+ error->message);
+ g_clear_error (&error);
+ }
+ }
+
+ if (out_is_remote != NULL) {
+ *out_is_remote = is_remote_session (self, connection, session_id, &error);
+
+ if (error != NULL) {
+ g_debug ("GdmManager: Error while retrieving remoteness for session: %s",
+ error->message);
+ g_clear_error (&error);
+ }
+ }
+
display = gdm_display_store_find (self->priv->display_store,
lookup_by_session_id,
(gpointer) session_id);
+ if (out_display != NULL)
+ *out_display = display;
+
out:
g_free (session_id);
-
- if (display != NULL) {
- if (out_pid != NULL)
- *out_pid = pid;
-
- if (out_uid != NULL)
- *out_uid = session_uid;
- }
- return display;
}
static gboolean
gdm_manager_handle_open_session (GdmDBusManager *manager,
GDBusMethodInvocation *invocation)
{
GdmManager *self = GDM_MANAGER (manager);
const char *sender = NULL;
GError *error = NULL;
GDBusConnection *connection;
- GdmDisplay *display;
+ GdmDisplay *display = NULL;
char *address;
- GPid pid;
- uid_t uid;
+ GPid pid = 0;
+ uid_t uid = (uid_t) -1;
g_debug ("GdmManager: trying to open new session");
sender = g_dbus_method_invocation_get_sender (invocation);
connection = g_dbus_method_invocation_get_connection (invocation);
- display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid, NULL);
+ get_display_and_details_for_bus_sender (self, connection, sender, &display, NULL, NULL, &pid, &uid, NULL, NULL);
if (display == NULL) {
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
_("No session available"));
return TRUE;
}
address = gdm_display_open_session_sync (display, pid, uid, NULL, &error);
if (address == NULL) {
g_dbus_method_invocation_return_gerror (invocation, error);
g_error_free (error);
return TRUE;
}
gdm_dbus_manager_complete_open_session (GDM_DBUS_MANAGER (manager),
invocation,
address);
g_free (address);
return TRUE;
}
static gboolean
gdm_manager_handle_open_reauthentication_channel (GdmDBusManager *manager,
GDBusMethodInvocation *invocation,
const char *username)
{
GdmManager *self = GDM_MANAGER (manager);
const char *sender = NULL;
GError *error = NULL;
GDBusConnection *connection;
- GdmDisplay *display;
+ GdmDisplay *display = NULL;
char *address;
- GPid pid;
- uid_t uid;
+ GPid pid = 0;
+ uid_t uid = (uid_t) -1;
gboolean is_login_screen = FALSE;
g_debug ("GdmManager: trying to open reauthentication channel for user %s", username);
sender = g_dbus_method_invocation_get_sender (invocation);
connection = g_dbus_method_invocation_get_connection (invocation);
- display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid, &is_login_screen);
+ get_display_and_details_for_bus_sender (self, connection, sender, &display, NULL, NULL, &pid, &uid, &is_login_screen, NULL);
if (is_login_screen) {
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
_("Login screen not allow to open reauthentication channel"));
return TRUE;
}
if (display == NULL) {
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
_("No session available"));
return TRUE;
}
address = gdm_display_open_reauthentication_channel_sync (display,
username,
pid,
uid,
NULL,
&error);
if (address == NULL) {
g_dbus_method_invocation_return_gerror (invocation, error);
g_error_free (error);
return TRUE;
}
--
1.8.4.2
From 8fe36a032eb5ce681c91d5ccc8b0719f8e360b53 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 11 Mar 2014 15:25:29 -0400
Subject: [PATCH 4/4] manager: support just-in-time reauthentication for
non-GDM sessions
Right now, gnome-shell can't unlock screens running on an X server that
isn't managed by GDM (say Xvnc or startx). This is because GDM handles
the backend processing for unlocking, and it handles that backend
processing from the worker associated with the session. If there is no
worker associated with the session (as is the case with Xvnc and startx),
then there's no process to handle reauthentication.
This commit notices that case, and creates a transient worker on the fly
just to perform one off authentication for unlock of non-GDM managed
sessions.
---
daemon/Makefile.am | 13 +++
daemon/gdm-manager.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 271 insertions(+), 10 deletions(-)
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index ead9096..750735a 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -289,83 +289,96 @@ endif
gdm_session_worker_LDFLAGS = \
$(XLIB_LIBS) \
$(PAM_LIBS) \
$(NULL)
gdm_session_worker_LDADD = \
$(top_builddir)/common/libgdmcommon.la \
$(DAEMON_LIBS) \
$(SYSTEMD_LIBS) \
$(JOURNALD_LIBS) \
$(LIBSELINUX_LIBS) \
$(NULL)
sbin_PROGRAMS = \
gdm \
$(NULL)
gdm_SOURCES = \
main.c \
gdm-display-access-file.c \
gdm-display-access-file.h \
gdm-display-store.c \
gdm-display-store.h \
gdm-display-factory.c \
gdm-display-factory.h \
gdm-local-display-factory.c \
gdm-local-display-factory.h \
gdm-display.c \
gdm-display.h \
+ gdm-session.c \
+ gdm-session.h \
+ gdm-session-record.c \
+ gdm-session-record.h \
+ gdm-session-worker-common.c \
+ gdm-session-worker-common.h \
+ gdm-session-worker-job.c \
gdm-static-display.c \
gdm-static-display.h \
gdm-transient-display.c \
gdm-transient-display.h \
gdm-manager.c \
gdm-manager.h \
gdm-slave-proxy.c \
gdm-slave-proxy.h \
gdm-dbus-util.c \
gdm-dbus-util.h \
$(NULL)
nodist_gdm_SOURCES = \
gdm-display-glue.h \
gdm-display-glue.c \
gdm-local-display-factory-glue.h \
gdm-local-display-factory-glue.c \
gdm-manager-glue.h \
gdm-manager-glue.c \
gdm-transient-display-glue.h \
gdm-transient-display-glue.c \
gdm-static-display-glue.h \
gdm-static-display-glue.c \
+ gdm-session-enum-types.c \
+ gdm-session-enum-types.h \
+ gdm-session-glue.c \
+ gdm-session-glue.h \
+ gdm-session-worker-glue.c \
+ gdm-session-worker-glue.h \
gdm-slave-glue.h \
gdm-slave-glue.c \
$(NULL)
XDMCP_SOURCES = \
gdm-xdmcp-display-factory.c \
gdm-xdmcp-display-factory.h \
gdm-xdmcp-display.c \
gdm-xdmcp-display.h \
gdm-xdmcp-greeter-display.c \
gdm-xdmcp-greeter-display.h \
gdm-xdmcp-chooser-display.c \
gdm-xdmcp-chooser-display.h \
$(NULL)
XDMCP_nodist_SOURCES = \
gdm-xdmcp-display-glue.c \
gdm-xdmcp-display-glue.h \
gdm-xdmcp-chooser-slave-glue.c \
gdm-xdmcp-chooser-slave-glue.h \
$(NULL)
if XDMCP_SUPPORT
gdm_SOURCES += $(XDMCP_SOURCES)
nodist_gdm_SOURCES += $(XDMCP_nodist_SOURCES)
endif
EXTRA_gdm_SOURCES = \
$(XDMCP_SOURCES) \
$(NULL)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 4c47045..7eb2172 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -16,60 +16,61 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <glib-object.h>
#ifdef WITH_SYSTEMD
#include <systemd/sd-login.h>
#endif
#include "gdm-common.h"
#include "gdm-dbus-util.h"
#include "gdm-manager.h"
#include "gdm-manager-glue.h"
+#include "gdm-session.h"
#include "gdm-display-store.h"
#include "gdm-display-factory.h"
#include "gdm-local-display-factory.h"
#include "gdm-xdmcp-display-factory.h"
#define GDM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_MANAGER, GdmManagerPrivate))
#define GDM_DBUS_PATH "/org/gnome/DisplayManager"
#define GDM_MANAGER_PATH GDM_DBUS_PATH "/Manager"
#define GDM_MANAGER_DISPLAYS_PATH GDM_DBUS_PATH "/Displays"
struct GdmManagerPrivate
{
GdmDisplayStore *display_store;
GdmLocalDisplayFactory *local_factory;
#ifdef HAVE_LIBXDMCP
GdmXdmcpDisplayFactory *xdmcp_factory;
#endif
gboolean xdmcp_enabled;
gboolean started;
gboolean wait_for_go;
gboolean no_console;
GDBusProxy *bus_proxy;
GDBusConnection *connection;
GDBusObjectManagerServer *object_manager;
};
enum {
@@ -648,104 +649,351 @@ gdm_manager_handle_open_session (GdmDBusManager *manager,
sender = g_dbus_method_invocation_get_sender (invocation);
connection = g_dbus_method_invocation_get_connection (invocation);
get_display_and_details_for_bus_sender (self, connection, sender, &display, NULL, NULL, &pid, &uid, NULL, NULL);
if (display == NULL) {
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
_("No session available"));
return TRUE;
}
address = gdm_display_open_session_sync (display, pid, uid, NULL, &error);
if (address == NULL) {
g_dbus_method_invocation_return_gerror (invocation, error);
g_error_free (error);
return TRUE;
}
gdm_dbus_manager_complete_open_session (GDM_DBUS_MANAGER (manager),
invocation,
address);
g_free (address);
return TRUE;
}
+#ifdef WITH_SYSTEMD
+static gboolean
+unlock_systemd_session (GdmManager *manager,
+ const char *ssid)
+{
+ GError *error = NULL;
+ GVariant *reply;
+
+ reply = g_dbus_connection_call_sync (manager->priv->connection,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "UnlockSession",
+ g_variant_new ("(s)", ssid),
+ NULL, /* expected reply */
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (reply == NULL) {
+ g_debug ("GdmManager: logind 'UnlockSession' %s raised:\n %s\n\n",
+ g_dbus_error_get_remote_error (error), error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ g_variant_unref (reply);
+
+ return TRUE;
+}
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+static gboolean
+unlock_consolekit_session (GdmManager *manager,
+ const char *ssid)
+{
+ GError *error = NULL;
+ GVariant *reply;
+
+ reply = g_dbus_connection_call_sync (manager->priv->connection,
+ "org.freedesktop.ConsoleKit",
+ ssid,
+ "org.freedesktop.ConsoleKit.Manager",
+ "Unlock",
+ NULL, /* parameters */
+ NULL, /* expected reply */
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (reply == NULL) {
+ g_debug ("GdmSlave: ConsoleKit %s raised:\n %s\n\n",
+ g_dbus_error_get_remote_error (error), error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ g_variant_unref (reply);
+
+ return TRUE;
+}
+#endif
+
+static void
+unlock_session (GdmManager *manager,
+ const char *ssid)
+{
+
+ g_debug ("GdmManager: Unlocking session %s", ssid);
+
+#ifdef WITH_SYSTEMD
+ if (LOGIND_RUNNING()) {
+ unlock_systemd_session (manager, ssid);
+ return;
+ }
+#endif
+
+#ifdef WITH_CONSOLE_KIT
+ unlock_consolekit_session (manager, ssid);
+#endif
+}
+static void
+on_reauthentication_client_connected (GdmSession *session,
+ GCredentials *credentials,
+ GPid pid_of_client,
+ GdmManager *self)
+{
+ g_debug ("GdmManager: client connected to reauthentication server");
+}
+
+static void
+on_reauthentication_client_disconnected (GdmSession *session,
+ GCredentials *credentials,
+ GPid pid_of_client,
+ GdmManager *self)
+{
+ g_debug ("GdmManger: client disconnected from reauthentication server");
+ gdm_session_close (session);
+ g_object_unref (session);
+}
+
+static void
+on_reauthentication_cancelled (GdmSession *session,
+ GdmManager *self)
+{
+ g_debug ("GdmManager: client cancelled reauthentication request");
+ gdm_session_close (session);
+ g_object_unref (session);
+}
+
+static void
+on_reauthentication_conversation_started (GdmSession *session,
+ const char *service_name,
+ GdmManager *self)
+{
+ g_debug ("GdmManager: reauthentication service '%s' started",
+ service_name);
+}
+
+static void
+on_reauthentication_conversation_stopped (GdmSession *session,
+ const char *service_name,
+ GdmManager *self)
+{
+ g_debug ("GdmManager: reauthentication service '%s' stopped",
+ service_name);
+}
+
+static void
+on_reauthentication_verification_complete (GdmSession *session,
+ const char *service_name,
+ GdmManager *self)
+{
+ const char *session_id;
+ session_id = g_object_get_data (G_OBJECT (session), "caller-session-id");
+ g_debug ("GdmManager: reauthenticated user in unmanaged session '%s' with service '%s'",
+ session_id, service_name);
+ unlock_session (self, session_id);
+ gdm_session_close (session);
+ g_object_unref (session);
+}
+
+static void
+remove_session_weak_refs (GdmManager *self,
+ GdmSession *session)
+{
+ g_object_weak_unref (G_OBJECT (self),
+ (GWeakNotify)
+ gdm_session_close,
+ session);
+ g_object_weak_unref (G_OBJECT (self),
+ (GWeakNotify)
+ g_object_unref,
+ session);
+}
+
+static char *
+open_temporary_reauthentication_channel (GdmManager *self,
+ char *seat_id,
+ char *session_id,
+ GPid pid,
+ uid_t uid,
+ gboolean is_remote)
+{
+ GdmSession *session;
+ char **environment;
+ const char *display, *auth_file;
+ char *address;
+
+ /* Note we're just using a minimal environment here rather than the
+ * session's environment because the caller is unprivileged and the
+ * associated worker will be privileged */
+ environment = g_get_environ ();
+ display = "";
+ auth_file = "/dev/null";
+
+ session = gdm_session_new (GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE,
+ uid,
+ display,
+ NULL,
+ NULL,
+ seat_id,
+ auth_file,
+ is_remote == FALSE,
+ (const char * const *)
+ environment);
+ g_strfreev (environment);
+
+ g_object_set_data_full (G_OBJECT (session),
+ "caller-session-id",
+ g_strdup (session_id),
+ (GDestroyNotify)
+ g_free);
+ g_object_weak_ref (G_OBJECT (self),
+ (GWeakNotify)
+ gdm_session_close,
+ session);
+ g_object_weak_ref (G_OBJECT (self),
+ (GWeakNotify)
+ g_object_unref,
+ session);
+ g_object_weak_ref (G_OBJECT (session),
+ (GWeakNotify)
+ remove_session_weak_refs,
+ self);
+
+ g_signal_connect (session,
+ "client-connected",
+ G_CALLBACK (on_reauthentication_client_connected),
+ self);
+ g_signal_connect (session,
+ "client-disconnected",
+ G_CALLBACK (on_reauthentication_client_disconnected),
+ self);
+ g_signal_connect (session,
+ "cancelled",
+ G_CALLBACK (on_reauthentication_cancelled),
+ self);
+ g_signal_connect (session,
+ "conversation-started",
+ G_CALLBACK (on_reauthentication_conversation_started),
+ self);
+ g_signal_connect (session,
+ "conversation-stopped",
+ G_CALLBACK (on_reauthentication_conversation_stopped),
+ self);
+ g_signal_connect (session,
+ "verification-complete",
+ G_CALLBACK (on_reauthentication_verification_complete),
+ self);
+
+ address = gdm_session_get_server_address (session);
+ return address;
+}
+
static gboolean
gdm_manager_handle_open_reauthentication_channel (GdmDBusManager *manager,
GDBusMethodInvocation *invocation,
const char *username)
{
GdmManager *self = GDM_MANAGER (manager);
const char *sender = NULL;
GError *error = NULL;
GDBusConnection *connection;
GdmDisplay *display = NULL;
char *address;
+ char *seat_id = NULL;
+ char *session_id = NULL;
GPid pid = 0;
uid_t uid = (uid_t) -1;
gboolean is_login_screen = FALSE;
+ gboolean is_remote = FALSE;
g_debug ("GdmManager: trying to open reauthentication channel for user %s", username);
sender = g_dbus_method_invocation_get_sender (invocation);
connection = g_dbus_method_invocation_get_connection (invocation);
- get_display_and_details_for_bus_sender (self, connection, sender, &display, NULL, NULL, &pid, &uid, &is_login_screen, NULL);
+ get_display_and_details_for_bus_sender (self, connection, sender, &display, &seat_id, &session_id, &pid, &uid, &is_login_screen, &is_remote);
if (is_login_screen) {
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
_("Login screen not allow to open reauthentication channel"));
return TRUE;
}
- if (display == NULL) {
+ if (session_id == NULL || pid == 0 || uid == (uid_t) -1) {
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
- _("No session available"));
-
+ _("Could not retrieve details about caller"));
return TRUE;
}
- address = gdm_display_open_reauthentication_channel_sync (display,
- username,
- pid,
- uid,
- NULL,
- &error);
+ if (display == NULL) {
+ address = open_temporary_reauthentication_channel (self,
+ seat_id,
+ session_id,
+ pid,
+ uid,
+ is_remote);
+ } else {
+ address = gdm_display_open_reauthentication_channel_sync (display,
+ username,
+ pid,
+ uid,
+ NULL,
+ &error);
+ }
if (address == NULL) {
g_dbus_method_invocation_return_gerror (invocation, error);
g_error_free (error);
return TRUE;
}
gdm_dbus_manager_complete_open_reauthentication_channel (GDM_DBUS_MANAGER (manager),
invocation,
address);
g_free (address);
return TRUE;
}
static void
manager_interface_init (GdmDBusManagerIface *interface)
{
interface->handle_open_session = gdm_manager_handle_open_session;
interface->handle_open_reauthentication_channel = gdm_manager_handle_open_reauthentication_channel;
}
static void
on_display_removed (GdmDisplayStore *display_store,
const char *id,
GdmManager *manager)
{
GdmDisplay *display;
display = gdm_display_store_lookup (display_store, id);
--
1.8.4.2
From a63ed886a5b232cc44938badd37daf394215d3b9 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 10 Apr 2014 08:56:10 -0400
Subject: [PATCH 1/4] session: introduce new client-rejected signal
If a client gets rejected because it's not allowed to connect
to a particular session, we really need to inform the owner
of the session object so it can do any clean up it needs to do,
if necessary.
---
daemon/gdm-session.c | 24 ++++++++++++++++++++++++
daemon/gdm-session.h | 1 +
2 files changed, 25 insertions(+)
diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
index e24ec7c..044a57c 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -117,60 +117,61 @@ struct _GdmSessionPrivate
uid_t allowed_user;
char *fallback_session_name;
GDBusServer *worker_server;
GDBusServer *outside_server;
GHashTable *environment;
};
enum {
PROP_0,
PROP_VERIFICATION_MODE,
PROP_ALLOWED_USER,
PROP_DISPLAY_NAME,
PROP_DISPLAY_HOSTNAME,
PROP_DISPLAY_IS_LOCAL,
PROP_DISPLAY_DEVICE,
PROP_DISPLAY_SEAT_ID,
PROP_DISPLAY_X11_AUTHORITY_FILE,
PROP_USER_X11_AUTHORITY_FILE,
PROP_CONVERSATION_ENVIRONMENT,
};
enum {
CONVERSATION_STARTED = 0,
CONVERSATION_STOPPED,
SETUP_COMPLETE,
CANCELLED,
HOSTNAME_SELECTED,
+ CLIENT_REJECTED,
CLIENT_CONNECTED,
CLIENT_DISCONNECTED,
CLIENT_READY_FOR_SESSION_TO_START,
DISCONNECTED,
VERIFICATION_COMPLETE,
SESSION_OPENED,
SESSION_STARTED,
SESSION_START_FAILED,
SESSION_EXITED,
SESSION_DIED,
REAUTHENTICATION_STARTED,
REAUTHENTICATED,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE (GdmSession,
gdm_session,
G_TYPE_OBJECT);
static GdmSessionConversation *
find_conversation_by_name (GdmSession *self,
const char *service_name)
{
GdmSessionConversation *conversation;
conversation = g_hash_table_lookup (self->priv->conversations, service_name);
if (conversation == NULL) {
@@ -1561,68 +1562,78 @@ setup_worker_server (GdmSession *self)
server = gdm_dbus_setup_private_server (observer, &error);
g_object_unref (observer);
if (server == NULL) {
g_warning ("Cannot create worker D-Bus server for the session: %s",
error->message);
return;
}
g_signal_connect_object (server,
"new-connection",
G_CALLBACK (handle_connection_from_worker),
self,
0);
self->priv->worker_server = server;
g_dbus_server_start (server);
g_debug ("GdmSession: D-Bus server for workers listening on %s",
g_dbus_server_get_client_address (self->priv->worker_server));
}
static gboolean
allow_user_function (GDBusAuthObserver *observer,
GIOStream *stream,
GCredentials *credentials,
GdmSession *self)
{
uid_t client_uid;
+ GPid pid_of_client;
client_uid = g_credentials_get_unix_user (credentials, NULL);
if (client_uid == self->priv->allowed_user) {
return TRUE;
}
g_debug ("GdmSession: User not allowed");
+ pid_of_client = credentials_get_unix_pid (credentials);
+ g_signal_emit (G_OBJECT (self),
+ signals [CLIENT_REJECTED],
+ 0,
+ credentials,
+ (guint)
+ pid_of_client);
+
+
return FALSE;
}
static void
setup_outside_server (GdmSession *self)
{
GDBusAuthObserver *observer;
GDBusServer *server;
GError *error = NULL;
g_debug ("GdmSession: Creating D-Bus server for greeters and such");
observer = g_dbus_auth_observer_new ();
g_signal_connect_object (observer,
"authorize-authenticated-peer",
G_CALLBACK (allow_user_function),
self,
0);
server = gdm_dbus_setup_private_server (observer, &error);
g_object_unref (observer);
if (server == NULL) {
g_warning ("Cannot create greeter D-Bus server for the session: %s",
error->message);
return;
}
g_signal_connect_object (server,
"new-connection",
@@ -3186,60 +3197,73 @@ gdm_session_class_init (GdmSessionClass *session_class)
G_STRUCT_OFFSET (GdmSessionClass, reauthentication_started),
NULL,
NULL,
NULL,
G_TYPE_NONE,
2,
G_TYPE_INT,
G_TYPE_STRING);
signals [REAUTHENTICATED] =
g_signal_new ("reauthenticated",
GDM_TYPE_SESSION,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GdmSessionClass, reauthenticated),
NULL,
NULL,
NULL,
G_TYPE_NONE,
1,
G_TYPE_STRING);
signals [CANCELLED] =
g_signal_new ("cancelled",
GDM_TYPE_SESSION,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GdmSessionClass, cancelled),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
+ signals [CLIENT_REJECTED] =
+ g_signal_new ("client-rejected",
+ GDM_TYPE_SESSION,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmSessionClass, client_rejected),
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_CREDENTIALS,
+ G_TYPE_UINT);
+
signals [CLIENT_CONNECTED] =
g_signal_new ("client-connected",
GDM_TYPE_SESSION,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GdmSessionClass, client_connected),
NULL,
NULL,
NULL,
G_TYPE_NONE,
2,
G_TYPE_CREDENTIALS,
G_TYPE_UINT);
signals [CLIENT_DISCONNECTED] =
g_signal_new ("client-disconnected",
GDM_TYPE_SESSION,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GdmSessionClass, client_disconnected),
NULL,
NULL,
NULL,
G_TYPE_NONE,
2,
G_TYPE_CREDENTIALS,
G_TYPE_UINT);
signals [CLIENT_READY_FOR_SESSION_TO_START] =
g_signal_new ("client-ready-for-session-to-start",
GDM_TYPE_SESSION,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GdmSessionClass, client_ready_for_session_to_start),
diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h
index 2511eca..8b93e2c 100644
--- a/daemon/gdm-session.h
+++ b/daemon/gdm-session.h
@@ -30,60 +30,61 @@ G_BEGIN_DECLS
#define GDM_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_SESSION, GdmSessionClass))
#define GDM_IS_SESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDM_TYPE_SESSION))
#define GDM_IS_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_SESSION))
#define GDM_SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_SESSION, GdmSessionClass))
typedef struct _GdmSessionPrivate GdmSessionPrivate;
typedef enum
{
GDM_SESSION_VERIFICATION_MODE_LOGIN,
GDM_SESSION_VERIFICATION_MODE_CHOOSER,
GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE
} GdmSessionVerificationMode;
typedef struct
{
GObject parent;
GdmSessionPrivate *priv;
} GdmSession;
typedef struct
{
GObjectClass parent_class;
/* Signals */
void (* client_ready_for_session_to_start) (GdmSession *session,
const char *service_name,
gboolean client_is_ready);
void (* cancelled) (GdmSession *session);
+ void (* client_rejected) (GdmSession *session);
void (* client_connected) (GdmSession *session);
void (* client_disconnected) (GdmSession *session);
void (* disconnected) (GdmSession *session);
void (* verification_complete) (GdmSession *session,
const char *service_name);
void (* session_opened) (GdmSession *session,
const char *service_name,
const char *session_id);
void (* session_started) (GdmSession *session,
const char *service_name,
const char *session_id,
int pid);
void (* session_start_failed) (GdmSession *session,
const char *service_name,
const char *message);
void (* session_exited) (GdmSession *session,
int exit_code);
void (* session_died) (GdmSession *session,
int signal_number);
void (* reauthentication_started) (GdmSession *session,
GPid pid_of_caller);
void (* reauthenticated) (GdmSession *session,
const char *service_name);
void (* conversation_started) (GdmSession *session,
const char *service_name);
void (* conversation_stopped) (GdmSession *session,
const char *service_name);
void (* setup_complete) (GdmSession *session,
const char *service_name);
} GdmSessionClass;
--
1.9.0
From d11dd2511e08ab73757b8e97572c912c1f2fff8d Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 10 Apr 2014 09:13:57 -0400
Subject: [PATCH 2/4] manager: stuff pid associated with transient session on
session object
In the event the session object is not associated with an audit session,
we want some way to match the object back to a client. This commit
stores the pid of the caller on the object.
---
daemon/gdm-manager.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index e6fd0b4..4d60ac0 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -843,60 +843,63 @@ open_temporary_reauthentication_channel (GdmManager *self,
{
GdmSession *session;
char **environment;
const char *display, *auth_file;
char *address;
/* Note we're just using a minimal environment here rather than the
* session's environment because the caller is unprivileged and the
* associated worker will be privileged */
environment = g_get_environ ();
display = "";
auth_file = "/dev/null";
session = gdm_session_new (GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE,
uid,
display,
NULL,
NULL,
seat_id,
auth_file,
is_remote == FALSE,
(const char * const *)
environment);
g_strfreev (environment);
g_object_set_data_full (G_OBJECT (session),
"caller-session-id",
g_strdup (session_id),
(GDestroyNotify)
g_free);
+ g_object_set_data (G_OBJECT (session),
+ "caller-pid",
+ GINT_TO_POINTER ((gint) pid));
g_object_weak_ref (G_OBJECT (self),
(GWeakNotify)
gdm_session_close,
session);
g_object_weak_ref (G_OBJECT (self),
(GWeakNotify)
g_object_unref,
session);
g_object_weak_ref (G_OBJECT (session),
(GWeakNotify)
remove_session_weak_refs,
self);
g_signal_connect (session,
"client-connected",
G_CALLBACK (on_reauthentication_client_connected),
self);
g_signal_connect (session,
"client-disconnected",
G_CALLBACK (on_reauthentication_client_disconnected),
self);
g_signal_connect (session,
"cancelled",
G_CALLBACK (on_reauthentication_cancelled),
self);
g_signal_connect (session,
"conversation-started",
G_CALLBACK (on_reauthentication_conversation_started),
self);
g_signal_connect (session,
--
1.9.0
From 24c3d14d5336aa59d15f1cfdb59643dd254a62bd Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 10 Apr 2014 09:22:07 -0400
Subject: [PATCH 3/4] manager: don't leak session objects when client is
rejected
if a client creates a transient reauthentication session and then we reject
the client when it tries to connect to it, then we need to clean up
the associated session object.
This commit does that.
---
daemon/gdm-manager.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 4d60ac0..084fbb4 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -752,60 +752,102 @@ unlock_session (GdmManager *manager,
unlock_systemd_session (manager, ssid);
return;
}
#endif
#ifdef WITH_CONSOLE_KIT
unlock_consolekit_session (manager, ssid);
#endif
}
static void
on_reauthentication_client_connected (GdmSession *session,
GCredentials *credentials,
GPid pid_of_client,
GdmManager *self)
{
g_debug ("GdmManager: client connected to reauthentication server");
}
static void
on_reauthentication_client_disconnected (GdmSession *session,
GCredentials *credentials,
GPid pid_of_client,
GdmManager *self)
{
g_debug ("GdmManger: client disconnected from reauthentication server");
gdm_session_close (session);
g_object_unref (session);
}
static void
+on_reauthentication_client_rejected (GdmSession *session,
+ GCredentials *credentials,
+ GPid pid_of_client,
+ GdmManager *self)
+{
+ GPid pid;
+
+ g_debug ("GdmManger: client with pid %ld rejected from reauthentication server", (long) pid_of_client);
+
+ if (gdm_session_client_is_connected (session)) {
+ /* we already have a client connected, ignore this rejected one */
+ return;
+ }
+
+ pid = (GPid) GPOINTER_TO_INT (g_object_get_data (G_OBJECT (session), "caller-pid"));
+
+ if (pid != pid_of_client) {
+ const char *session_id;
+ char *client_session_id;
+
+ /* rejected client isn't the process that started the
+ * transient reauthentication session. If it's not even from the
+ * same audit session, ignore it since it doesn't "own" the
+ * reauthentication session
+ */
+ client_session_id = get_session_id_for_pid (self->priv->connection,
+ pid_of_client,
+ NULL);
+ session_id = g_object_get_data (G_OBJECT (session), "caller-session-id");
+
+ if (g_strcmp0 (session_id, client_session_id) != 0) {
+ return;
+ }
+ }
+
+ /* client was rejected, so clean up its session object
+ */
+ gdm_session_close (session);
+ g_object_unref (session);
+}
+
+static void
on_reauthentication_cancelled (GdmSession *session,
GdmManager *self)
{
g_debug ("GdmManager: client cancelled reauthentication request");
gdm_session_close (session);
g_object_unref (session);
}
static void
on_reauthentication_conversation_started (GdmSession *session,
const char *service_name,
GdmManager *self)
{
g_debug ("GdmManager: reauthentication service '%s' started",
service_name);
}
static void
on_reauthentication_conversation_stopped (GdmSession *session,
const char *service_name,
GdmManager *self)
{
g_debug ("GdmManager: reauthentication service '%s' stopped",
service_name);
}
static void
on_reauthentication_verification_complete (GdmSession *session,
const char *service_name,
GdmManager *self)
@@ -868,60 +910,64 @@ open_temporary_reauthentication_channel (GdmManager *self,
g_object_set_data_full (G_OBJECT (session),
"caller-session-id",
g_strdup (session_id),
(GDestroyNotify)
g_free);
g_object_set_data (G_OBJECT (session),
"caller-pid",
GINT_TO_POINTER ((gint) pid));
g_object_weak_ref (G_OBJECT (self),
(GWeakNotify)
gdm_session_close,
session);
g_object_weak_ref (G_OBJECT (self),
(GWeakNotify)
g_object_unref,
session);
g_object_weak_ref (G_OBJECT (session),
(GWeakNotify)
remove_session_weak_refs,
self);
g_signal_connect (session,
"client-connected",
G_CALLBACK (on_reauthentication_client_connected),
self);
g_signal_connect (session,
"client-disconnected",
G_CALLBACK (on_reauthentication_client_disconnected),
self);
g_signal_connect (session,
+ "client-rejected",
+ G_CALLBACK (on_reauthentication_client_rejected),
+ self);
+ g_signal_connect (session,
"cancelled",
G_CALLBACK (on_reauthentication_cancelled),
self);
g_signal_connect (session,
"conversation-started",
G_CALLBACK (on_reauthentication_conversation_started),
self);
g_signal_connect (session,
"conversation-stopped",
G_CALLBACK (on_reauthentication_conversation_stopped),
self);
g_signal_connect (session,
"verification-complete",
G_CALLBACK (on_reauthentication_verification_complete),
self);
address = gdm_session_get_server_address (session);
return address;
}
static gboolean
gdm_manager_handle_open_reauthentication_channel (GdmDBusManager *manager,
GDBusMethodInvocation *invocation,
const char *username)
{
GdmManager *self = GDM_MANAGER (manager);
const char *sender = NULL;
GError *error = NULL;
GDBusConnection *connection;
GdmDisplay *display = NULL;
--
1.9.0
From 9d67a7fd3acdc4b063020dfca53f676c2f1449d1 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 10 Apr 2014 09:27:59 -0400
Subject: [PATCH 4/4] manager: be more accepting of callers with uids different
from their session
If a user runs su in their session, that switched user will now be
running in a session that doesn't belong to it. GDM won't allow a user
access to the worker process associated with the session in this case.
Instead, it will try to create a temporary just-in-time reauthentication
channel so reauthentication can happen without having the user talking to
another user's worker. Unfortunately, a logic error in the code means,
the user won't access to its own just-in-time channel.
This commit fixes that.
---
daemon/gdm-manager.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 084fbb4..5809792 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -568,61 +568,61 @@ get_display_and_details_for_bus_sender (GdmManager *self,
if (session_id == NULL) {
g_debug ("GdmManager: Error while retrieving session id for sender: %s",
error->message);
g_error_free (error);
goto out;
}
if (out_session_id != NULL) {
*out_session_id = g_strdup (session_id);
}
if (out_is_login_screen != NULL) {
*out_is_login_screen = is_login_session (self, connection, session_id, &error);
if (error != NULL) {
g_debug ("GdmManager: Error while checking if sender is login screen: %s",
error->message);
g_error_free (error);
goto out;
}
}
if (!get_uid_for_session_id (connection, session_id, &session_uid, &error)) {
g_debug ("GdmManager: Error while retrieving uid for session: %s",
error->message);
g_error_free (error);
goto out;
}
if (out_uid != NULL)
- *out_uid = session_uid;
+ *out_uid = caller_uid;
if (caller_uid != session_uid) {
g_debug ("GdmManager: uid for sender and uid for session don't match");
goto out;
}
if (out_seat_id != NULL) {
*out_seat_id = get_seat_id_for_session_id (connection, session_id, &error);
if (error != NULL) {
g_debug ("GdmManager: Error while retrieving seat id for session: %s",
error->message);
g_clear_error (&error);
}
}
if (out_is_remote != NULL) {
*out_is_remote = is_remote_session (self, connection, session_id, &error);
if (error != NULL) {
g_debug ("GdmManager: Error while retrieving remoteness for session: %s",
error->message);
g_clear_error (&error);
}
}
display = gdm_display_store_find (self->priv->display_store,
lookup_by_session_id,
(gpointer) session_id);
if (out_display != NULL)
--
1.9.0