From 16adbf262b641ec722794a30a91097767d13fc16 Mon Sep 17 00:00:00 2001 From: Ray Strode 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 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 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 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 #include #include #include #include #include #include #include #include #include #include #include #ifdef WITH_SYSTEMD #include #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