From 2c351af58d1ba5581a95ed02d38fdc8dd904ad7b Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 28 Oct 2014 17:16:18 -0400
Subject: [PATCH 1/2] kerberos: maintain one long-lasting object manager client
to kerberos service
At the moment, the kerberos backend creates one object manager to the
kerberos identity service per provider object. Provider objects are actually
fairly transient and get created and destroyed, in some cases, per operation
on an account. The upshot is, object manager clients end up getting created
more frequently than they really should be. To make matters worse, the kerberos
provider has no finalize function, so these object manager clients are getting
leaked.
This commit makes the object manager client get created once at start up,
and get reused by all providers. Since there's only one object manager,
rooted in the main thread, using the main thread's main loop context
now, the per-thread synchronous codepaths can't call object manager async
functions using a local main loop context. They do this, at the moment, because
there are async, main thread code paths that also need to talk to the
kerberos service. The local main loop context provides a way to call the
async code synchronously, and prevent duplication of logic.
This commit gets rid of all the local main loop contexts, and instead uses
sync functions. To prevent duplication of logic, the async code now
leverages the sync code, in a thread.
---
src/goabackend/goakerberosprovider.c | 963 +++++++++++++----------------------
1 file changed, 345 insertions(+), 618 deletions(-)
diff --git a/src/goabackend/goakerberosprovider.c b/src/goabackend/goakerberosprovider.c
index f9c54cd4f79c..2eb6b677ab22 100644
--- a/src/goabackend/goakerberosprovider.c
+++ b/src/goabackend/goakerberosprovider.c
@@ -41,8 +41,6 @@ struct _GoaKerberosProvider
{
/*< private >*/
GoaProvider parent_instance;
- GoaIdentityServiceManager *identity_manager;
- GDBusObjectManager *object_manager;
};
typedef struct _GoaKerberosProviderClass GoaKerberosProviderClass;
@@ -52,6 +50,35 @@ struct _GoaKerberosProviderClass
GoaProviderClass parent_class;
};
+static GoaIdentityServiceManager *identity_manager;
+static GMutex identity_manager_mutex;
+static GCond identity_manager_condition;
+
+static GDBusObjectManager *object_manager;
+static GMutex object_manager_mutex;
+static GCond object_manager_condition;
+
+static void ensure_identity_manager (void);
+static void ensure_object_manager (void);
+
+static char *sign_in_identity_sync (GoaKerberosProvider *self,
+ const char *identifier,
+ const char *password,
+ const char *preauth_source,
+ GCancellable *cancellable,
+ GError **error);
+static void sign_in_thread (GSimpleAsyncResult *result,
+ GoaKerberosProvider *self,
+ GCancellable *cancellable);
+static GoaIdentityServiceIdentity *get_identity_from_object_manager (GoaKerberosProvider *self,
+ const char *identifier);
+static gboolean dbus_proxy_reload_properties_sync (GDBusProxy *proxy,
+ GCancellable *cancellable);
+
+static void goa_kerberos_provider_module_init (void);
+static void create_object_manager (void);
+static void create_identity_manager (void);
+
/**
* SECTION:goakerberosprovider
* @title: GoaKerberosProvider
@@ -61,12 +88,20 @@ struct _GoaKerberosProviderClass
*/
G_DEFINE_TYPE_WITH_CODE (GoaKerberosProvider, goa_kerberos_provider, GOA_TYPE_PROVIDER,
+ goa_kerberos_provider_module_init ();
goa_provider_ensure_extension_points_registered ();
g_io_extension_point_implement (GOA_PROVIDER_EXTENSION_POINT_NAME,
g_define_type_id,
GOA_KERBEROS_NAME,
0));
+static void
+goa_kerberos_provider_module_init (void)
+{
+ create_object_manager ();
+ create_identity_manager ();
+}
+
static const gchar *
get_provider_type (GoaProvider *provider)
{
@@ -189,359 +224,6 @@ clear_entry_validation_error (GtkEntry *entry)
}
static void
-on_identity_signed_in (GoaIdentityServiceManager *manager,
- GAsyncResult *result,
- GSimpleAsyncResult *operation_result)
-{
- gboolean signed_in;
- GError *error;
- char *identity_object_path;
-
- error = NULL;
- signed_in = goa_identity_service_manager_call_sign_in_finish (manager,
- &identity_object_path,
- result,
- &error);
-
- if (!signed_in)
- {
- translate_error (&error);
-
- if (g_error_matches (error,
- G_IO_ERROR,
- G_IO_ERROR_CANCELLED))
- {
- g_clear_error (&error);
- g_set_error_literal (&error,
- GOA_ERROR,
- GOA_ERROR_DIALOG_DISMISSED,
- "");
- }
-
- g_simple_async_result_take_error (operation_result, error);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
- return;
- }
-
- g_simple_async_result_set_op_res_gpointer (operation_result,
- g_strdup (identity_object_path),
- (GDestroyNotify)
- g_free);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
-}
-
-static void
-on_identity_manager_ensured (GoaKerberosProvider *self,
- GAsyncResult *result,
- GSimpleAsyncResult *operation_result)
-{
- GoaIdentityServiceManager *manager;
- GError *error;
-
- error = NULL;
- manager = goa_identity_service_manager_proxy_new_for_bus_finish (result, &error);
- if (manager == NULL)
- {
- translate_error (&error);
- g_simple_async_result_take_error (operation_result, error);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
- return;
- }
-
- g_simple_async_result_set_op_res_gpointer (operation_result,
- g_object_ref (manager),
- (GDestroyNotify)
- g_object_unref);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
-}
-
-static void
-ensure_identity_manager (GoaKerberosProvider *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GSimpleAsyncResult *operation_result;
-
- operation_result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- ensure_identity_manager);
- g_simple_async_result_set_check_cancellable (operation_result, cancellable);
-
- g_object_set_data (G_OBJECT (operation_result),
- "cancellable",
- cancellable);
-
- if (self->identity_manager != NULL)
- {
- g_simple_async_result_set_op_res_gpointer (operation_result,
- g_object_ref (self->identity_manager),
- (GDestroyNotify)
- g_object_unref);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
- return;
- }
-
- goa_identity_service_manager_proxy_new_for_bus (G_BUS_TYPE_SESSION,
- G_DBUS_PROXY_FLAGS_NONE,
- "org.gnome.Identity",
- "/org/gnome/Identity/Manager",
- cancellable,
- (GAsyncReadyCallback)
- on_identity_manager_ensured,
- operation_result);
-}
-
-static void
-on_object_manager_ensured (GoaKerberosProvider *self,
- GAsyncResult *result,
- GSimpleAsyncResult *operation_result)
-{
- GDBusObjectManager *manager;
- GError *error;
-
- error = NULL;
- manager = goa_identity_service_object_manager_client_new_for_bus_finish (result, &error);
- if (manager == NULL)
- {
- translate_error (&error);
- g_simple_async_result_take_error (operation_result, error);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
- return;
- }
-
- g_simple_async_result_set_op_res_gpointer (operation_result,
- g_object_ref (manager),
- (GDestroyNotify)
- g_object_unref);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
-}
-
-static void
-ensure_object_manager (GoaKerberosProvider *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GSimpleAsyncResult *operation_result;
-
- operation_result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- ensure_object_manager);
- g_simple_async_result_set_check_cancellable (operation_result, cancellable);
-
- g_object_set_data (G_OBJECT (operation_result),
- "cancellable",
- cancellable);
-
- if (self->object_manager != NULL)
- {
- g_simple_async_result_set_op_res_gpointer (operation_result,
- g_object_ref (self->object_manager),
- (GDestroyNotify)
- g_object_unref);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
- return;
- }
- goa_identity_service_object_manager_client_new_for_bus (G_BUS_TYPE_SESSION,
- G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
- "org.gnome.Identity",
- "/org/gnome/Identity",
- cancellable,
- (GAsyncReadyCallback)
- on_object_manager_ensured,
- operation_result);
-}
-
-static void
-on_secret_keys_exchanged_for_sign_in (GoaKerberosProvider *self,
- GAsyncResult *result,
- GSimpleAsyncResult *operation_result)
-{
- const char *identifier;
- const char *password;
- const char *preauth_source;
- GCancellable *cancellable;
- GError *error;
- GVariantBuilder details;
-
- error = NULL;
-
- if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
- &error))
- {
- g_simple_async_result_take_error (operation_result, error);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
- return;
- }
-
- cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
- password = g_object_get_data (G_OBJECT (operation_result), "password");
- preauth_source = g_object_get_data (G_OBJECT (operation_result), "preauthentication-source");
- identifier = g_simple_async_result_get_source_tag (operation_result);
-
- g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
-
- if (password != NULL)
- {
- GcrSecretExchange *secret_exchange;
- char *secret;
-
- secret_exchange = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
-
- secret = gcr_secret_exchange_send (secret_exchange, password, -1);
- g_variant_builder_add (&details, "{ss}", "initial-password", secret);
- g_free (secret);
- }
-
- if (preauth_source != NULL)
- {
- g_variant_builder_add (&details, "{ss}", "preauthentication-source", preauth_source);
- }
-
- goa_identity_service_manager_call_sign_in (self->identity_manager,
- identifier,
- g_variant_builder_end (&details),
- cancellable,
- (GAsyncReadyCallback)
- on_identity_signed_in,
- operation_result);
-}
-
-static void
-on_secret_keys_exchanged (GoaIdentityServiceManager *manager,
- GAsyncResult *result,
- GSimpleAsyncResult *operation_result)
-{
- GcrSecretExchange *secret_exchange;
- char *return_key;
- GError *error;
-
- secret_exchange = g_simple_async_result_get_source_tag (operation_result);
-
- error = NULL;
- if (!goa_identity_service_manager_call_exchange_secret_keys_finish (manager,
- &return_key,
- result,
- &error))
- {
- g_object_unref (secret_exchange);
-
- g_simple_async_result_take_error (operation_result, error);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
- return;
- }
-
- if (!gcr_secret_exchange_receive (secret_exchange, return_key))
- {
- g_object_unref (secret_exchange);
-
- g_simple_async_result_set_error (operation_result,
- GCR_ERROR,
- GCR_ERROR_UNRECOGNIZED,
- _("Identity service returned invalid key"));
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
- return;
- }
-
- g_simple_async_result_set_op_res_gpointer (operation_result,
- secret_exchange,
- (GDestroyNotify)
- g_object_unref);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
-}
-
-static void
-exchange_secret_keys (GoaKerberosProvider *self,
- const char *password,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
-
- GSimpleAsyncResult *operation_result;
- GcrSecretExchange *secret_exchange;
- char *secret_key;
-
- secret_exchange = gcr_secret_exchange_new (NULL);
-
- operation_result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- secret_exchange);
-
- if (password == NULL)
- {
- g_simple_async_result_complete_in_idle (operation_result);
- g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
- NULL,
- NULL);
- return;
- }
-
- secret_key = gcr_secret_exchange_begin (secret_exchange);
-
- goa_identity_service_manager_call_exchange_secret_keys (self->identity_manager,
- secret_key,
- cancellable,
- (GAsyncReadyCallback)
- on_secret_keys_exchanged,
- operation_result);
- g_free (secret_key);
-}
-
-static void
-on_identity_manager_ensured_for_sign_in (GoaKerberosProvider *self,
- GAsyncResult *result,
- GSimpleAsyncResult *operation_result)
-{
- GoaIdentityServiceManager *manager;
- const char *password;
- GCancellable *cancellable;
- GError *error;
-
- error = NULL;
-
- if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
- &error))
- {
- g_simple_async_result_take_error (operation_result, error);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
- return;
- }
-
- manager = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
-
- if (self->identity_manager == NULL)
- self->identity_manager = g_object_ref (manager);
-
- cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
- password = g_object_get_data (G_OBJECT (operation_result), "password");
-
- exchange_secret_keys (self,
- password,
- cancellable,
- (GAsyncReadyCallback)
- on_secret_keys_exchanged_for_sign_in,
- operation_result);
-}
-
-static void
sign_in_identity (GoaKerberosProvider *self,
const char *identifier,
const char *password,
@@ -567,116 +249,15 @@ sign_in_identity (GoaKerberosProvider *self,
"password",
(gpointer)
password);
-
g_object_set_data_full (G_OBJECT (operation_result),
"preauthentication-source",
g_strdup (preauth_source),
g_free);
-
- ensure_identity_manager (self,
- cancellable,
- (GAsyncReadyCallback)
- on_identity_manager_ensured_for_sign_in,
- operation_result);
-}
-
-static void
-on_object_manager_ensured_for_look_up (GoaKerberosProvider *self,
- GAsyncResult *result,
- GSimpleAsyncResult *operation_result)
-{
- GDBusObjectManager *manager;
- const char *identifier;
- GList *objects, *node;
- GError *error;
- gboolean found;
-
- error = NULL;
- found = FALSE;
-
- if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
- &error))
- {
-
- g_simple_async_result_take_error (operation_result, error);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
- return;
- }
-
- manager = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
-
- if (self->object_manager == NULL)
- self->object_manager = g_object_ref (manager);
-
- identifier = g_simple_async_result_get_source_tag (operation_result);
-
- g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
- NULL,
- NULL);
- objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->object_manager));
-
- for (node = objects; node != NULL; node = node->next)
- {
- GoaIdentityServiceIdentity *candidate_identity;
- const char *candidate_identifier;
- GDBusObject *object;
-
- object = node->data;
-
- candidate_identity = GOA_IDENTITY_SERVICE_IDENTITY (g_dbus_object_get_interface (object, "org.gnome.Identity"));
-
- if (candidate_identity == NULL)
- continue;
-
- candidate_identifier = goa_identity_service_identity_get_identifier (candidate_identity);
-
- if (g_strcmp0 (candidate_identifier, identifier) == 0)
- {
- g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
- candidate_identity,
- (GDestroyNotify)
- g_object_unref);
- found = TRUE;
- break;
- }
-
- g_object_unref (candidate_identity);
- }
-
- if (!found)
- g_simple_async_result_set_error (operation_result, GOA_ERROR, GOA_ERROR_FAILED, "Failed to find an identity");
-
- g_list_free_full (objects, (GDestroyNotify) g_object_unref);
- g_simple_async_result_complete_in_idle (G_SIMPLE_ASYNC_RESULT (operation_result));
- g_object_unref (operation_result);
-}
-
-static void
-look_up_identity (GoaKerberosProvider *self,
- const char *identifier,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GSimpleAsyncResult *operation_result;
-
- operation_result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- (gpointer)
- identifier);
-
- g_simple_async_result_set_check_cancellable (operation_result, cancellable);
-
- g_object_set_data (G_OBJECT (operation_result),
- "cancellable",
- cancellable);
- ensure_object_manager (self,
- cancellable,
- (GAsyncReadyCallback)
- on_object_manager_ensured_for_look_up,
- operation_result);
+ g_simple_async_result_run_in_thread (operation_result,
+ (GSimpleAsyncThreadFunc)
+ sign_in_thread,
+ G_PRIORITY_DEFAULT,
+ cancellable);
}
static void
@@ -703,13 +284,14 @@ get_ticket_sync (GoaKerberosProvider *self,
{
GVariant *credentials;
GError *lookup_error;
+ GError *sign_in_error;
GoaAccount *account;
GoaTicketing *ticketing;
GVariant *details;
const char *identifier;
const char *password;
const char *preauth_source;
- SignInRequest request;
+ char *object_path = NULL;
gboolean ret;
ret = FALSE;
@@ -758,31 +340,24 @@ get_ticket_sync (GoaKerberosProvider *self,
}
}
- memset (&request, 0, sizeof (SignInRequest));
- request.loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE);
- request.error = NULL;
-
- sign_in_identity (self,
- identifier,
- password,
- preauth_source,
- cancellable,
- (GAsyncReadyCallback)
- on_account_signed_in,
- &request);
-
- g_main_loop_run (request.loop);
- g_main_loop_unref (request.loop);
+ sign_in_error = NULL;
+ object_path = sign_in_identity_sync (self,
+ identifier,
+ password,
+ preauth_source,
+ cancellable,
+ &sign_in_error);
- if (request.error != NULL)
+ if (sign_in_error != NULL)
{
- g_propagate_error (error, request.error);
+ g_propagate_error (error, sign_in_error);
goto out;
}
ret = TRUE;
out:
g_clear_object (&ticketing);
+ g_free (object_path);
if (credentials != NULL)
g_variant_unref (credentials);
@@ -1764,106 +1339,39 @@ show_account (GoaProvider *provider,
_("Network _Resources"));
}
-static void
-on_identity_looked_up (GoaKerberosProvider *provider,
- GAsyncResult *result,
- GSimpleAsyncResult *operation_result)
-{
-
- GoaIdentityServiceIdentity *identity;
- GError *error;
-
- error = NULL;
- if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), &error))
- {
- g_simple_async_result_take_error (operation_result, error);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
- return;
- }
-
- identity = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
- if (identity != NULL)
- g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
- g_object_ref (identity),
- (GDestroyNotify)
- g_object_unref);
- else
- g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
- NULL,
- NULL);
-
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
-}
-
-static void
-on_identity_looked_up_to_ensure_credentials (GoaKerberosProvider *self,
- GAsyncResult *result,
- GSimpleAsyncResult *operation_result)
+static gboolean
+dbus_proxy_reload_properties_sync (GDBusProxy *proxy,
+ GCancellable *cancellable)
{
-
- GoaIdentityServiceIdentity *identity;
- GError *error;
- GoaObject *object;
- GoaAccount *account;
- const char *identifier;
- GCancellable *cancellable;
-
- error = NULL;
- if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), &error))
- {
- g_simple_async_result_take_error (operation_result, error);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
- return;
- }
-
- identity = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
-
- if (identity != NULL && goa_identity_service_identity_get_is_signed_in (identity))
+ GVariant *result;
+ char *name;
+ GVariant *value;
+ GVariantIter *iter;
+
+ result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (proxy),
+ g_dbus_proxy_get_name_owner (proxy),
+ g_dbus_proxy_get_object_path (proxy),
+ "org.freedesktop.DBus.Properties",
+ "GetAll",
+ g_variant_new ("(s)", g_dbus_proxy_get_interface_name (proxy)),
+ G_VARIANT_TYPE ("(a{sv})"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cancellable,
+ NULL);
+ if (result == NULL)
+ return FALSE;
+
+ g_variant_get (result, "(a{sv})", &iter);
+ while (g_variant_iter_next (iter, "{sv}", &name, &value))
{
- g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
- g_object_ref (identity),
- (GDestroyNotify)
- g_object_unref);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
- return;
- }
-
- object = GOA_OBJECT (g_async_result_get_source_object (G_ASYNC_RESULT (operation_result)));
- cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
+ g_dbus_proxy_set_cached_property (proxy, name, value);
- if (!get_ticket_sync (self,
- object,
- FALSE /* Don't allow interaction */,
- cancellable,
- &error))
- {
- g_simple_async_result_take_error (operation_result, error);
- g_simple_async_result_complete_in_idle (operation_result);
- g_object_unref (operation_result);
- return;
+ g_free (name);
+ g_variant_unref (value);
}
-
- account = goa_object_peek_account (object);
- identifier = goa_account_get_identity (account);
-
- look_up_identity (self,
- identifier,
- cancellable,
- (GAsyncReadyCallback)
- on_identity_looked_up,
- operation_result);
-}
-
-static void
-on_credentials_ensured (GoaObject *object,
- GAsyncResult *result,
- GMainLoop *loop)
-{
- g_main_loop_quit (loop);
+ g_variant_iter_free (iter);
+ return TRUE;
}
static gboolean
@@ -1873,65 +1381,57 @@ ensure_credentials_sync (GoaProvider *provider,
GCancellable *cancellable,
GError **error)
{
- GoaIdentityServiceIdentity *identity;
+ GoaIdentityServiceIdentity *identity = NULL;
GoaAccount *account;
const char *identifier;
- GSimpleAsyncResult *operation_result;
- GMainLoop *loop;
- GMainContext *context;
gint64 timestamp;
GDateTime *now, *expiration_time;
GTimeSpan time_span;
- GError *lookup_error;
+ gboolean credentials_ensured = FALSE;
account = goa_object_peek_account (object);
identifier = goa_account_get_identity (account);
- context = g_main_context_new ();
- g_main_context_push_thread_default (context);
- loop = g_main_loop_new (context, FALSE);
- operation_result = g_simple_async_result_new (G_OBJECT (object),
- (GAsyncReadyCallback)
- on_credentials_ensured,
- loop,
- ensure_credentials_sync);
- g_simple_async_result_set_check_cancellable (operation_result, cancellable);
-
- g_object_set_data (G_OBJECT (operation_result),
- "cancellable",
- cancellable);
+ ensure_identity_manager ();
- g_object_ref (operation_result);
- look_up_identity (GOA_KERBEROS_PROVIDER (provider),
- identifier,
- cancellable,
- (GAsyncReadyCallback)
- on_identity_looked_up_to_ensure_credentials,
- operation_result);
+ g_mutex_lock (&identity_manager_mutex);
+ identity = get_identity_from_object_manager (GOA_KERBEROS_PROVIDER (provider),
+ identifier);
- g_main_loop_run (loop);
- g_main_loop_unref (loop);
-
- g_main_context_pop_thread_default (context);
- g_main_context_unref (context);
+ if (identity != NULL)
+ {
+ if (!dbus_proxy_reload_properties_sync (G_DBUS_PROXY (identity), cancellable))
+ g_clear_object (&identity);
+ }
- lookup_error = NULL;
- if (g_simple_async_result_propagate_error (operation_result, &lookup_error))
+ if (identity == NULL || !goa_identity_service_identity_get_is_signed_in (identity))
{
- translate_error (&lookup_error);
- g_set_error_literal (error,
- GOA_ERROR,
- GOA_ERROR_NOT_AUTHORIZED,
- lookup_error->message);
- g_error_free (lookup_error);
- g_object_unref (operation_result);
- return FALSE;
+ gboolean ticket_synced;
+
+ g_mutex_unlock (&identity_manager_mutex);
+ ticket_synced = get_ticket_sync (GOA_KERBEROS_PROVIDER (provider),
+ object,
+ FALSE /* Don't allow interaction */,
+ cancellable,
+ error);
+ g_mutex_lock (&identity_manager_mutex);
+
+ if (!ticket_synced)
+ goto out;
+
+ if (identity == NULL)
+ identity = get_identity_from_object_manager (GOA_KERBEROS_PROVIDER (provider),
+ identifier);
}
- identity = g_simple_async_result_get_op_res_gpointer (operation_result);
+ if (identity == NULL)
+ goto out;
+
+ dbus_proxy_reload_properties_sync (G_DBUS_PROXY (identity), cancellable);
now = g_date_time_new_now_local ();
timestamp = goa_identity_service_identity_get_expiration_timestamp (identity);
+
expiration_time = g_date_time_new_from_unix_local (timestamp);
time_span = g_date_time_difference (expiration_time, now);
@@ -1941,12 +1441,239 @@ ensure_credentials_sync (GoaProvider *provider,
time_span = 0;
*out_expires_in = (int) time_span;
+ credentials_ensured = TRUE;
g_date_time_unref (now);
g_date_time_unref (expiration_time);
- g_object_unref (operation_result);
- return TRUE;
+out:
+ g_clear_object (&identity);
+ g_mutex_unlock (&identity_manager_mutex);
+ return credentials_ensured;
+}
+
+static GoaIdentityServiceIdentity *
+get_identity_from_object_manager (GoaKerberosProvider *self,
+ const char *identifier)
+{
+ GoaIdentityServiceIdentity *identity = NULL;
+ GList *objects, *node;
+
+ ensure_object_manager ();
+
+ g_mutex_lock (&object_manager_mutex);
+ objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager));
+
+ for (node = objects; node != NULL; node = node->next)
+ {
+ GoaIdentityServiceIdentity *candidate_identity;
+ const char *candidate_identifier;
+ GDBusObject *object;
+
+ object = node->data;
+
+ candidate_identity = GOA_IDENTITY_SERVICE_IDENTITY (g_dbus_object_get_interface (object, "org.gnome.Identity"));
+
+ if (candidate_identity == NULL)
+ continue;
+
+ candidate_identifier = goa_identity_service_identity_get_identifier (candidate_identity);
+
+ if (g_strcmp0 (candidate_identifier, identifier) == 0)
+ {
+ identity = candidate_identity;
+ break;
+ }
+
+ g_object_unref (candidate_identity);
+ }
+
+ g_list_free_full (objects, (GDestroyNotify) g_object_unref);
+ g_mutex_unlock (&object_manager_mutex);
+
+ return identity;
+}
+
+static char *
+sign_in_identity_sync (GoaKerberosProvider *self,
+ const char *identifier,
+ const char *password,
+ const char *preauth_source,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GcrSecretExchange *secret_exchange;
+ char *secret_key;
+ char *return_key;
+ char *concealed_secret;
+ char *identity_object_path = NULL;
+ gboolean keys_exchanged;
+ GVariantBuilder details;
+
+ secret_exchange = gcr_secret_exchange_new (NULL);
+
+ secret_key = gcr_secret_exchange_begin (secret_exchange);
+ ensure_identity_manager ();
+
+ g_mutex_lock (&identity_manager_mutex);
+ keys_exchanged = goa_identity_service_manager_call_exchange_secret_keys_sync (identity_manager,
+ secret_key,
+ &return_key,
+ cancellable,
+ error);
+ g_mutex_unlock (&identity_manager_mutex);
+ g_free (secret_key);
+
+ if (!keys_exchanged)
+ goto out;
+
+ if (!gcr_secret_exchange_receive (secret_exchange, return_key))
+ {
+ g_set_error (error,
+ GCR_ERROR,
+ GCR_ERROR_UNRECOGNIZED,
+ _("Identity service returned invalid key"));
+ goto out;
+ }
+
+ g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
+
+ concealed_secret = gcr_secret_exchange_send (secret_exchange, password, -1);
+ g_variant_builder_add (&details, "{ss}", "initial-password", concealed_secret);
+ g_free (concealed_secret);
+
+ if (preauth_source != NULL)
+ {
+ g_variant_builder_add (&details, "{ss}", "preauthentication-source", preauth_source);
+ }
+
+ g_mutex_lock (&identity_manager_mutex);
+ goa_identity_service_manager_call_sign_in_sync (identity_manager,
+ identifier,
+ g_variant_builder_end (&details),
+ &identity_object_path,
+ cancellable,
+ error);
+ g_mutex_unlock (&identity_manager_mutex);
+
+out:
+ g_object_unref (secret_exchange);
+ return identity_object_path;
+}
+
+static void
+sign_in_thread (GSimpleAsyncResult *result,
+ GoaKerberosProvider *self,
+ GCancellable *cancellable)
+{
+ const char *identifier;
+ const char *password;
+ const char *preauth_source;
+ char *object_path;
+ GError *error;
+
+ identifier = g_simple_async_result_get_source_tag (result);
+ password = g_object_get_data (G_OBJECT (result), "password");
+ preauth_source = g_object_get_data (G_OBJECT (result), "preauth-source");
+
+ error = NULL;
+ object_path = sign_in_identity_sync (self, identifier, password, preauth_source, cancellable, &error);
+
+ if (object_path == NULL)
+ g_simple_async_result_take_error (result, error);
+ else
+ g_simple_async_result_set_op_res_gpointer (result, object_path, NULL);
+}
+
+
+static void
+on_object_manager_created (gpointer object,
+ GAsyncResult *result,
+ GSimpleAsyncResult *operation_result)
+{
+ GDBusObjectManager *manager;
+ GError *error;
+
+ error = NULL;
+ manager = goa_identity_service_object_manager_client_new_for_bus_finish (result, &error);
+ if (manager == NULL)
+ {
+ g_warning ("GoaKerberosProvider: Could not connect to identity service: %s", error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ g_mutex_lock (&object_manager_mutex);
+ object_manager = manager;
+ g_cond_signal (&object_manager_condition);
+ g_mutex_unlock (&object_manager_mutex);
+}
+
+static void
+create_object_manager (void)
+{
+ goa_identity_service_object_manager_client_new_for_bus (G_BUS_TYPE_SESSION,
+ G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+ "org.gnome.Identity",
+ "/org/gnome/Identity",
+ NULL,
+ (GAsyncReadyCallback)
+ on_object_manager_created,
+ NULL);
+}
+
+static void
+ensure_object_manager (void)
+{
+ g_mutex_lock (&object_manager_mutex);
+ while (object_manager == NULL)
+ g_cond_wait (&object_manager_condition, &object_manager_mutex);
+ g_mutex_unlock (&object_manager_mutex);
+}
+
+static void
+on_identity_manager_created (gpointer identity,
+ GAsyncResult *result,
+ GSimpleAsyncResult *operation_result)
+{
+ GoaIdentityServiceManager *manager;
+ GError *error;
+
+ error = NULL;
+ manager = goa_identity_service_manager_proxy_new_for_bus_finish (result, &error);
+ if (manager == NULL)
+ {
+ g_warning ("GoaKerberosProvider: Could not connect to identity service manager: %s", error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ g_mutex_lock (&identity_manager_mutex);
+ identity_manager = manager;
+ g_cond_signal (&identity_manager_condition);
+ g_mutex_unlock (&identity_manager_mutex);
+}
+
+static void
+create_identity_manager (void)
+{
+ goa_identity_service_manager_proxy_new_for_bus (G_BUS_TYPE_SESSION,
+ G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+ "org.gnome.Identity",
+ "/org/gnome/Identity/Manager",
+ NULL,
+ (GAsyncReadyCallback)
+ on_identity_manager_created,
+ NULL);
+}
+
+static void
+ensure_identity_manager (void)
+{
+ g_mutex_lock (&identity_manager_mutex);
+ while (identity_manager == NULL)
+ g_cond_wait (&identity_manager_condition, &identity_manager_mutex);
+ g_mutex_unlock (&identity_manager_mutex);
}
static void
--
2.5.0
From 2dbd414c16d8654f0cfccb54fede644b8f3216db Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 28 Oct 2014 17:10:49 -0400
Subject: [PATCH 2/2] identity: separate identity service off into its own
process
This commit segregates the kerberos specific functionality off
into its own helper process.
This has a couple of benefits:
1) It is actually a better fit for how the code was initially designed,
which was first staged in gnome-settings-daemon with g-o-a talking to
it. Right now we have gnome-online-accounts talking to itself,
in-process, through d-bus, which is suboptimal.
2) It keeps any leaks or crashes in the kerberos code from bringing down
the whole online accounts daemon.
---
data/Makefile.am | 8 ++++-
data/org.gnome.Identity.service.in | 3 ++
src/daemon/Makefile.am | 8 -----
src/daemon/goadaemon.c | 43 +++++++++++++-------------
src/goaidentity/Makefile.am | 10 +++---
src/goaidentity/goaidentityservice.c | 2 +-
src/goaidentity/main.c | 59 ++++++++++++++++++++++++++++++++++++
7 files changed, 97 insertions(+), 36 deletions(-)
create mode 100644 data/org.gnome.Identity.service.in
create mode 100644 src/goaidentity/main.c
diff --git a/data/Makefile.am b/data/Makefile.am
index cb30eb8d1391..fb68063c8234 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -14,9 +14,14 @@ gsettings_SCHEMAS = $(gsettings_in_files:.xml.in=.xml)
servicedir = $(datadir)/dbus-1/services
service_in_files = org.gnome.OnlineAccounts.service.in
+
+if BUILD_KERBEROS
+service_in_files += org.gnome.Identity.service.in
+endif
+
service_DATA = $(service_in_files:.service.in=.service)
-$(service_DATA): $(service_in_files) Makefile
+%.service: %.service.in Makefile
@sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@
EXTRA_DIST = \
@@ -29,6 +34,7 @@ EXTRA_DIST = \
DISTCLEANFILES = \
$(gsettings_SCHEMAS) \
org.gnome.OnlineAccounts.service \
+ org.gnome.Identity.service \
$(NULL)
clean-local :
diff --git a/data/org.gnome.Identity.service.in b/data/org.gnome.Identity.service.in
new file mode 100644
index 000000000000..bd3b03225ab6
--- /dev/null
+++ b/data/org.gnome.Identity.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.gnome.Identity
+Exec=@libexecdir@/goa-identity-service
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
index 9fdb11538a4e..8f5352fad39e 100644
--- a/src/daemon/Makefile.am
+++ b/src/daemon/Makefile.am
@@ -48,14 +48,6 @@ goa_daemon_LDADD = \
$(TP_LIBS) \
$(NULL)
-if BUILD_KERBEROS
-goa_daemon_LDADD += \
- $(top_builddir)/src/goaidentity/libgoaidentity.la \
- $(KRB5_LIBS) \
- $(GCR_LIBS) \
- $(NULL)
-endif
-
clean-local :
rm -f *~
diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c
index 8074f201ef46..1aa0f18aee45 100644
--- a/src/daemon/goadaemon.c
+++ b/src/daemon/goadaemon.c
@@ -25,9 +25,6 @@
#include "goadaemon.h"
#include "goabackend/goabackend.h"
#include "goabackend/goautils.h"
-#ifdef GOA_KERBEROS_ENABLED
-#include "goaidentity/goaidentityservice.h"
-#endif
struct _GoaDaemon
{
@@ -43,10 +40,6 @@ struct _GoaDaemon
GoaManager *manager;
-#ifdef GOA_KERBEROS_ENABLED
- GoaIdentityService *identity_service;
-#endif
-
guint config_timeout_id;
};
@@ -112,10 +105,6 @@ goa_daemon_finalize (GObject *object)
g_object_unref (daemon->object_manager);
g_object_unref (daemon->connection);
-#ifdef GOA_KERBEROS_ENABLED
- g_clear_object (&daemon->identity_service);
-#endif
-
G_OBJECT_CLASS (goa_daemon_parent_class)->finalize (object);
}
@@ -173,15 +162,32 @@ on_file_monitor_changed (GFileMonitor *monitor,
}
}
+#ifdef GOA_KERBEROS_ENABLED
+static void
+activate_identity_service (GoaDaemon *daemon)
+{
+ GoaProvider *provider;
+
+ /* We activate the identity service implicitly by using the kerberos
+ * backend. This way if the kerberos backend isn't enabled, we don't
+ * end up starting the identity service needlessly
+ */
+ provider = goa_provider_get_for_provider_type (GOA_KERBEROS_NAME);
+
+ if (provider != NULL)
+ {
+ g_debug ("activated kerberos provider");
+ g_object_unref (provider);
+ }
+}
+#endif
+
static void
goa_daemon_init (GoaDaemon *daemon)
{
static volatile GQuark goa_error_domain = 0;
GoaObjectSkeleton *object;
gchar *path;
-#ifdef GOA_KERBEROS_ENABLED
- GError *error = NULL;
-#endif
/* this will force associating errors in the GOA_ERROR error domain
* with org.freedesktop.Goa.Error.* errors via g_dbus_error_register_error_domain().
@@ -228,14 +234,7 @@ goa_daemon_init (GoaDaemon *daemon)
g_dbus_object_manager_server_set_connection (daemon->object_manager, daemon->connection);
#ifdef GOA_KERBEROS_ENABLED
- daemon->identity_service = goa_identity_service_new ();
- if (!goa_identity_service_activate (daemon->identity_service,
- &error))
- {
- g_warning ("Error activating identity service: %s", error->message);
- g_error_free (error);
- g_clear_object (&daemon->identity_service);
- }
+ activate_identity_service (daemon);
#endif
}
diff --git a/src/goaidentity/Makefile.am b/src/goaidentity/Makefile.am
index 8e11f6d596da..537287a2cca3 100644
--- a/src/goaidentity/Makefile.am
+++ b/src/goaidentity/Makefile.am
@@ -47,6 +47,7 @@ identity_sources = \
goakerberosidentity.c \
goakerberosidentityinquiry.c \
goakerberosidentitymanager.c \
+ main.c \
$(NULL)
identity_dbus_built_sources = \
@@ -95,23 +96,24 @@ BUILT_SOURCES += $(realmd_dbus_built_sources)
EXTRA_DIST += org.freedesktop.realmd.xml
if BUILD_KERBEROS
-noinst_LTLIBRARIES = libgoaidentity.la
+libexec_PROGRAMS = goa-identity-service
-libgoaidentity_la_SOURCES = \
+goa_identity_service_SOURCES = \
goaidentityenumtypes.h goaidentityenumtypes.c \
$(identity_dbus_built_sources) \
$(realmd_dbus_built_sources) \
$(identity_sources) \
$(NULL)
-libgoaidentity_la_CFLAGS = \
+goa_identity_service_CFLAGS = \
$(GLIB_CFLAGS) \
$(GTK_CFLAGS) \
$(KRB5_CFLAGS) \
$(GCR_CFLAGS) \
$(NULL)
-libgoaidentity_la_LIBADD = \
+goa_identity_service_LDADD = \
+ $(top_builddir)/src/goa/libgoa-1.0.la \
$(GLIB_LIBS) \
$(GTK_LIBS) \
$(KRB5_LIBS) \
diff --git a/src/goaidentity/goaidentityservice.c b/src/goaidentity/goaidentityservice.c
index 38bbde6a7d93..6b6225adbc61 100644
--- a/src/goaidentity/goaidentityservice.c
+++ b/src/goaidentity/goaidentityservice.c
@@ -1757,7 +1757,7 @@ on_name_lost (GDBusConnection *connection,
GoaIdentityService *self)
{
if (g_strcmp0 (name, "org.gnome.Identity") == 0)
- g_debug ("GoaIdentityService: Lost name org.gnome.Identity");
+ raise (SIGTERM);
}
gboolean
diff --git a/src/goaidentity/main.c b/src/goaidentity/main.c
new file mode 100644
index 000000000000..2de35acfc561
--- /dev/null
+++ b/src/goaidentity/main.c
@@ -0,0 +1,59 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <glib-unix.h>
+
+#include <gio/gio.h>
+
+#include "goaidentityservice.h"
+
+int
+main (int argc,
+ char **argv)
+{
+ GMainLoop *loop;
+ GoaIdentityService *service;
+ GError *error;
+ int ret = 1;
+
+ loop = g_main_loop_new (NULL, FALSE);
+ service = goa_identity_service_new ();
+
+ error = NULL;
+ goa_identity_service_activate (service, &error);
+
+ if (error != NULL) {
+ g_warning ("couldn't activate identity service: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ g_main_loop_run (loop);
+
+ goa_identity_service_deactivate (service);
+
+ ret = 0;
+out:
+ g_object_unref (service);
+ g_main_loop_unref (loop);
+
+ return ret;
+}
--
2.5.0